File: | libsynthesis/src/sysync/stringutils.cpp |
Warning: | line 131, column 21 Value stored to 'kp' is never read |
1 | /* |
2 | * File: stringutils.cpp |
3 | * |
4 | * Authors: Lukas Zeller (luz@plan44.ch) |
5 | * Beat Forster (bfo@synthesis.ch) |
6 | * |
7 | * C++ string utils |
8 | * |
9 | * Copyright (c) 2001-2011 by Synthesis AG + plan44.ch |
10 | * |
11 | * 2002-05-01 : luz : extracted from sysync_utils |
12 | */ |
13 | |
14 | #include "prefix_file.h" |
15 | #include "stringutils.h" |
16 | |
17 | // Consistent support for Linux, MacOSX CW & XCode |
18 | #if defined __GNUC__4 || defined _MSC_VER |
19 | #include <ctype.h> |
20 | #else |
21 | #include <ctype> |
22 | #endif |
23 | |
24 | #include <cstdio> |
25 | #include <cstring> |
26 | #include <stdarg.h> |
27 | |
28 | using namespace std; |
29 | |
30 | namespace sysync { |
31 | |
32 | |
33 | |
34 | #ifdef NO_VSNPRINTF |
35 | // dummy (unsafe!!) map to vsprintf |
36 | int vsnprintf(char *s, int sz, const char *formatStr, va_list arg) |
37 | { |
38 | return vsprintf(s,formatStr,arg); |
39 | } // vsnprintf |
40 | #endif |
41 | |
42 | #ifdef NO_SNPRINTF |
43 | // own implementation (possibly unsafe, if vsnprintf is dummy) |
44 | int snprintf(char *s, int sz, const char *formatStr, ...) |
45 | { |
46 | va_list args; |
47 | |
48 | va_start(args, formatStr)__builtin_va_start(args, formatStr); |
49 | // now make the string |
50 | int n=vsnprintf(s,sz,formatStr,args); |
51 | va_end(args)__builtin_va_end(args); |
52 | return n; |
53 | } // snprintf |
54 | #endif |
55 | |
56 | |
57 | /// @brief Return passed pointer as C string, if pointer is NULL, empty string is returned |
58 | /// @param[in] aStr a C string or NULL |
59 | /// @return if aStr is NULL, returns empty string, aStr otherwise |
60 | const char *alwaysCStr(const char *aStr) |
61 | { |
62 | return aStr ? aStr : ""; |
63 | } // alwaysCStr |
64 | |
65 | |
66 | // Assign char ptr to string object |
67 | // NOTE: NULL is allowed and means empty string |
68 | void AssignString(string &aString, const char *aCharP) |
69 | { |
70 | if (aCharP) |
71 | aString=aCharP; |
72 | else |
73 | aString.erase(); |
74 | } // AssignString |
75 | |
76 | |
77 | // Assign char ptr to char array of size aLen (note that we always leave room for terminator) |
78 | // NOTE: NULL is allowed and means empty string |
79 | void AssignCString(char *aCStr, const char *aCharP, size_t aLen) |
80 | { |
81 | if (aCharP) { |
82 | strncpy(aCStr,aCharP,aLen-1); |
83 | aCStr[aLen-1]=0; // make sure it is terminated |
84 | } |
85 | else |
86 | aCStr[0]=0; |
87 | } // AssignCString |
88 | |
89 | |
90 | // trim leading spaces/ctrls and everything including and after the next space/ctrl |
91 | void AssignTrimmedCString(char *aCStr, const char *aCharP, size_t aLen) |
92 | { |
93 | if (aCharP) { |
94 | // not empty, find first non-control/space |
95 | while (*aCharP && (uInt8)(*aCharP)<=0x20) aCharP++; |
96 | // now find end |
97 | const char *e = aCharP; |
98 | while (*e && (uInt8)(*e)>0x20) e++; |
99 | // copy valid part of URL |
100 | size_t n=e-aCharP; |
101 | if (n>aLen-1) n=aLen-1; // limit to max buffer size |
102 | strncpy(aCStr,aCharP,n); |
103 | aCStr[n]=0; // make sure it is terminated |
104 | } |
105 | else |
106 | aCStr[0]=0; |
107 | } // AssignTrimmedCString |
108 | |
109 | |
110 | |
111 | // save mangled into C-string buffer |
112 | uInt16 assignMangledToCString(char *aCString, const char *aCode, uInt16 aMaxBytes, bool aIsName, uInt8 aMangleInc, const char *aSecondKey) |
113 | { |
114 | uInt8 mangler=aMangleInc; |
115 | uInt16 b,bytes=0; |
116 | uInt8 c; |
117 | const char *kp = aSecondKey && *aSecondKey ? aSecondKey : NULL__null; // need at least once char of key |
118 | while(aCode && *aCode && bytes<aMaxBytes-1) { |
119 | c = *(aCode++); |
120 | if ((aIsName && (c>=0x20)) || (!aIsName && isalnum(c))) { |
121 | // save only visible chars and spaces from name and alphanums from code |
122 | *(aCString++)= |
123 | c ^ mangler ^ (kp ? *(kp++) : 0); // add mangled |
124 | if (kp && *kp==0) kp=aSecondKey; // wrap around |
125 | mangler+=aMangleInc; |
126 | bytes++; |
127 | } |
128 | } |
129 | // add terminator in all cases |
130 | *aCString++=mangler ^ (kp ? *(kp++) : 0); |
131 | if (kp && *kp==0) kp=aSecondKey; // wrap around |
Value stored to 'kp' is never read | |
132 | bytes++; |
133 | // now add some garbage to disguise length of actual data |
134 | b=bytes; |
135 | while (b<aMaxBytes) { |
136 | *aCString++ = b++ ^ mangler; |
137 | mangler+=aMangleInc; |
138 | } |
139 | // return actual number of bytes (without disguising garbage) |
140 | return bytes; |
141 | } // assignMangledToCString |
142 | |
143 | |
144 | // get unmangled into string |
145 | void getUnmangled(string &aString, const char *aMangled, uInt16 aMaxChars, uInt8 aMangleInc, const char *aSecondKey) |
146 | { |
147 | uInt8 mangler=aMangleInc; |
148 | uInt8 c; |
149 | const char *kp = aSecondKey && *aSecondKey ? aSecondKey : NULL__null; // need at least once char of key |
150 | aString.erase(); |
151 | while (aMaxChars-- > 0 && aMangled && (c=((uInt8)(*aMangled) ^ mangler ^ (kp ? *(kp++) : 0)))) { |
152 | aString += (char)c; |
153 | if (kp && *kp==0) kp=aSecondKey; // wrap around |
154 | aMangled++; |
155 | mangler+=aMangleInc; |
156 | } |
157 | } // getUnmangled |
158 | |
159 | |
160 | // get unmangled into buffer |
161 | void getUnmangledAsBuf(appCharP aBuffer, uInt16 aBufSize, cAppCharP aMangled, uInt8 aMangleInc, cAppCharP aSecondKey) |
162 | { |
163 | uInt8 mangler=aMangleInc; |
164 | uInt8 c; |
165 | if (!aBuffer || aBufSize<1) return; // no buffer |
166 | const char *kp = aSecondKey && *aSecondKey ? aSecondKey : NULL__null; // need at least once char of key |
167 | aBuffer[--aBufSize]=0; // ultimate security terminator |
168 | while (aBufSize-- > 0 && aMangled && (c=((uInt8)(*aMangled) ^ mangler ^ (kp ? *(kp++) : 0)))) { |
169 | *(aBuffer++) = (char)c; |
170 | if (kp && *kp==0) kp=aSecondKey; // wrap around |
171 | aMangled++; |
172 | mangler+=aMangleInc; |
173 | } |
174 | *(aBuffer) = 0; // terminate |
175 | } // getUnmangled |
176 | |
177 | |
178 | |
179 | // case insensitive and whitespace trimming strcmp, NULL allowed as empty string input |
180 | sInt16 strutrimcmp(const char *s1, const char *s2) |
181 | { |
182 | // skip whitespace on both strings first |
183 | while (s1 && *s1 && isspace(*s1)) ++s1; |
184 | while (s2 && *s2 && isspace(*s2)) ++s2; |
185 | // count number of non-whitespaces |
186 | sInt32 n1=0; while (s1 && s1[n1] && !isspace(s1[n1])) ++n1; |
187 | sInt32 n2=0; while (s2 && s2[n2] && !isspace(s2[n2])) ++n2; |
188 | // now compare |
189 | return strucmp(s1,s2,n1,n2); |
190 | } // strutrimcmp |
191 | |
192 | |
193 | // case insensitive strcmp which allow wildcards ? and * in s2, NULL allowed as empty string input |
194 | sInt16 strwildcmp(const char *s1, const char *s2, size_t len1, size_t len2) |
195 | { |
196 | // allow NULL as empty strings |
197 | if (!s1) s1 = ""; |
198 | if (!s2) s2 = ""; |
199 | // s1>s2 : 1, s1==s2 : 0, s1<s2 : -1 |
200 | size_t i,j; // size_t instead of sInt32: BCPPB |
201 | // calc number of chars we must compare |
202 | size_t len = len1==0 ? len2 : (len2==0 ? len1 : (len1>len2 ? len2 : len1)); |
203 | for (i=0; (!len || i<len) && *s1 && *s2; i++) { |
204 | // while both strings have chars and not len reached |
205 | if (*s2=='*') { |
206 | // zero to arbitrary number of chars |
207 | s2++; |
208 | j=0; |
209 | if (*s2==0) return 0; // if asterisk is last in pattern, match is complete |
210 | while (*s1) { |
211 | // more pattern follows, recurse to compare the rest |
212 | if (strwildcmp(s1,s2,len1 ? len1-i-j : 0,len2 ? len2-i-1 : 0)==0) { |
213 | // rest matches now -> full match |
214 | return 0; |
215 | } |
216 | // next attempt |
217 | s1++; |
218 | j++; |
219 | } |
220 | // no match if we get this far |
221 | return 1; |
222 | } |
223 | else if (*s2!='?' && toupper(*s1)!=toupper(*s2)) |
224 | return toupper(*s1)>toupper(*s2) ? 1 : -1; // different and no wildcard in pattern at this place |
225 | // next |
226 | s1++; |
227 | s2++; |
228 | } |
229 | // equal up to end of shorter string or reached len |
230 | // - if both reached end or len |
231 | if (len1 ? i==len1 : *s1==0) { |
232 | // s1 has reached end, check special case that pattern ends with *, this would be ok |
233 | if ((len==0 || i<len2) && *s2=='*') { s2++; i++; } // simply consume asterisk, if s2 is now at end as well, that's ok |
234 | if (len2 ? i==len2 : *s2==0) return 0; // match only if s2 is now at end as well |
235 | } |
236 | // - not equal, longer string is larger |
237 | // (if not reached end of s1 or stopped before len1, s1 is longer) |
238 | return (len1 ? i<len1 : *s1) ? 1 : -1; |
239 | } // strwildcmp |
240 | |
241 | |
242 | #ifdef SYNTHESIS_UNIT_TEST |
243 | bool test_strwildcmp(void) |
244 | { |
245 | bool ok=true; |
246 | int i; |
247 | UNIT_TEST_CALL(i=strwildcmp("http://test.com/test","http*://test.com/test"),("i=%d",i),i==0,ok); |
248 | UNIT_TEST_CALL(i=strwildcmp("https://test.com/test","http*://test.com/test"),("i=%d",i),i==0,ok); |
249 | UNIT_TEST_CALL(i=strwildcmp("htt://test.com/test","http*://test.com/test"),("i=%d",i),i!=0,ok); |
250 | UNIT_TEST_CALL(i=strwildcmp("http://test.com/test/10000","http*://test.com/test*"),("i=%d",i),i==0,ok); |
251 | UNIT_TEST_CALL(i=strwildcmp("http://test.com/test","http*://test.com/test*"),("i=%d",i),i==0,ok); |
252 | UNIT_TEST_CALL(i=strwildcmp("realGARBAGE","real"),("i=%d",i),i!=0,ok); |
253 | UNIT_TEST_CALL(i=strwildcmp("realGARBAGE","real",4),("i=%d",i),i==0,ok); |
254 | UNIT_TEST_CALL(i=strwildcmp("realGARBAGE","realTRASH",4,4),("i=%d",i),i==0,ok); |
255 | UNIT_TEST_CALL(i=strwildcmp("one_two_two2_four_five","one*two2*five"),("i=%d",i),i==0,ok); |
256 | UNIT_TEST_CALL(i=strwildcmp("one_two_two2_four_five","one*two2*five",12),("i=%d",i),i!=0,ok); |
257 | UNIT_TEST_CALL(i=strwildcmp("one_two_two2_four_five","one*two2*five",12,8),("i=%d",i),i==0,ok); |
258 | UNIT_TEST_CALL(i=strwildcmp("one_two_two2_four_five","one*two2*five",12,9),("i=%d",i),i==0,ok); |
259 | UNIT_TEST_CALL(i=strwildcmp("one_two_two2_four_five","one*two2*five",12,10),("i=%d",i),i!=0,ok); |
260 | UNIT_TEST_CALL(i=strwildcmp("P800","P?00"),("i=%d",i),i==0,ok); |
261 | UNIT_TEST_CALL(i=strwildcmp("P810","P?00"),("i=%d",i),i!=0,ok); |
262 | return ok; |
263 | } |
264 | #endif |
265 | |
266 | |
267 | // case insensitive strpos, returns -1 if not found |
268 | sInt32 strupos(const char *s, const char *pat, size_t slen, size_t patlen) |
269 | { |
270 | size_t i,k; |
271 | for (i=0; (!slen || i<slen) && s && *s; i++) { |
272 | for (k=0; (!patlen || k<patlen) && pat && *pat; k++) { |
273 | if (*(s+k)==0 || (slen && i+k>=slen)) |
274 | return -1; // pattern too long to possibly match at all |
275 | if (toupper(*(s+k))!=toupper(*pat)) |
276 | break; // no match at this position |
277 | pat++; |
278 | } |
279 | if (*pat==0 || (patlen && k>=patlen)) |
280 | return i; // pattern end reached and all matches so far -> found string here |
281 | // try next position |
282 | s++; |
283 | } |
284 | return -1; // not found in any position |
285 | } // strupos |
286 | |
287 | |
288 | // case insensitive strcmp, NULL allowed as empty string input |
289 | sInt16 strucmp(const char *s1, const char *s2, size_t len1, size_t len2) |
290 | { |
291 | // allow NULL as empty strings |
292 | if (!s1) s1 = ""; |
293 | if (!s2) s2 = ""; |
294 | // s1>s2 : 1, s1==s2 : 0, s1<s2 : -1 |
295 | size_t i; |
296 | // calc number of chars we must compare |
297 | size_t len = len1==0 ? len2 : (len2==0 ? len1 : (len1>len2 ? len2 : len1)); |
298 | for (i=0; (!len || i<len) && *s1 && *s2; i++) { |
299 | // while both strings have chars and not len reached |
300 | if (toupper(*s1)!=toupper(*s2)) |
301 | return toupper(*s1)>toupper(*s2) ? 1 : -1; // different |
302 | // next |
303 | s1++; |
304 | s2++; |
305 | } |
306 | // equal up to end of shorter string or reached len |
307 | // - if both reached end or len -> equal |
308 | if ( ((len1 ? i==len1 : false) || *s1==0) && ((len2 ? i==len2 : false) || *s2==0) ) return 0; |
309 | // - not equal, longer string is larger |
310 | // (if not reached end of s1 or stopped before len1, s1 is longer |
311 | // but note than len1 can be longer than actual length of s1, so we |
312 | // must check for *s1 to make sure we have really not reached end of s1) |
313 | return (len1 ? i<len1 && *s1 : *s1) ? 1 : -1; |
314 | } // strucmp |
315 | |
316 | |
317 | // byte by byte strcmp, NULL allowed as empty string input |
318 | // Note: is compatible with standard strncmp if len2 is left unspecified |
319 | sInt16 strnncmp(const char *s1, const char *s2, size_t len1, size_t len2) |
320 | { |
321 | // allow NULL as empty strings |
322 | if (!s1) s1 = ""; |
323 | if (!s2) s2 = ""; |
324 | // s1>s2 : 1, s1==s2 : 0, s1<s2 : -1 |
325 | size_t i; // size_t instead of sInt32: BCPPB |
326 | // calc number of chars we must compare |
327 | size_t len = len1==0 ? len2 : (len2==0 ? len1 : (len1>len2 ? len2 : len1)); |
328 | for (i=0; (!len || i<len) && *s1 && *s2; i++) { |
329 | // while both strings have chars and not len reached |
330 | if (*s1!=*s2) |
331 | return *s1>*s2 ? 1 : -1; // different |
332 | // next |
333 | s1++; |
334 | s2++; |
335 | } |
336 | // equal up to end of shorter string or reached len |
337 | // - if both reached end or len |
338 | if ( ((len1 ? i==len1 : false) || *s1==0) && ((len2 ? i==len2 : false) || *s2==0) ) return 0; |
339 | // - not equal, longer string is larger |
340 | // (if not reached end of s1 or stopped before len1, s1 is longer |
341 | // but note than len1 can be longer than actual length of s1, so we |
342 | // must check for *s1 to make sure we have really not reached end of s1) |
343 | return (len1 ? i<len1 && *s1 : *s1) ? 1 : -1; |
344 | } // strnncmp |
345 | |
346 | |
347 | // parser for tag="value" type string format |
348 | cAppCharP nextTag(cAppCharP aTagString, string &aTag, string &aTagValue) |
349 | { |
350 | size_t n; |
351 | if (!aTagString) return NULL__null; |
352 | // find start of next tag |
353 | while (*aTagString==' ' || *aTagString==',') aTagString++; |
354 | // find end of tag |
355 | cAppCharP p = strchr(aTagString,'='); |
356 | if (!p) return NULL__null; // no more tags |
357 | n=p-aTagString; // size of tag |
358 | // save tag name |
359 | aTag.assign(aTagString,n); |
360 | // check for value |
361 | aTagValue.erase(); // default to none |
362 | p++; // skip '=' |
363 | if (*p==0) return NULL__null; // no more tags |
364 | // must start with single or double quote |
365 | char q=*p; // quote char |
366 | if (q!=0x22 && q!='\'') return p; // no value, next tag follows immediately |
367 | p++; // skip starting quote |
368 | while (*p) { |
369 | if (*p=='\\') { |
370 | // escape next char |
371 | p++; |
372 | if (*p==0) break; // no next char, string ends |
373 | } |
374 | else if (*p==q) { |
375 | // end of string (unescaped closing quote) |
376 | p++; // skip closing quote |
377 | break; |
378 | } |
379 | // just take char as it is |
380 | aTagValue+=*p++; |
381 | } |
382 | if (*p==';') p++; // skip semicolon if there is one |
383 | if (*p==0) return NULL__null; // end of string, no more tags |
384 | // p is now starting point for next tag |
385 | return p; |
386 | } // nextTag |
387 | |
388 | |
389 | // direct conversion of value (usually from nextTag()) into uInt32 |
390 | uInt32 uint32Val(cAppCharP aValue) |
391 | { |
392 | uInt32 res=0; |
393 | StrToULong(aValue, res); |
394 | return res; |
395 | } // uint32Val |
396 | |
397 | |
398 | // direct conversion of value (usually from nextTag()) into uInt16 |
399 | uInt16 uint16Val(cAppCharP aValue) |
400 | { |
401 | uInt16 res=0; |
402 | StrToUShort(aValue, res); |
403 | return res; |
404 | } // uint16val |
405 | |
406 | |
407 | // direct conversion of value (usually from nextTag()) into bool |
408 | bool boolVal(cAppCharP aValue) |
409 | { |
410 | bool res=false; |
411 | StrToBool(aValue, res); |
412 | return res; |
413 | } // boolVal |
414 | |
415 | |
416 | |
417 | // returns true on successful conversion of string to bool |
418 | bool StrToBool(const char *aStr, bool &aBool) |
419 | { |
420 | if ( |
421 | strutrimcmp(aStr,"yes")==0 || |
422 | strutrimcmp(aStr,"true")==0 || |
423 | strutrimcmp(aStr,"1")==0 || |
424 | strutrimcmp(aStr,"on")==0 |
425 | ) { |
426 | aBool=true; |
427 | return true; |
428 | } |
429 | else if ( |
430 | strutrimcmp(aStr,"no")==0 || |
431 | strutrimcmp(aStr,"false")==0 || |
432 | strutrimcmp(aStr,"0")==0 || |
433 | strutrimcmp(aStr,"off")==0 |
434 | ) { |
435 | aBool=false; |
436 | return true; |
437 | } |
438 | // error |
439 | return false; |
440 | } // StrToBool |
441 | |
442 | |
443 | const char *tristateString(sInt8 aTristate) |
444 | { |
445 | if (aTristate<0) return "default"; |
446 | else if (aTristate>0) return "Yes"; |
447 | else return "No"; |
448 | } |
449 | |
450 | |
451 | const char *boolString(bool aBool) |
452 | { |
453 | if (aBool) return "Yes"; |
454 | else return "No"; |
455 | } |
456 | |
457 | |
458 | |
459 | |
460 | // returns true on successful conversion of string to enum |
461 | bool StrToEnum(const char * const aEnumNames[], sInt16 aNumEnums, sInt16 &aShort, const char *aStr, sInt16 aLen) |
462 | { |
463 | const char *e; |
464 | for (sInt16 k=0; k<aNumEnums; k++) { |
465 | e=aEnumNames[k]; |
466 | if (!e) continue; // NULL entries are allowed in aEnumNames but will be skipped |
467 | if (strucmp(aStr,e,aLen)==0) { |
468 | aShort=k; |
469 | return true; |
470 | } |
471 | } |
472 | return false; // not found |
473 | } // StrToEnum |
474 | |
475 | |
476 | // makes hex char out of nibble |
477 | char NibbleToHexDigit(uInt8 aNibble) |
478 | { |
479 | aNibble &= 0x0F; |
480 | if (aNibble>9) return 'A'-0x0A+aNibble; |
481 | else return '0'+aNibble; |
482 | } // NibbleToHexDigit |
483 | |
484 | |
485 | // returns number of successfully converted chars |
486 | sInt16 HexStrToUShort(const char *aStr, uInt16 &aShort, sInt16 aMaxDigits) |
487 | { |
488 | // our own implementation |
489 | char c; |
490 | sInt16 n=0; |
491 | aShort=0; |
492 | //firstly check aMaxDigits to avoid accessing invalid value of 'aStr' |
493 | //This will cause a memory warning checked by valgrind |
494 | while ((n<aMaxDigits) && aStr && (c=*aStr++)) { |
495 | if (!isxdigit(c)) break; |
496 | aShort<<=4; |
497 | aShort+=(toupper(c)-0x30); |
498 | if (!isdigit(c)) aShort-=7; |
499 | n++; |
500 | } |
501 | return n; |
502 | } // HexStrToUShort |
503 | |
504 | |
505 | // returns number of successfully converted chars |
506 | sInt16 HexStrToULong(const char *aStr, uInt32 &aLong, sInt16 aMaxDigits) |
507 | { |
508 | // our own implementation |
509 | char c; |
510 | sInt16 n=0; |
511 | aLong=0; |
512 | |
513 | while (aStr && (c=*aStr++) && (n<aMaxDigits)) { |
514 | if (!isxdigit(c)) break; |
515 | aLong*= 16; |
516 | aLong+=(toupper(c)-0x30); |
517 | if (!isdigit(c)) aLong-=7; |
518 | n++; |
519 | } // while |
520 | |
521 | return n; |
522 | } // HexStrToULong |
523 | |
524 | |
525 | // returns number of successfully converted chars |
526 | sInt16 HexStrToULongLong(const char *aStr, uInt64 &aLongLong, sInt16 aMaxDigits) |
527 | { |
528 | // our own implementation |
529 | char c; |
530 | sInt16 n=0; |
531 | aLongLong=0; |
532 | |
533 | while (aStr && (c=*aStr++) && (n<aMaxDigits)) { |
534 | if (!isxdigit(c)) break; |
535 | aLongLong*= 16; |
536 | aLongLong+=(toupper(c)-0x30); |
537 | if (!isdigit(c)) aLongLong-=7; |
538 | n++; |
539 | } // while |
540 | |
541 | return n; |
542 | } // HexStrToULongLong |
543 | |
544 | sInt16 HexStrToUIntPtr(const char *aStr, uIntPtr &aIntPtr, sInt16 aMaxDigits) |
545 | { |
546 | #if __WORDSIZE64 == 64 |
547 | return HexStrToULongLong(aStr, aIntPtr, aMaxDigits); |
548 | #else |
549 | uInt32 l; |
550 | sInt16 n = HexStrToULong(aStr, l, aMaxDigits); |
551 | aIntPtr = (uIntPtr)l; |
552 | return n; |
553 | #endif |
554 | } // HexStrToUIntPtr |
555 | |
556 | // returns number of successfully converted chars |
557 | sInt16 StrToUShort(const char *aStr, uInt16 &aShort, sInt16 aMaxDigits) |
558 | { |
559 | // our own implementation |
560 | char c; |
561 | sInt16 n=0; |
562 | aShort=0; |
563 | while (aStr && (c=*aStr++) && (n<aMaxDigits)) { |
564 | if (!isdigit(c)) break; |
565 | aShort*=10; |
566 | aShort+=(c-0x30); |
567 | n++; |
568 | } |
569 | return n; |
570 | } // StrToUShort |
571 | |
572 | |
573 | // returns number of successfully converted chars |
574 | sInt16 StrToULong(const char *aStr, uInt32 &aLong, sInt16 aMaxDigits) |
575 | { |
576 | // our own implementation |
577 | char c; |
578 | sInt16 n=0; |
579 | aLong=0; |
580 | while (aStr && (c=*aStr++) && (n<aMaxDigits)) { |
581 | if (!isdigit(c)) break; |
582 | aLong*=10l; |
583 | aLong+=(c-0x30); |
584 | n++; |
585 | } |
586 | return n; |
587 | } // StrToULong |
588 | |
589 | |
590 | // returns number of successfully converted chars |
591 | sInt16 StrToULongLong(const char *aStr, uInt64 &aLongLong, sInt16 aMaxDigits) |
592 | { |
593 | // our own implementation |
594 | char c; |
595 | sInt16 n=0; |
596 | aLongLong=0; |
597 | while (aStr && (c=*aStr++) && (n<aMaxDigits)) { |
598 | if (!isdigit(c)) break; |
599 | aLongLong*=10l; |
600 | aLongLong+=(c-0x30); |
601 | n++; |
602 | } |
603 | return n; |
604 | } // StrToULongLong |
605 | |
606 | |
607 | // helper |
608 | static bool isMinus(const char *&aStr, sInt16 &aNumRead) |
609 | { |
610 | if (!aStr) return false; // not minus |
611 | if (*aStr=='-') { |
612 | aStr++; |
613 | aNumRead++; |
614 | return true; // is minus |
615 | } |
616 | else if (*aStr=='+') { |
617 | aStr++; |
618 | aNumRead++; |
619 | } |
620 | // is plus |
621 | return false; |
622 | } // isMinus |
623 | |
624 | |
625 | // returns number of successfully converted chars |
626 | sInt16 StrToShort(const char *aStr, sInt16 &aShort, sInt16 aMaxDigits) |
627 | { |
628 | // our own implementation |
629 | uInt16 temp; |
630 | sInt16 n=0; |
631 | bool neg=isMinus(aStr,n); |
632 | n+=StrToUShort(aStr,temp,aMaxDigits-n); |
633 | if (neg) aShort=-temp; |
634 | else aShort=temp; |
635 | return n; |
636 | } // StrToShort |
637 | |
638 | |
639 | // returns number of successfully converted chars |
640 | sInt16 StrToLong(const char *aStr, sInt32 &aLong, sInt16 aMaxDigits) |
641 | { |
642 | // our own implementation |
643 | uInt32 temp; |
644 | sInt16 n=0; |
645 | bool neg=isMinus(aStr,n); |
646 | n+=StrToULong(aStr,temp,aMaxDigits-n); |
647 | if (neg) aLong=-(sInt32)temp; |
648 | else aLong=temp; |
649 | return n; |
650 | } // StrToLong |
651 | |
652 | |
653 | // returns number of successfully converted chars |
654 | sInt16 StrToLongLong(const char *aStr, sInt64 &aLongLong, sInt16 aMaxDigits) |
655 | { |
656 | // our own implementation |
657 | uInt64 temp; |
658 | sInt16 n=0; |
659 | bool neg=isMinus(aStr,n); |
660 | n+=StrToULongLong(aStr,temp,aMaxDigits-n); |
661 | if (neg) aLongLong=-(sInt64)temp; |
662 | else aLongLong=temp; |
663 | return n; |
664 | } // StrToLongLong |
665 | |
666 | |
667 | #ifndef NO_FLOATS |
668 | |
669 | // returns number of successfully converted chars |
670 | sInt16 StrToDouble(const char *aStr, double &aDouble, sInt16 aMaxDigits) |
671 | { |
672 | // our own implementation |
673 | char c; |
674 | sInt16 n=0; |
675 | bool neg=isMinus(aStr,n); |
676 | sInt64 fraction=0; |
677 | aDouble=0; |
678 | while (aStr && (c=*aStr++) && (n<aMaxDigits)) { |
679 | if (!isdigit(c)) { |
680 | if (fraction || c!='.') break; |
681 | fraction=10; // first digit after decimal point is 1/10 |
682 | n++; |
683 | continue; // next |
684 | } |
685 | c-=0x30; // make 0..9 |
686 | if (fraction) { |
687 | // within fractional part |
688 | aDouble+=(double)c/fraction; |
689 | fraction*=10; |
690 | } |
691 | else { |
692 | // integer part |
693 | aDouble*=10.0; |
694 | aDouble+=c; |
695 | } |
696 | n++; |
697 | } |
698 | if (neg) aDouble=-aDouble; |
699 | return n; |
700 | } // StrToDouble |
701 | |
702 | #endif // NO_FLOATS |
703 | |
704 | |
705 | // returns number of C-string-escaped chars successfully converted to string |
706 | sInt16 CStrToStrAppend(const char *aStr, string &aString, bool aStopAtQuoteOrCtrl, char ignore) |
707 | { |
708 | unsigned char c; |
709 | const char *p=aStr; |
710 | while ((c=*p++)) { |
711 | // check for escape |
712 | if (c=='\\') { |
713 | // escape, check next |
714 | c=*p++; |
715 | if (!c) break; // unfinished escape sequence is ignored |
716 | switch (c) { |
717 | case 't' : c=0x09; break; // TAB |
718 | case 'n' : c=0x0A; break; // line feed |
719 | case 'r' : c=0x0D; break; // carriage return |
720 | case '\r': |
721 | case '\n': |
722 | // continued line, swallow line end |
723 | c=0; |
724 | break; |
725 | case 'x' : |
726 | // hex char |
727 | c=0; uInt16 n=0; |
728 | while (isxdigit(*p) && n<2) { |
729 | c=(c<<4) | (*p>'9' ? toupper(*p)-'A'+0x0A : *p-'0'); |
730 | p++; n++; |
731 | } |
732 | break; |
733 | } |
734 | // c is the char to add |
735 | } |
736 | else if (aStopAtQuoteOrCtrl && (c=='"' || c<0x20)) { |
737 | // terminating char is NOT consumed |
738 | p--; |
739 | break; // stop here |
740 | } |
741 | // otherwise, ignore any control characters |
742 | else if (c<0x20 && c!=ignore) |
743 | continue; |
744 | // add it to the result |
745 | if (c) aString+=c; |
746 | } |
747 | // return number of converted chars |
748 | return p-aStr; |
749 | } // CStrToStrAppend |
750 | |
751 | |
752 | |
753 | // add a hex byte to a string |
754 | // Note: this is required because PalmOS sprintf does not correctly |
755 | // work with %02X (always writes 4 digits!) |
756 | void AppendHexByte(string &aString, uInt8 aByte) |
757 | { |
758 | aString += NibbleToHexDigit(aByte>>4); |
759 | aString += NibbleToHexDigit(aByte); |
760 | } // AppendHexByte |
761 | |
762 | |
763 | // returns number of C-string-escaped chars successfully converted to string |
764 | sInt16 StrToCStrAppend(const char *aStr, string &aString, bool aAllow8Bit, char ignore) |
765 | { |
766 | unsigned char c; |
767 | const char *p=aStr; |
768 | while ((c=*p++)) { |
769 | // check for specials |
770 | if (c==ignore) aString+= c; |
771 | else if (c==0x09) aString+="\\t"; |
772 | else if (c==0x0A) aString+="\\n"; |
773 | else if (c==0x0D) aString+="\\r"; |
774 | else if (c==0x22) aString+="\\\""; |
775 | else if (c=='\\') aString+="\\\\"; // escape the backslash as well |
776 | else if (c<0x20 || c==0x7F || (!aAllow8Bit && c>=0x80)) { |
777 | aString += "\\x"; |
778 | AppendHexByte(aString,c); |
779 | } |
780 | else { |
781 | // as is |
782 | aString+=c; |
783 | } |
784 | } |
785 | // return number of converted chars |
786 | return p-aStr; |
787 | } // CStrToStrAppend |
788 | |
789 | |
790 | |
791 | // old-style C-formatted output into string object |
792 | void vStringObjPrintf(string &aStringObj, const char *aFormat, bool aAppend, va_list aArgs) |
793 | { |
794 | #ifndef NO_VSNPRINTF |
795 | const size_t bufsiz=128; |
796 | #else |
797 | const size_t bufsiz=2048; |
798 | #endif |
799 | ssize_t actualsize; |
800 | char buf[bufsiz]; |
801 | |
802 | buf[0]='\0'; |
803 | char *bufP = NULL__null; |
804 | if (!aAppend) aStringObj.erase(); |
805 | #ifndef NO_VSNPRINTF |
806 | // using aArgs in vsnprintf() is destructive, need a copy in |
807 | // case we call the function a second time |
808 | va_list args; |
809 | va_copy(args, aArgs)__builtin_va_copy(args, aArgs); |
810 | #endif |
811 | actualsize = vsnprintf(buf, bufsiz, aFormat, aArgs); |
812 | #ifndef NO_VSNPRINTF |
813 | if (actualsize>=(ssize_t)bufsiz) { |
814 | // default buffer was too small, create bigger dynamic buffer |
815 | bufP = new char[actualsize+1]; |
816 | actualsize = vsnprintf(bufP, actualsize+1, aFormat, args); |
817 | if (actualsize>0) { |
818 | aStringObj += bufP; |
819 | } |
820 | delete [] bufP; |
821 | } |
822 | else |
823 | #endif |
824 | { |
825 | // small default buffer was big enough, add it |
826 | if (actualsize<0) goto done; // abort, error |
827 | aStringObj += buf; |
828 | } |
829 | done: |
830 | #ifndef NO_VSNPRINTF |
831 | va_end(args)__builtin_va_end(args); |
832 | #endif |
833 | } // vStringObjPrintf |
834 | |
835 | |
836 | // old-style C-formatted output into string object |
837 | void StringObjPrintf(string &aStringObj, const char *aFormat, ...) |
838 | { |
839 | va_list args; |
840 | |
841 | va_start(args, aFormat)__builtin_va_start(args, aFormat); |
842 | // now make the string |
843 | vStringObjPrintf(aStringObj,aFormat,false,args); |
844 | va_end(args)__builtin_va_end(args); |
845 | } // StringObjPrintf |
846 | |
847 | |
848 | // old-style C-formatted output appending into string object |
849 | void StringObjAppendPrintf(string &aStringObj, const char *aFormat, ...) |
850 | { |
851 | va_list args; |
852 | |
853 | va_start(args, aFormat)__builtin_va_start(args, aFormat); |
854 | // now make the string |
855 | vStringObjPrintf(aStringObj,aFormat,true,args); |
856 | va_end(args)__builtin_va_end(args); |
857 | } // StringObjAppendPrintf |
858 | |
859 | } // namespace sysync |
860 | |
861 | /* eof */ |
862 |