1 /*
2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2003 University of Virginia,
4 ** Massachusetts Institute of Technology
5 **
6 ** This program is free software; you can redistribute it and/or modify it
7 ** under the terms of the GNU General Public License as published by the
8 ** Free Software Foundation; either version 2 of the License, or (at your
9 ** option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful, but
12 ** WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ** General Public License for more details.
15 **
16 ** The GNU General Public License is available from http://www.gnu.org/ or
17 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18 ** MA 02111-1307, USA.
19 **
20 ** For information on splint: info@splint.org
21 ** To report a bug: splint-bug@splint.org
22 ** For more information: http://www.splint.org
23 */
24 /*
25 ** cstring.c
26 */
27
28 /*
29 * Herbert 06/12/2000
30 * - use drive spec specials with OS2 like with WIN32
31 * - cstring_replaceAll () needed in cpplib.c
32 */
33
34 # include "splintMacros.nf"
35 # include "basic.h"
36 # include "osd.h"
37
38 /*@only@*/ /*@notnull@*/
cstring_newEmpty(void)39 cstring cstring_newEmpty (void)
40 {
41 return (cstring_create (0));
42 }
43
cstring_firstChar(cstring s)44 char cstring_firstChar (cstring s)
45 {
46 llassert (cstring_isDefined (s));
47 llassert (cstring_length (s) > 0);
48
49 return (s[0]);
50 }
51
cstring_getChar(cstring s,size_t n)52 char cstring_getChar (cstring s, size_t n)
53 {
54 size_t length = cstring_length (s);
55
56 llassert (cstring_isDefined (s));
57 llassert (n >= 1 && n <= length);
58
59 return (s[n - 1]);
60 }
61
cstring_suffix(cstring s,size_t n)62 cstring cstring_suffix (cstring s, size_t n)
63 {
64 llassert (cstring_isDefined (s));
65 llassert (n <= cstring_length (s));
66
67 return (s + n);
68 }
69
cstring_prefix(cstring s,size_t n)70 cstring cstring_prefix (cstring s, size_t n)
71 /*@requires maxRead(s) >= n /\ maxSet(s) >= n @*/
72 /*@ensures maxRead(result) == n /\ maxSet(result) == n @*/
73 {
74 cstring t;
75 char c;
76 llassert (cstring_isDefined (s));
77 llassert (n <= cstring_length (s));
78
79 c = *(s + n);
80 /*@-mods@*/ /* The modifications cancel out. */
81 *(s + n) = '\0';
82 t = cstring_copy (s);
83 *(s + n) = c;
84 /*@=mods@*/
85
86 return t;
87 }
88
89 /* effects If s = [0-9]*, returns s as an int.
90 ** else returns -1.
91 */
92
cstring_toPosInt(cstring s)93 int cstring_toPosInt (cstring s)
94 {
95 int val = 0;
96
97 cstring_chars (s, c)
98 {
99 if (isdigit ((unsigned char) c))
100 {
101 val = (val * 10) + (int)(c - '0');
102 }
103 else
104 {
105 return -1;
106 }
107 } end_cstring_chars ;
108
109 return val;
110 }
111
cstring_afterChar(cstring s,char c)112 cstring cstring_afterChar (cstring s, char c)
113 {
114 llassert (cstring_isDefined (s));
115 return strchr (s, c);
116 }
117
cstring_beforeChar(cstring s,char c)118 cstring cstring_beforeChar (cstring s, char c)
119 {
120 if (cstring_isDefined (s))
121 {
122 char *cp = strchr (s, c);
123
124 if (cp != NULL)
125 {
126 cstring ret;
127
128 /*@-mods@*/
129 *cp = '\0';
130 ret = cstring_copy (s);
131 *cp = c;
132 /*@=mods@*/ /* modification is undone */
133
134 return ret;
135 }
136 }
137
138 return cstring_undefined;
139 }
140
cstring_setChar(cstring s,size_t n,char c)141 void cstring_setChar (cstring s, size_t n, char c) /*@requires maxRead(s) >= (n - 1) /\ maxSet(s) >= (n - 1) @*/
142 {
143 llassert (cstring_isDefined (s));
144 llassert (n > 0 && n <= cstring_length (s));
145
146 s[n - 1] = c;
147 }
148
cstring_lastChar(cstring s)149 char cstring_lastChar (cstring s)
150 {
151 size_t length;
152
153 llassert (cstring_isDefined (s));
154
155 length = cstring_length (s);
156 llassert (length > 0);
157
158 return (s[length - 1]);
159 }
160
cstring_copy(cstring s)161 /*@only@*/ cstring cstring_copy (cstring s) /*@ensures maxSet(result) == maxRead(s) /\ maxRead(result) == maxRead(s) @*/
162 {
163 if (cstring_isDefined (s))
164 {
165 return (mstring_copy (s));
166 }
167 else
168 {
169 return cstring_undefined;
170 }
171 }
172
cstring_copyLength(char * s,size_t len)173 /*@only@*/ cstring cstring_copyLength (char *s, size_t len) /*@requires maxSet(s) >= (len - 1) @*/
174 {
175 char *res = mstring_create (len + 1);
176
177 strncpy (res, s, len);
178 res[len] = '\0';
179 return res;
180 }
181
cstring_containsChar(cstring c,char ch)182 bool cstring_containsChar (cstring c, char ch)
183 {
184 if (cstring_isDefined (c))
185 {
186 return (strchr (c, ch) != NULL);
187 }
188 else
189 {
190 return FALSE;
191 }
192 }
193
194 /*
195 ** Replaces all occurances of old in s with new.
196 */
197
cstring_replaceAll(cstring s,char old,char snew)198 void cstring_replaceAll (cstring s, char old, char snew)
199 {
200
201 llassert (old != snew);
202
203 if (cstring_isDefined (s))
204 {
205 char *sp = strchr (s, old);
206
207 while (sp != NULL)
208 {
209 *sp = snew;
210 sp = strchr (sp, old);
211 }
212
213 }
214 }
215
cstring_replaceLit(cstring s,char * old,char * snew)216 void cstring_replaceLit (/*@unique@*/ cstring s, char *old, char *snew)
217 /*@requires maxRead(snew) >= 0 /\ maxRead(old) >= 0 /\ maxRead(old) >= maxRead(snew) @*/
218 {
219 llassert (strlen (old) >= strlen (snew));
220
221 if (cstring_isDefined (s))
222 {
223 char *sp = strstr (s, old);
224
225 while (sp != NULL)
226 {
227 int lendiff = size_toInt (strlen (old) - strlen (snew));
228 char *tsnew = snew;
229
230 llassert (lendiff >= 0);
231
232 while (*tsnew != '\0')
233 {
234 llassert (*sp != '\0');
235 *sp++ = *tsnew++;
236 }
237
238 if (lendiff > 0)
239 {
240 while (*(sp + lendiff) != '\0')
241 {
242 *sp = *(sp + lendiff);
243 sp++;
244 }
245
246 *sp = '\0';
247 }
248
249 sp = strstr (s, old);
250 }
251 }
252 }
253
254 /*
255 ** removes all chars in clist from s
256 */
257
cstring_stripChars(cstring s,const char * clist)258 void cstring_stripChars (cstring s, const char *clist)
259 {
260 if (cstring_isDefined (s))
261 {
262 int i;
263 size_t size = cstring_length (s);
264
265 for (i = 0; i < size_toInt (size); i++)
266 {
267
268 char c = s[i];
269
270 if (strchr (clist, c) != NULL)
271 {
272 /* strip this char */
273 int j;
274
275 size--;
276
277 for (j = i; j < size_toInt (size); j++)
278 {
279 s[j] = s[j+1];
280 }
281
282 s[size] = '\0';
283 i--;
284 }
285 }
286 }
287 }
288
cstring_contains(cstring c,cstring sub)289 bool cstring_contains (/*@unique@*/ cstring c, cstring sub)
290 {
291 if (cstring_isDefined (c))
292 {
293 llassert (cstring_isDefined (sub));
294
295 return (strstr (c, sub) != NULL);
296 }
297 else
298 {
299 return FALSE;
300 }
301 }
302
lookLike(char c)303 static char lookLike (char c) /*@*/
304 {
305 if (c == 'I' || c == 'l')
306 {
307 return '1';
308 }
309 else if (c == 'O' || c == 'o')
310 {
311 return '0';
312 }
313 else if (c == 'Z')
314 {
315 return '2';
316 }
317 else if (c == 'S')
318 {
319 return '5';
320 }
321 else
322 {
323 return c;
324 }
325 }
326
cstring_genericEqual(cstring s,cstring t,size_t nchars,bool caseinsensitive,bool lookalike)327 cmpcode cstring_genericEqual (cstring s, cstring t,
328 size_t nchars,
329 bool caseinsensitive,
330 bool lookalike)
331 /*@requires maxRead(s) >= nchars /\ maxRead(t) >= nchars @*/
332 {
333 if (s == t) return CGE_SAME;
334 else if (cstring_isUndefined (s))
335 {
336 return cstring_isEmpty (t) ? CGE_SAME : CGE_DISTINCT;
337 }
338 else if (cstring_isUndefined (t))
339 {
340 return cstring_isEmpty (s) ? CGE_SAME : CGE_DISTINCT;
341 }
342 else
343 {
344 int i = 0;
345 bool diffcase = FALSE;
346 bool difflookalike = FALSE;
347
348 while (*s != '\0')
349 {
350 if (nchars > 0 && i >= size_toInt (nchars))
351 {
352 break;
353 }
354
355 if (*t == *s)
356 {
357 ; /* no difference */
358 }
359 else if (caseinsensitive
360 && (toupper ((int) *t) == toupper ((int) *s)))
361 {
362 diffcase = TRUE;
363 }
364 else if (lookalike && (lookLike (*t) == lookLike (*s)))
365 {
366 difflookalike = TRUE;
367 }
368 else
369 {
370 return CGE_DISTINCT;
371 }
372 i++;
373 s++;
374 t++;
375 }
376
377
378 if (*s == '\0' && *t != '\0')
379 {
380 return CGE_DISTINCT;
381 }
382
383 if (diffcase)
384 {
385 return CGE_CASE;
386 }
387 else if (difflookalike)
388 {
389 return CGE_LOOKALIKE;
390 }
391 else
392 {
393 return CGE_SAME;
394 }
395 }
396 }
397
398
399
cstring_equalFree(cstring c1,cstring c2)400 bool cstring_equalFree (/*@only@*/ cstring c1, /*@only@*/ cstring c2)
401 {
402 bool res = cstring_equal (c1, c2);
403 cstring_free (c1);
404 cstring_free (c2);
405 return res;
406 }
407
cstring_equal(cstring c1,cstring c2)408 bool cstring_equal (cstring c1, cstring c2)
409 {
410 if (c1 == c2) return TRUE;
411 else if (cstring_isUndefined (c1)) return cstring_isEmpty (c2);
412 else if (cstring_isUndefined (c2)) return cstring_isEmpty (c1);
413 else return (strcmp (c1, c2) == 0);
414 }
415
cstring_equalLen(cstring c1,cstring c2,size_t len)416 bool cstring_equalLen (cstring c1, cstring c2, size_t len)
417 {
418 if (c1 == c2) return TRUE;
419 else if (cstring_isUndefined (c1)) return cstring_isEmpty (c2);
420 else if (cstring_isUndefined (c2)) return cstring_isEmpty (c1);
421 else return (strncmp (c1, c2, len) == 0);
422 }
423
cstring_equalCaseInsensitive(cstring c1,cstring c2)424 bool cstring_equalCaseInsensitive (cstring c1, cstring c2)
425 {
426 if (c1 == c2) return TRUE;
427 else if (cstring_isUndefined (c1)) return cstring_isEmpty (c2);
428 else if (cstring_isUndefined (c2)) return cstring_isEmpty (c1);
429 else return (cstring_genericEqual (c1, c2, 0, TRUE, FALSE) != CGE_DISTINCT);
430 }
431
cstring_equalLenCaseInsensitive(cstring c1,cstring c2,size_t len)432 bool cstring_equalLenCaseInsensitive (cstring c1, cstring c2, size_t len)
433 {
434 if (c1 == c2) return TRUE;
435 else if (cstring_isUndefined (c1)) return cstring_isEmpty (c2);
436 else if (cstring_isUndefined (c2)) return cstring_isEmpty (c1);
437 else return (cstring_genericEqual (c1, c2, len, TRUE, FALSE) != CGE_DISTINCT);
438 }
439
cstring_equalPrefix(cstring c1,cstring c2)440 bool cstring_equalPrefix (cstring c1, cstring c2)
441 {
442 llassert (c2 != NULL);
443
444 if (cstring_isUndefined (c1))
445 {
446 return (strlen (c2) == 0);
447 }
448
449 return (strncmp (c1, c2, strlen (c2)) == 0);
450 }
451
cstring_equalPrefixLit(cstring c1,const char * c2)452 bool cstring_equalPrefixLit (cstring c1, const char *c2)
453 {
454 llassert (c2 != NULL);
455
456 if (cstring_isUndefined (c1))
457 {
458 return (strlen (c2) == 0);
459 }
460
461 return (strncmp (c1, c2, strlen (c2)) == 0);
462 }
463
cstring_xcompare(cstring * c1,cstring * c2)464 int cstring_xcompare (cstring *c1, cstring *c2)
465 {
466 return (cstring_compare (*c1, *c2));
467 }
468
cstring_compare(cstring c1,cstring c2)469 int cstring_compare (cstring c1, cstring c2)
470 {
471 int res;
472
473 if (c1 == c2)
474 {
475 res = 0;
476 }
477 else if (cstring_isUndefined (c1))
478 {
479 if (cstring_isEmpty (c2))
480 {
481 res = 0;
482 }
483 else
484 {
485 res = 1;
486 }
487 }
488 else if (cstring_isUndefined (c2))
489 {
490 if (cstring_isEmpty (c1))
491 {
492 res = 0;
493 }
494 else
495 {
496 res = -1;
497 }
498 }
499 else
500 {
501 res = strcmp (c1, c2);
502 }
503
504 return (res);
505 }
506
cstring_markOwned(cstring s)507 void cstring_markOwned (/*@owned@*/ cstring s)
508 {
509 sfreeEventually (s);
510 }
511
cstring_free(cstring s)512 void cstring_free (/*@only@*/ cstring s)
513 {
514 if (cstring_isDefined (s))
515 {
516 /*drl 2/3/2002*/
517 s[0] = '\0';
518
519 sfree (s);
520 }
521 }
522
cstring_fromChars(const char * cp)523 cstring cstring_fromChars (/*@exposed@*/ const char *cp)
524 {
525 return (cstring) cp;
526 }
527
cstring_toCharsSafe(cstring s)528 /*@exposed@*/ char *cstring_toCharsSafe (cstring s)
529 {
530 static /*@only@*/ cstring emptystring = cstring_undefined;
531
532 if (cstring_isDefined (s))
533 {
534 return (char *) s;
535 }
536 else
537 {
538 if (cstring_isUndefined (emptystring))
539 {
540 emptystring = cstring_newEmpty ();
541 }
542
543 return emptystring;
544 }
545 }
546
cstring_length(cstring s)547 size_t cstring_length (cstring s)
548 {
549 if (cstring_isDefined (s))
550 {
551 return strlen (s);
552 }
553
554 return 0;
555 }
556
557 cstring
cstring_capitalize(cstring s)558 cstring_capitalize (cstring s) /*@requires maxSet(s) >= 0 @*/
559 {
560 if (!cstring_isEmpty (s))
561 {
562 cstring ret = cstring_copy (s);
563
564 cstring_setChar (ret, 1, (char) toupper ((int) cstring_firstChar (ret)));
565 return ret;
566 }
567
568 return cstring_undefined;
569 }
570
571 cstring
cstring_capitalizeFree(cstring s)572 cstring_capitalizeFree (cstring s) /*@requires maxSet(s) >= 0 /\ maxRead(s) >= 0 @*/
573 {
574 if (!cstring_isEmpty (s))
575 {
576 cstring_setChar (s, 1, (char) toupper ((int) cstring_firstChar (s)));
577 return s;
578 }
579
580 return s;
581 }
582
583 cstring
cstring_clip(cstring s,size_t len)584 cstring_clip (cstring s, size_t len)
585 {
586 if (cstring_isUndefined (s) || cstring_length (s) <= len)
587 {
588 ;
589 }
590 else
591 {
592 llassert (s != NULL);
593
594 *(s + len) = '\0';
595 }
596
597 return s;
598 }
599
600 /*@only@*/ cstring
cstring_elide(cstring s,size_t len)601 cstring_elide (cstring s, size_t len)
602 {
603 if (cstring_isUndefined (s) || cstring_length (s) <= len)
604 {
605 return cstring_copy (s);
606 }
607 else
608 {
609 cstring sc = cstring_create (len);
610
611 strncpy (sc, s, len);
612
613 *(sc + len - 1) = '\0';
614 *(sc + len - 2) = '.';
615 *(sc + len - 3) = '.';
616 *(sc + len - 4) = '.';
617
618 return sc;
619 }
620 }
621
622 /*@only@*/ cstring
cstring_fill(cstring s,size_t n)623 cstring_fill (cstring s, size_t n) /*@requires n >= 0 @*/
624 {
625 cstring t = cstring_create (n + 1);
626 cstring ot = t;
627 size_t len = cstring_length (s);
628 size_t i;
629
630 if (len > n)
631 {
632 for (i = 0; i < n; i++)
633 {
634
635 *t++ = *s++;
636 }
637 *t = '\0';
638 }
639 else
640 {
641 for (i = 0; i < len; i++)
642 {
643
644 *t++ = *s++;
645 }
646 for (i = 0; i < n - len; i++)
647 {
648
649 *t++ = ' ';
650 }
651 *t = '\0';
652 }
653
654 return ot;
655 }
656
657 cstring
cstring_downcase(cstring s)658 cstring_downcase (cstring s)
659 {
660 if (cstring_isDefined (s))
661 {
662 cstring t = cstring_create (strlen (s) + 1);
663 cstring ot = t;
664 char c;
665
666 while ((c = *s) != '\0')
667 {
668 if (c >= 'A' && c <= 'Z')
669 {
670 c = c - 'A' + 'a';
671 }
672 *t++ = c;
673 s++;
674 }
675 *t = '\0';
676
677 return ot;
678 }
679 else
680 {
681 return cstring_undefined;
682 }
683 }
684
685 /*@notnull@*/ cstring
cstring_appendChar(cstring s1,char c)686 cstring_appendChar (/*@only@*/ cstring s1, char c)
687 {
688 size_t l = cstring_length (s1);
689 char *s;
690
691 s = (char *) dmalloc (sizeof (*s) * (l + 2));
692
693 if (cstring_isDefined (s1))
694 {
695 strcpy (s, s1);
696 *(s + l) = c;
697 *(s + l + 1) = '\0';
698 sfree (s1);
699 }
700 else
701 {
702 *(s) = c;
703 *(s + 1) = '\0';
704 }
705
706 return s;
707 }
708
709 /*@only@*/ cstring
cstring_concatFree(cstring s,cstring t)710 cstring_concatFree (cstring s, cstring t)
711 {
712 cstring res = cstring_concat (s, t);
713 cstring_free (s);
714 cstring_free (t);
715 return res;
716 }
717
718 /*@only@*/ cstring
cstring_concatFree1(cstring s,cstring t)719 cstring_concatFree1 (cstring s, cstring t)
720 {
721 cstring res = cstring_concat (s, t);
722 cstring_free (s);
723 return res;
724 }
725
726 /*@only@*/ cstring
cstring_concatChars(cstring s,char * t)727 cstring_concatChars (cstring s, char *t)
728 {
729 cstring res = cstring_concat (s, cstring_fromChars (t));
730 cstring_free (s);
731 return res;
732 }
733
734 /*@only@*/ cstring
cstring_concatLength(cstring s1,char * s2,size_t len)735 cstring_concatLength (cstring s1, char *s2, size_t len) /*@requires maxSet(s2) >= (len - 1) @*/
736 {
737 cstring tmp = cstring_copyLength (s2, len);
738 cstring res = cstring_concat (s1, tmp);
739 cstring_free (tmp);
740 cstring_free (s1);
741
742 return res;
743 }
744
745 /*@only@*/ cstring
cstring_concat(cstring s,cstring t)746 cstring_concat (cstring s, cstring t) /*@requires maxSet(s) >= 0 @*/
747 {
748 char *ret = mstring_create (cstring_length (s) + cstring_length (t));
749
750 if (cstring_isDefined (s))
751 {
752 strcpy (ret, s);
753 }
754 if (cstring_isDefined (t))
755 {
756 strcat (ret, t);
757 }
758
759 return ret;
760 }
761
762 /*@notnull@*/ /*@only@*/ cstring
cstring_prependCharO(char c,cstring s1)763 cstring_prependCharO (char c, /*@only@*/ cstring s1)
764 {
765 cstring res = cstring_prependChar (c, s1);
766
767 cstring_free (s1);
768 return (res);
769 }
770
771 /*@notnull@*/ /*@only@*/ cstring
cstring_prependChar(char c,cstring s1)772 cstring_prependChar (char c, /*@temp@*/ cstring s1)
773 {
774 size_t l = cstring_length (s1);
775 char *s = (char *) dmalloc (sizeof (*s) * (l + 2));
776
777 *(s) = c;
778
779 if (cstring_isDefined (s1))
780 {
781 /*@-mayaliasunique@*/
782 strcpy (s + 1, s1);
783 /*@=mayaliasunique@*/
784 }
785
786 *(s + l + 1) = '\0';
787 return s;
788 }
789
790 bool
cstring_hasNonAlphaNumBar(cstring s)791 cstring_hasNonAlphaNumBar (cstring s)
792 {
793 int c;
794
795 if (cstring_isUndefined (s)) return FALSE;
796
797 while ((c = (int) *s) != (int) '\0')
798 {
799 if ((isalnum (c) == 0) && (c != (int) '_')
800 && (c != (int) '.') && (c != (int) CONNECTCHAR))
801 {
802 return TRUE;
803 }
804
805 s++;
806 }
807 return FALSE;
808 }
809
810 /*@only@*/ /*@notnull@*/ cstring
cstring_create(size_t n)811 cstring_create (size_t n)
812 {
813 char *s = dmalloc (sizeof (*s) * (n + 1));
814
815 *s = '\0';
816 return s;
817 }
818
819 /*@only@*/ /*@notnull@*/ cstring
cstring_copySegment(cstring s,size_t findex,size_t tindex)820 cstring_copySegment (cstring s, size_t findex, size_t tindex)
821 {
822 cstring res = cstring_create (tindex - findex + 1);
823
824 llassert (cstring_isDefined (s));
825 llassert (cstring_length (s) > tindex);
826
827 strncpy (res, (s + findex), size_fromInt (size_toInt (tindex - findex) + 1));
828 return res;
829 }
830
cstring_toSymbol(cstring s)831 lsymbol cstring_toSymbol (cstring s)
832 {
833 lsymbol res = lsymbol_fromString (s);
834
835 cstring_free (s);
836 return res;
837 }
838
cstring_bsearch(cstring key,char ** table,int nentries)839 cstring cstring_bsearch (cstring key, char **table, int nentries)
840 {
841 if (cstring_isDefined (key))
842 {
843 int low = 0;
844 int high = nentries;
845 int mid = (high + low + 1) / 2;
846 int last = -1;
847 cstring res = cstring_undefined;
848
849 while (low <= high && mid < nentries)
850 {
851 int cmp;
852
853 llassert (mid != last);
854 llassert (mid >= 0 && mid < nentries);
855
856 cmp = cstring_compare (key, table[mid]);
857
858 if (cmp == 0)
859 {
860 res = table[mid];
861 break;
862 }
863 else if (cmp < 0) /* key is before table[mid] */
864 {
865 high = mid - 1;
866 }
867 else /* key of after table[mid] */
868 {
869 low = mid + 1;
870 }
871
872 last = mid;
873 mid = (high + low + 1) / 2;
874 }
875
876 if (mid != 0 && mid < nentries - 1)
877 {
878 llassert (cstring_compare (key, table[mid - 1]) > 0);
879 llassert (cstring_compare (key, table[mid + 1]) < 0);
880 }
881
882 return res;
883 }
884
885 return cstring_undefined;
886 }
887
cstring_advanceWhiteSpace(cstring s)888 extern /*@observer@*/ cstring cstring_advanceWhiteSpace (cstring s)
889 {
890 if (cstring_isDefined (s)) {
891 char *t = s;
892
893 while (*t != '\0' && isspace ((int) *t)) {
894 t++;
895 }
896
897 return t;
898 }
899
900 return cstring_undefined;
901 }
902
903 /* changes strings like "sdf" "sdfsd" into "sdfsdfsd"*/
904 /* This function understands that "sdf\" \"sdfsdf" is okay*/
doMergeString(cstring s)905 static mstring doMergeString (cstring s)
906 {
907 char *ptr;
908 mstring ret;
909 char * retPtr;
910 bool escape;
911
912 llassert(cstring_isDefined (s));
913
914 ret = mstring_create (cstring_length(s) );
915
916 ptr = s;
917
918 retPtr = ret;
919 /*
920 llassert(*ptr == '\"');
921
922 *retPtr = *ptr;
923
924 retPtr++;
925 ptr++;
926 */
927
928 while (*ptr != '\0')
929 {
930 escape = FALSE;
931
932 if (*ptr == '\\')
933 {
934 *retPtr = *ptr;
935
936 if (!escape)
937 escape = TRUE;
938 else
939 /* case of escaped \ ('\\') */
940 escape = FALSE;
941 }
942 else if ( (*ptr == '\"') && (!escape) )
943 {
944 while ( (ptr[1] != '\"') && (ptr[1] != '\0') )
945 {
946 ptr++;
947 }
948 if (ptr[1] == '\0')
949 {
950 llassert(*ptr == '\"');
951 *retPtr = '\"';
952 retPtr++;
953 *retPtr = '\0';
954 BADEXIT;
955
956 /*@notreached@*/ return ret;
957 }
958 else
959 {
960 ptr++;
961 }
962 }
963 else
964 {
965 *retPtr = *ptr;
966 }
967
968 retPtr++;
969 ptr++;
970
971 }/* end while */
972 *retPtr = '\0';
973 return ret;
974 }
975
doExpandEscapes(cstring s,size_t * len)976 static mstring doExpandEscapes (cstring s, /*@out@*/ size_t *len)
977 {
978 char *ptr;
979 mstring ret;
980 char * retPtr;
981
982 llassert(cstring_isDefined (s));
983
984 ret = mstring_create (cstring_length(s));
985
986 ptr = s;
987
988 retPtr = ret;
989 while (*ptr != '\0')
990 {
991 if (*ptr != '\\')
992 {
993 *retPtr = *ptr;
994 retPtr++;
995 ptr++;
996 continue;
997 }
998
999 if (*ptr == '\\')
1000 {
1001 ptr++;
1002 if (*ptr == '\0')
1003 {
1004 /*not a legal escape sequence but try to handle it in a sesible way*/
1005 *retPtr = '\\';
1006 retPtr++;
1007 }
1008
1009 /* Handle Octal escapes */
1010 else if (*ptr >= '0' && *ptr <= '9' )
1011 {
1012 int total;
1013 total = (int)(*ptr - '0');
1014 ptr++;
1015 /*octal can only be 3 characters long */
1016 if (*ptr != '\0' && (*ptr >= '0' && *ptr <= '9' ) )
1017 {
1018 total *= 8;
1019 ptr++;
1020 if (*ptr != '\0' && (*ptr >= '0' && *ptr <= '9' ) )
1021 {
1022 total *= 8;
1023 total += (int) (*ptr - '0');
1024 ptr++;
1025 }
1026 }
1027
1028 *retPtr = (char) total;
1029 retPtr++;
1030 }
1031
1032 else if (*ptr == 'x')
1033 {
1034 int total;
1035 total = 0;
1036 ptr++;
1037 if (!(*ptr != '\0' &&
1038 ( (*ptr >= '0' && *ptr <= '9' ) ||
1039 (toupper(*ptr) >= (int)('A') && toupper(*ptr) <= (int)('F') ) )
1040 ))
1041 {
1042 total = (int)'x';
1043 }
1044 else
1045 {
1046 while (*ptr != '\0' &&
1047 ( (*ptr >= '0' && *ptr <= '9' ) ||
1048 (toupper(*ptr) >= ((int)('A')) && toupper(*ptr) <= ((int)'F') ) )
1049 )
1050 {
1051 total *= 16;
1052 if (*ptr >= '0' && *ptr <= '9' )
1053 total += (int)(*ptr - '0');
1054 else
1055 total += ( (toupper(*ptr) - 'A') + 10);
1056 ptr++;
1057 }
1058 }
1059 *retPtr = (char) total;
1060 retPtr++;
1061 }
1062 else
1063 {
1064 switch ( *ptr )
1065 {
1066 case 'a':
1067 *retPtr = '\a';
1068 retPtr++;
1069 /*@switchbreak@*/ break;
1070
1071 case 'b':
1072 *retPtr = '\b';
1073 retPtr++;
1074 /*@switchbreak@*/ break;
1075
1076 case 'f':
1077 *retPtr = '\f';
1078 retPtr++;
1079 /*@switchbreak@*/ break;
1080
1081 case 'n':
1082 *retPtr = '\n';
1083 retPtr++;
1084 /*@switchbreak@*/ break;
1085
1086 case 'r':
1087 *retPtr = '\r';
1088 retPtr++;
1089 /*@switchbreak@*/ break;
1090
1091 case 't':
1092 *retPtr = '\t';
1093 retPtr++;
1094 /*@switchbreak@*/ break;
1095 /* ' " ? \ */
1096 /* we assume invalid sequences are handled somewhere else
1097 so we handle an invalid sequence of the form \char by replacing
1098 it with char (this is what gcc does) the C standard says a diagnostic is
1099 required..*/
1100 default:
1101 *retPtr = *ptr;
1102 retPtr++;
1103 }
1104 ptr++;
1105 }
1106
1107 }/*end outer if*/
1108
1109 }/*end while */
1110
1111 /* add the null character */
1112 *retPtr = '\0';
1113
1114 llassert( (retPtr-ret) >= 0 );
1115 *len = (size_t)(retPtr - ret);
1116 return ret;
1117 }
1118
1119
1120 /*this function is like sctring_expandEscapses */
cstring_expandEscapes(cstring s)1121 mstring cstring_expandEscapes (cstring s)
1122 {
1123 size_t len;
1124
1125 mstring ret;
1126 ret = doExpandEscapes (s, &len);
1127 return ret;
1128 }
1129
cstring_lengthExpandEscapes(cstring s)1130 size_t cstring_lengthExpandEscapes (cstring s)
1131 {
1132 size_t len;
1133 mstring tmpStr, tmpStr2;
1134
1135 tmpStr = doMergeString (s);
1136 tmpStr2 = doExpandEscapes (tmpStr, &len);
1137
1138 cstring_free(tmpStr);
1139 cstring_free(tmpStr2);
1140
1141 return len;
1142 }
1143
cstring_replaceChar(cstring c,char oldChar,char newChar)1144 cstring cstring_replaceChar(/*@returned@*/ cstring c, char oldChar, char newChar)
1145 {
1146 char *ptr;
1147 llassert(oldChar != '\0');
1148 if (cstring_isUndefined(c) )
1149 {
1150 llcontbug(cstring_makeLiteral("cstring_replaceChar called with undefined string"));
1151 return c;
1152 }
1153
1154 ptr = c;
1155 while (*ptr != '\0')
1156 {
1157 if (*ptr == oldChar)
1158 *ptr = newChar;
1159 ptr++;
1160 }
1161
1162 return c;
1163 }
1164
1165
1166
1167
1168
1169
1170
1171
1172