Bug Summary

File:libsynthesis/src/sysync/stringutils.cpp
Warning:line 131, column 21
Value stored to 'kp' is never read

Annotated Source Code

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
28using namespace std;
29
30namespace sysync {
31
32
33
34#ifdef NO_VSNPRINTF
35// dummy (unsafe!!) map to vsprintf
36int 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)
44int 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
60const 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
68void 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
79void 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
91void 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
112uInt16 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
145void 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
161void 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
180sInt16 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
194sInt16 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
243bool 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
268sInt32 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
289sInt16 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
319sInt16 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
348cAppCharP 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
390uInt32 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
399uInt16 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
408bool 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
418bool 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
443const 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
451const 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
461bool 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
477char 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
486sInt16 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
506sInt16 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
526sInt16 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
544sInt16 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
557sInt16 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
574sInt16 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
591sInt16 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
608static 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
626sInt16 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
640sInt16 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
654sInt16 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
670sInt16 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
706sInt16 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!)
756void 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
764sInt16 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
792void 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
837void 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
849void 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