Nicer handling of hand-generated files by build system
[splint-patched.git] / src / cstring.c
blobeeb5f2b89b497ee8b144cb68b3c7dc039dfe4e02
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.
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
25 ** cstring.c
29 * Herbert 06/12/2000
30 * - use drive spec specials with OS2 like with WIN32
31 * - cstring_replaceAll () needed in cpplib.c
34 # include "splintMacros.nf"
35 # include "basic.h"
36 # include "osd.h"
38 /*@only@*/ /*@notnull@*/
39 cstring cstring_newEmpty (void)
41 return (cstring_create (0));
44 char cstring_firstChar (cstring s)
46 llassert (cstring_isDefined (s));
47 llassert (cstring_length (s) > 0);
49 return (s[0]);
52 char cstring_getChar (cstring s, size_t n)
54 size_t length = cstring_length (s);
56 llassert (cstring_isDefined (s));
57 llassert (n >= 1 && n <= length);
59 return (s[n - 1]);
62 cstring cstring_suffix (cstring s, size_t n)
64 llassert (cstring_isDefined (s));
65 llassert (n <= cstring_length (s));
67 return (s + 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 @*/
74 cstring t;
75 char c;
76 llassert (cstring_isDefined (s));
77 llassert (n <= cstring_length (s));
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@*/
86 return t;
89 /* effects If s = [0-9]*, returns s as an int.
90 ** else returns -1.
93 int cstring_toPosInt (cstring s)
95 int val = 0;
97 cstring_chars (s, c)
99 if (isdigit ((unsigned char) c))
101 val = (val * 10) + (int)(c - '0');
103 else
105 return -1;
107 } end_cstring_chars ;
109 return val;
112 cstring cstring_afterChar (cstring s, char c)
114 llassert (cstring_isDefined (s));
115 return strchr (s, c);
118 cstring cstring_beforeChar (cstring s, char c)
120 if (cstring_isDefined (s))
122 char *cp = strchr (s, c);
124 if (cp != NULL)
126 cstring ret;
128 /*@-mods@*/
129 *cp = '\0';
130 ret = cstring_copy (s);
131 *cp = c;
132 /*@=mods@*/ /* modification is undone */
134 return ret;
138 return cstring_undefined;
141 void cstring_setChar (cstring s, size_t n, char c) /*@requires maxRead(s) >= (n - 1) /\ maxSet(s) >= (n - 1) @*/
143 llassert (cstring_isDefined (s));
144 llassert (n > 0 && n <= cstring_length (s));
146 s[n - 1] = c;
149 char cstring_lastChar (cstring s)
151 size_t length;
153 llassert (cstring_isDefined (s));
155 length = cstring_length (s);
156 llassert (length > 0);
158 return (s[length - 1]);
161 /*@only@*/ cstring cstring_copy (cstring s) /*@ensures maxSet(result) == maxRead(s) /\ maxRead(result) == maxRead(s) @*/
163 if (cstring_isDefined (s))
165 return (mstring_copy (s));
167 else
169 return cstring_undefined;
173 /*@only@*/ cstring cstring_copyLength (char *s, size_t len) /*@requires maxSet(s) >= (len - 1) @*/
175 char *res = mstring_create (len + 1);
177 strncpy (res, s, len);
178 res[len] = '\0';
179 return res;
182 bool cstring_containsChar (cstring c, char ch)
184 if (cstring_isDefined (c))
186 return (strchr (c, ch) != NULL);
188 else
190 return FALSE;
195 ** Replaces all occurances of old in s with new.
198 void cstring_replaceAll (cstring s, char old, char snew)
201 llassert (old != snew);
203 if (cstring_isDefined (s))
205 char *sp = strchr (s, old);
207 while (sp != NULL)
209 *sp = snew;
210 sp = strchr (sp, old);
216 void cstring_replaceLit (/*@unique@*/ cstring s, char *old, char *snew)
217 /*@requires maxRead(snew) >= 0 /\ maxRead(old) >= 0 /\ maxRead(old) >= maxRead(snew) @*/
219 llassert (strlen (old) >= strlen (snew));
221 if (cstring_isDefined (s))
223 char *sp = strstr (s, old);
225 while (sp != NULL)
227 int lendiff = size_toInt (strlen (old) - strlen (snew));
228 char *tsnew = snew;
230 llassert (lendiff >= 0);
232 while (*tsnew != '\0')
234 llassert (*sp != '\0');
235 *sp++ = *tsnew++;
238 if (lendiff > 0)
240 while (*(sp + lendiff) != '\0')
242 *sp = *(sp + lendiff);
243 sp++;
246 *sp = '\0';
249 sp = strstr (s, old);
255 ** removes all chars in clist from s
258 void cstring_stripChars (cstring s, const char *clist)
260 if (cstring_isDefined (s))
262 int i;
263 size_t size = cstring_length (s);
265 for (i = 0; i < size_toInt (size); i++)
268 char c = s[i];
270 if (strchr (clist, c) != NULL)
272 /* strip this char */
273 int j;
275 size--;
277 for (j = i; j < size_toInt (size); j++)
279 s[j] = s[j+1];
282 s[size] = '\0';
283 i--;
289 bool cstring_contains (/*@unique@*/ cstring c, cstring sub)
291 if (cstring_isDefined (c))
293 llassert (cstring_isDefined (sub));
295 return (strstr (c, sub) != NULL);
297 else
299 return FALSE;
303 static char lookLike (char c) /*@*/
305 if (c == 'I' || c == 'l')
307 return '1';
309 else if (c == 'O' || c == 'o')
311 return '0';
313 else if (c == 'Z')
315 return '2';
317 else if (c == 'S')
319 return '5';
321 else
323 return c;
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 @*/
333 if (s == t) return CGE_SAME;
334 else if (cstring_isUndefined (s))
336 return cstring_isEmpty (t) ? CGE_SAME : CGE_DISTINCT;
338 else if (cstring_isUndefined (t))
340 return cstring_isEmpty (s) ? CGE_SAME : CGE_DISTINCT;
342 else
344 int i = 0;
345 bool diffcase = FALSE;
346 bool difflookalike = FALSE;
348 while (*s != '\0')
350 if (nchars > 0 && i >= size_toInt (nchars))
352 break;
355 if (*t == *s)
357 ; /* no difference */
359 else if (caseinsensitive
360 && (toupper ((int) *t) == toupper ((int) *s)))
362 diffcase = TRUE;
364 else if (lookalike && (lookLike (*t) == lookLike (*s)))
366 difflookalike = TRUE;
368 else
370 return CGE_DISTINCT;
372 i++;
373 s++;
374 t++;
378 if (*s == '\0' && *t != '\0')
380 return CGE_DISTINCT;
383 if (diffcase)
385 return CGE_CASE;
387 else if (difflookalike)
389 return CGE_LOOKALIKE;
391 else
393 return CGE_SAME;
400 bool cstring_equalFree (/*@only@*/ cstring c1, /*@only@*/ cstring c2)
402 bool res = cstring_equal (c1, c2);
403 cstring_free (c1);
404 cstring_free (c2);
405 return res;
408 bool cstring_equal (cstring c1, cstring c2)
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);
416 bool cstring_equalLen (cstring c1, cstring c2, size_t len)
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);
424 bool cstring_equalCaseInsensitive (cstring c1, cstring c2)
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);
432 bool cstring_equalLenCaseInsensitive (cstring c1, cstring c2, size_t len)
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);
440 bool cstring_equalPrefix (cstring c1, cstring c2)
442 llassert (c2 != NULL);
444 if (cstring_isUndefined (c1))
446 return (strlen (c2) == 0);
449 return (strncmp (c1, c2, strlen (c2)) == 0);
452 bool cstring_equalPrefixLit (cstring c1, const char *c2)
454 llassert (c2 != NULL);
456 if (cstring_isUndefined (c1))
458 return (strlen (c2) == 0);
461 return (strncmp (c1, c2, strlen (c2)) == 0);
464 int cstring_xcompare (cstring *c1, cstring *c2)
466 return (cstring_compare (*c1, *c2));
469 int cstring_compare (cstring c1, cstring c2)
471 int res;
473 if (c1 == c2)
475 res = 0;
477 else if (cstring_isUndefined (c1))
479 if (cstring_isEmpty (c2))
481 res = 0;
483 else
485 res = 1;
488 else if (cstring_isUndefined (c2))
490 if (cstring_isEmpty (c1))
492 res = 0;
494 else
496 res = -1;
499 else
501 res = strcmp (c1, c2);
504 return (res);
507 void cstring_markOwned (/*@owned@*/ cstring s)
509 sfreeEventually (s);
512 void cstring_free (/*@only@*/ cstring s)
514 if (cstring_isDefined (s))
516 /*drl 2/3/2002*/
517 s[0] = '\0';
519 sfree (s);
523 cstring cstring_fromChars (/*@exposed@*/ const char *cp)
525 return (cstring) cp;
528 /*@exposed@*/ char *cstring_toCharsSafe (cstring s)
530 static /*@only@*/ cstring emptystring = cstring_undefined;
532 if (cstring_isDefined (s))
534 return (char *) s;
536 else
538 if (cstring_isUndefined (emptystring))
540 emptystring = cstring_newEmpty ();
543 return emptystring;
547 size_t cstring_length (cstring s)
549 if (cstring_isDefined (s))
551 return strlen (s);
554 return 0;
557 cstring
558 cstring_capitalize (cstring s) /*@requires maxSet(s) >= 0 @*/
560 if (!cstring_isEmpty (s))
562 cstring ret = cstring_copy (s);
564 cstring_setChar (ret, 1, (char) toupper ((int) cstring_firstChar (ret)));
565 return ret;
568 return cstring_undefined;
571 cstring
572 cstring_capitalizeFree (cstring s) /*@requires maxSet(s) >= 0 /\ maxRead(s) >= 0 @*/
574 if (!cstring_isEmpty (s))
576 cstring_setChar (s, 1, (char) toupper ((int) cstring_firstChar (s)));
577 return s;
580 return s;
583 cstring
584 cstring_clip (cstring s, size_t len)
586 if (cstring_isUndefined (s) || cstring_length (s) <= len)
590 else
592 llassert (s != NULL);
594 *(s + len) = '\0';
597 return s;
600 /*@only@*/ cstring
601 cstring_elide (cstring s, size_t len)
603 if (cstring_isUndefined (s) || cstring_length (s) <= len)
605 return cstring_copy (s);
607 else
609 cstring sc = cstring_create (len);
611 strncpy (sc, s, len);
613 *(sc + len - 1) = '\0';
614 *(sc + len - 2) = '.';
615 *(sc + len - 3) = '.';
616 *(sc + len - 4) = '.';
618 return sc;
622 /*@only@*/ cstring
623 cstring_fill (cstring s, size_t n) /*@requires n >= 0 @*/
625 cstring t = cstring_create (n + 1);
626 cstring ot = t;
627 size_t len = cstring_length (s);
628 size_t i;
630 if (len > n)
632 for (i = 0; i < n; i++)
635 *t++ = *s++;
637 *t = '\0';
639 else
641 for (i = 0; i < len; i++)
644 *t++ = *s++;
646 for (i = 0; i < n - len; i++)
649 *t++ = ' ';
651 *t = '\0';
654 return ot;
657 cstring
658 cstring_downcase (cstring s)
660 if (cstring_isDefined (s))
662 cstring t = cstring_create (strlen (s) + 1);
663 cstring ot = t;
664 char c;
666 while ((c = *s) != '\0')
668 if (c >= 'A' && c <= 'Z')
670 c = c - 'A' + 'a';
672 *t++ = c;
673 s++;
675 *t = '\0';
677 return ot;
679 else
681 return cstring_undefined;
685 /*@notnull@*/ cstring
686 cstring_appendChar (/*@only@*/ cstring s1, char c)
688 size_t l = cstring_length (s1);
689 char *s;
691 s = (char *) dmalloc (sizeof (*s) * (l + 2));
693 if (cstring_isDefined (s1))
695 strcpy (s, s1);
696 *(s + l) = c;
697 *(s + l + 1) = '\0';
698 sfree (s1);
700 else
702 *(s) = c;
703 *(s + 1) = '\0';
706 return s;
709 /*@only@*/ cstring
710 cstring_concatFree (cstring s, cstring t)
712 cstring res = cstring_concat (s, t);
713 cstring_free (s);
714 cstring_free (t);
715 return res;
718 /*@only@*/ cstring
719 cstring_concatFree1 (cstring s, cstring t)
721 cstring res = cstring_concat (s, t);
722 cstring_free (s);
723 return res;
726 /*@only@*/ cstring
727 cstring_concatChars (cstring s, char *t)
729 cstring res = cstring_concat (s, cstring_fromChars (t));
730 cstring_free (s);
731 return res;
734 /*@only@*/ cstring
735 cstring_concatLength (cstring s1, char *s2, size_t len) /*@requires maxSet(s2) >= (len - 1) @*/
737 cstring tmp = cstring_copyLength (s2, len);
738 cstring res = cstring_concat (s1, tmp);
739 cstring_free (tmp);
740 cstring_free (s1);
742 return res;
745 /*@only@*/ cstring
746 cstring_concat (cstring s, cstring t) /*@requires maxSet(s) >= 0 @*/
748 char *ret = mstring_create (cstring_length (s) + cstring_length (t));
750 if (cstring_isDefined (s))
752 strcpy (ret, s);
754 if (cstring_isDefined (t))
756 strcat (ret, t);
759 return ret;
762 /*@notnull@*/ /*@only@*/ cstring
763 cstring_prependCharO (char c, /*@only@*/ cstring s1)
765 cstring res = cstring_prependChar (c, s1);
767 cstring_free (s1);
768 return (res);
771 /*@notnull@*/ /*@only@*/ cstring
772 cstring_prependChar (char c, /*@temp@*/ cstring s1)
774 size_t l = cstring_length (s1);
775 char *s = (char *) dmalloc (sizeof (*s) * (l + 2));
777 *(s) = c;
779 if (cstring_isDefined (s1))
781 /*@-mayaliasunique@*/
782 strcpy (s + 1, s1);
783 /*@=mayaliasunique@*/
786 *(s + l + 1) = '\0';
787 return s;
790 bool
791 cstring_hasNonAlphaNumBar (cstring s)
793 int c;
795 if (cstring_isUndefined (s)) return FALSE;
797 while ((c = (int) *s) != (int) '\0')
799 if ((isalnum (c) == 0) && (c != (int) '_')
800 && (c != (int) '.') && (c != (int) CONNECTCHAR))
802 return TRUE;
805 s++;
807 return FALSE;
810 /*@only@*/ /*@notnull@*/ cstring
811 cstring_create (size_t n)
813 char *s = dmalloc (sizeof (*s) * (n + 1));
815 *s = '\0';
816 return s;
819 /*@only@*/ /*@notnull@*/ cstring
820 cstring_copySegment (cstring s, size_t findex, size_t tindex)
822 cstring res = cstring_create (tindex - findex + 1);
824 llassert (cstring_isDefined (s));
825 llassert (cstring_length (s) > tindex);
827 strncpy (res, (s + findex), size_fromInt (size_toInt (tindex - findex) + 1));
828 return res;
831 lsymbol cstring_toSymbol (cstring s)
833 lsymbol res = lsymbol_fromString (s);
835 cstring_free (s);
836 return res;
839 cstring cstring_bsearch (cstring key, char **table, int nentries)
841 if (cstring_isDefined (key))
843 int low = 0;
844 int high = nentries;
845 int mid = (high + low + 1) / 2;
846 int last = -1;
847 cstring res = cstring_undefined;
849 while (low <= high && mid < nentries)
851 int cmp;
853 llassert (mid != last);
854 llassert (mid >= 0 && mid < nentries);
856 cmp = cstring_compare (key, table[mid]);
858 if (cmp == 0)
860 res = table[mid];
861 break;
863 else if (cmp < 0) /* key is before table[mid] */
865 high = mid - 1;
867 else /* key of after table[mid] */
869 low = mid + 1;
872 last = mid;
873 mid = (high + low + 1) / 2;
876 if (mid != 0 && mid < nentries - 1)
878 llassert (cstring_compare (key, table[mid - 1]) > 0);
879 llassert (cstring_compare (key, table[mid + 1]) < 0);
882 return res;
885 return cstring_undefined;
888 extern /*@observer@*/ cstring cstring_advanceWhiteSpace (cstring s)
890 if (cstring_isDefined (s)) {
891 char *t = s;
893 while (*t != '\0' && isspace ((int) *t)) {
894 t++;
897 return t;
900 return cstring_undefined;
903 /* changes strings like "sdf" "sdfsd" into "sdfsdfsd"*/
904 /* This function understands that "sdf\" \"sdfsdf" is okay*/
905 static mstring doMergeString (cstring s)
907 char *ptr;
908 mstring ret;
909 char * retPtr;
910 bool escape;
912 llassert(cstring_isDefined (s));
914 ret = mstring_create (cstring_length(s) );
916 ptr = s;
918 retPtr = ret;
920 llassert(*ptr == '\"');
922 *retPtr = *ptr;
924 retPtr++;
925 ptr++;
928 while (*ptr != '\0')
930 escape = FALSE;
932 if (*ptr == '\\')
934 *retPtr = *ptr;
936 if (!escape)
937 escape = TRUE;
938 else
939 /* case of escaped \ ('\\') */
940 escape = FALSE;
942 else if ( (*ptr == '\"') && (!escape) )
944 while ( (ptr[1] != '\"') && (ptr[1] != '\0') )
946 ptr++;
948 if (ptr[1] == '\0')
950 llassert(*ptr == '\"');
951 *retPtr = '\"';
952 retPtr++;
953 *retPtr = '\0';
954 BADEXIT;
956 /*@notreached@*/ return ret;
958 else
960 ptr++;
963 else
965 *retPtr = *ptr;
968 retPtr++;
969 ptr++;
971 }/* end while */
972 *retPtr = '\0';
973 return ret;
976 static mstring doExpandEscapes (cstring s, /*@out@*/ size_t *len)
978 char *ptr;
979 mstring ret;
980 char * retPtr;
982 llassert(cstring_isDefined (s));
984 ret = mstring_create (cstring_length(s));
986 ptr = s;
988 retPtr = ret;
989 while (*ptr != '\0')
991 if (*ptr != '\\')
993 *retPtr = *ptr;
994 retPtr++;
995 ptr++;
996 continue;
999 if (*ptr == '\\')
1001 ptr++;
1002 if (*ptr == '\0')
1004 /*not a legal escape sequence but try to handle it in a sesible way*/
1005 *retPtr = '\\';
1006 retPtr++;
1009 /* Handle Octal escapes */
1010 else if (*ptr >= '0' && *ptr <= '9' )
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' ) )
1018 total *= 8;
1019 ptr++;
1020 if (*ptr != '\0' && (*ptr >= '0' && *ptr <= '9' ) )
1022 total *= 8;
1023 total += (int) (*ptr - '0');
1024 ptr++;
1028 *retPtr = (char) total;
1029 retPtr++;
1032 else if (*ptr == 'x')
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') ) )
1042 total = (int)'x';
1044 else
1046 while (*ptr != '\0' &&
1047 ( (*ptr >= '0' && *ptr <= '9' ) ||
1048 (toupper(*ptr) >= ((int)('A')) && toupper(*ptr) <= ((int)'F') ) )
1051 total *= 16;
1052 if (*ptr >= '0' && *ptr <= '9' )
1053 total += (int)(*ptr - '0');
1054 else
1055 total += ( (toupper(*ptr) - 'A') + 10);
1056 ptr++;
1059 *retPtr = (char) total;
1060 retPtr++;
1062 else
1064 switch ( *ptr )
1066 case 'a':
1067 *retPtr = '\a';
1068 retPtr++;
1069 /*@switchbreak@*/ break;
1071 case 'b':
1072 *retPtr = '\b';
1073 retPtr++;
1074 /*@switchbreak@*/ break;
1076 case 'f':
1077 *retPtr = '\f';
1078 retPtr++;
1079 /*@switchbreak@*/ break;
1081 case 'n':
1082 *retPtr = '\n';
1083 retPtr++;
1084 /*@switchbreak@*/ break;
1086 case 'r':
1087 *retPtr = '\r';
1088 retPtr++;
1089 /*@switchbreak@*/ break;
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++;
1104 ptr++;
1107 }/*end outer if*/
1109 }/*end while */
1111 /* add the null character */
1112 *retPtr = '\0';
1114 llassert( (retPtr-ret) >= 0 );
1115 *len = (size_t)(retPtr - ret);
1116 return ret;
1120 /*this function is like sctring_expandEscapses */
1121 mstring cstring_expandEscapes (cstring s)
1123 size_t len;
1125 mstring ret;
1126 ret = doExpandEscapes (s, &len);
1127 return ret;
1130 size_t cstring_lengthExpandEscapes (cstring s)
1132 size_t len;
1133 mstring tmpStr, tmpStr2;
1135 tmpStr = doMergeString (s);
1136 tmpStr2 = doExpandEscapes (tmpStr, &len);
1138 cstring_free(tmpStr);
1139 cstring_free(tmpStr2);
1141 return len;
1144 cstring cstring_replaceChar(/*@returned@*/ cstring c, char oldChar, char newChar)
1146 char *ptr;
1147 llassert(oldChar != '\0');
1148 if (cstring_isUndefined(c) )
1150 llcontbug(cstring_makeLiteral("cstring_replaceChar called with undefined string"));
1151 return c;
1154 ptr = c;
1155 while (*ptr != '\0')
1157 if (*ptr == oldChar)
1158 *ptr = newChar;
1159 ptr++;
1162 return c;