Bug 564076: Small parser cleanup changes. (r=mrbkap)
[mozilla-central.git] / xpcom / ds / nsCRT.cpp
blobca1f49997b5d588229f539efb3028856760be0f2
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
39 /**
40 * MODULE NOTES:
41 * @update gess7/30/98
43 * Much as I hate to do it, we were using string compares wrong.
44 * Often, programmers call functions like strcmp(s1,s2), and pass
45 * one or more null strings. Rather than blow up on these, I've
46 * added quick checks to ensure that cases like this don't cause
47 * us to fail.
49 * In general, if you pass a null into any of these string compare
50 * routines, we simply return 0.
54 #include "nsCRT.h"
55 #include "nsIServiceManager.h"
56 #include "nsCharTraits.h"
57 #include "prbit.h"
58 #include "nsUTF8Utils.h"
60 #define ADD_TO_HASHVAL(hashval, c) \
61 hashval = PR_ROTATE_LEFT32(hashval, 4) ^ (c);
63 //----------------------------------------------------------------------
66 ////////////////////////////////////////////////////////////////////////////////
67 // My lovely strtok routine
69 #define IS_DELIM(m, c) ((m)[(c) >> 3] & (1 << ((c) & 7)))
70 #define SET_DELIM(m, c) ((m)[(c) >> 3] |= (1 << ((c) & 7)))
71 #define DELIM_TABLE_SIZE 32
73 char* nsCRT::strtok(char* string, const char* delims, char* *newStr)
75 NS_ASSERTION(string, "Unlike regular strtok, the first argument cannot be null.");
77 char delimTable[DELIM_TABLE_SIZE];
78 PRUint32 i;
79 char* result;
80 char* str = string;
82 for (i = 0; i < DELIM_TABLE_SIZE; i++)
83 delimTable[i] = '\0';
85 for (i = 0; delims[i]; i++) {
86 SET_DELIM(delimTable, static_cast<PRUint8>(delims[i]));
88 NS_ASSERTION(delims[i] == '\0', "too many delimiters");
90 // skip to beginning
91 while (*str && IS_DELIM(delimTable, static_cast<PRUint8>(*str))) {
92 str++;
94 result = str;
96 // fix up the end of the token
97 while (*str) {
98 if (IS_DELIM(delimTable, static_cast<PRUint8>(*str))) {
99 *str++ = '\0';
100 break;
102 str++;
104 *newStr = str;
106 return str == result ? NULL : result;
109 ////////////////////////////////////////////////////////////////////////////////
112 * Compare unichar string ptrs, stopping at the 1st null
113 * NOTE: If both are null, we return 0.
114 * NOTE: We terminate the search upon encountering a NULL
116 * @update gess 11/10/99
117 * @param s1 and s2 both point to unichar strings
118 * @return 0 if they match, -1 if s1<s2; 1 if s1>s2
120 PRInt32 nsCRT::strcmp(const PRUnichar* s1, const PRUnichar* s2) {
121 if(s1 && s2) {
122 for (;;) {
123 PRUnichar c1 = *s1++;
124 PRUnichar c2 = *s2++;
125 if (c1 != c2) {
126 if (c1 < c2) return -1;
127 return 1;
129 if ((0==c1) || (0==c2)) break;
132 else {
133 if (s1) // s2 must have been null
134 return -1;
135 if (s2) // s1 must have been null
136 return 1;
138 return 0;
142 * Compare unichar string ptrs, stopping at the 1st null or nth char.
143 * NOTE: If either is null, we return 0.
144 * NOTE: We DO NOT terminate the search upon encountering NULL's before N
146 * @update gess 11/10/99
147 * @param s1 and s2 both point to unichar strings
148 * @return 0 if they match, -1 if s1<s2; 1 if s1>s2
150 PRInt32 nsCRT::strncmp(const PRUnichar* s1, const PRUnichar* s2, PRUint32 n) {
151 if(s1 && s2) {
152 if(n != 0) {
153 do {
154 PRUnichar c1 = *s1++;
155 PRUnichar c2 = *s2++;
156 if (c1 != c2) {
157 if (c1 < c2) return -1;
158 return 1;
160 } while (--n != 0);
163 return 0;
166 PRUnichar* nsCRT::strdup(const PRUnichar* str)
168 PRUint32 len = nsCRT::strlen(str);
169 return strndup(str, len);
172 PRUnichar* nsCRT::strndup(const PRUnichar* str, PRUint32 len)
174 nsCppSharedAllocator<PRUnichar> shared_allocator;
175 PRUnichar* rslt = shared_allocator.allocate(len + 1); // add one for the null
176 // PRUnichar* rslt = new PRUnichar[len + 1];
178 if (rslt == NULL) return NULL;
179 memcpy(rslt, str, len * sizeof(PRUnichar));
180 rslt[len] = 0;
181 return rslt;
185 * |nsCRT::HashCode| is identical to |PL_HashString|, which tests
186 * (http://bugzilla.mozilla.org/showattachment.cgi?attach_id=26596)
187 * show to be the best hash among several other choices.
189 * We re-implement it here rather than calling it for two reasons:
190 * (1) in this interface, we also calculate the length of the
191 * string being hashed; and (2) the narrow and wide and `buffer' versions here
192 * will hash equivalent strings to the same value, e.g., "Hello" and L"Hello".
194 PRUint32 nsCRT::HashCode(const char* str, PRUint32* resultingStrLen)
196 PRUint32 h = 0;
197 const char* s = str;
199 if (!str) return h;
201 unsigned char c;
202 while ( (c = *s++) )
203 ADD_TO_HASHVAL(h, c);
205 if ( resultingStrLen )
206 *resultingStrLen = (s-str)-1;
207 return h;
210 PRUint32 nsCRT::HashCode(const char* start, PRUint32 length)
212 PRUint32 h = 0;
213 const char* s = start;
214 const char* end = start + length;
216 unsigned char c;
217 while ( s < end ) {
218 c = *s++;
219 ADD_TO_HASHVAL(h, c);
222 return h;
225 PRUint32 nsCRT::HashCode(const PRUnichar* str, PRUint32* resultingStrLen)
227 PRUint32 h = 0;
228 const PRUnichar* s = str;
230 if (!str) return h;
232 PRUnichar c;
233 while ( (c = *s++) )
234 ADD_TO_HASHVAL(h, c);
236 if ( resultingStrLen )
237 *resultingStrLen = (s-str)-1;
238 return h;
241 PRUint32 nsCRT::HashCode(const PRUnichar* start, PRUint32 length)
243 PRUint32 h = 0;
244 const PRUnichar* s = start;
245 const PRUnichar* end = start + length;
247 PRUnichar c;
248 while ( s < end ) {
249 c = *s++;
250 ADD_TO_HASHVAL(h, c);
253 return h;
256 PRUint32 nsCRT::HashCodeAsUTF16(const char* start, PRUint32 length,
257 PRBool* err)
259 PRUint32 h = 0;
260 const char* s = start;
261 const char* end = start + length;
263 *err = PR_FALSE;
265 while ( s < end )
267 PRUint32 ucs4 = UTF8CharEnumerator::NextChar(&s, end, err);
268 if (*err) {
269 return 0;
272 if (ucs4 < PLANE1_BASE) {
273 ADD_TO_HASHVAL(h, ucs4);
275 else {
276 ADD_TO_HASHVAL(h, H_SURROGATE(ucs4));
277 ADD_TO_HASHVAL(h, L_SURROGATE(ucs4));
281 return h;
284 // This should use NSPR but NSPR isn't exporting its PR_strtoll function
285 // Until then...
286 PRInt64 nsCRT::atoll(const char *str)
288 if (!str)
289 return LL_Zero();
291 PRInt64 ll = LL_Zero(), digitll = LL_Zero();
293 while (*str && *str >= '0' && *str <= '9') {
294 LL_MUL(ll, ll, 10);
295 LL_UI2L(digitll, (*str - '0'));
296 LL_ADD(ll, ll, digitll);
297 str++;
300 return ll;