2 ** LCLint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2000 University of Virginia,
4 ** Massachusetts Institute of Technology
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.
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.
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 lclint: lclint-request@cs.virginia.edu
21 ** To report a bug: lclint-bug@cs.virginia.edu
22 ** For more information: http://lclint.cs.virginia.edu
30 * - use drive spec specials with OS2 like with WIN32
31 * - cstring_replaceAll () needed in cpplib.c
34 # include "lclintMacros.nf"
39 static /*@only@*/ /*@notnull@*/
40 cstring cstring_newEmpty (void)
42 return (cstring_create (0));
45 char cstring_firstChar (cstring s)
47 llassert (cstring_isDefined (s));
48 llassert (cstring_length (s) > 0);
53 char cstring_getChar (cstring s, int n)
55 int length = cstring_length (s);
57 llassert (cstring_isDefined (s));
58 llassert (n >= 1 && n <= length);
63 cstring cstring_suffix (cstring s, int n)
65 llassert (cstring_isDefined (s));
66 llassert (n <= cstring_length (s));
71 cstring cstring_prefix (cstring s, int n)
75 llassert (cstring_isDefined (s));
76 llassert (n <= cstring_length (s));
79 /*@-mods@*/ /* The modifications cancel out. */
88 /* effects If s = [0-9]*, returns s as an int.
92 int cstring_toPosInt (cstring s)
98 if (isdigit ((unsigned char) c))
100 val = (val * 10) + (int)(c - '0');
106 } end_cstring_chars ;
111 cstring cstring_beforeChar (cstring s, char c)
113 if (cstring_isDefined (s))
115 char *cp = strchr (s, c);
123 ret = cstring_copy (s);
125 /*@=mods@*/ /* modification is undone */
131 return cstring_undefined;
134 void cstring_setChar (cstring s, int n, char c)
136 llassert (cstring_isDefined (s));
137 llassert (n > 0 && n <= cstring_length (s));
142 char cstring_lastChar (cstring s)
146 llassert (cstring_isDefined (s));
148 length = cstring_length (s);
149 llassert (length > 0);
151 return (s[length - 1]);
154 /*@only@*/ cstring cstring_copy (cstring s)
156 if (cstring_isDefined (s))
158 return (mstring_copy (s));
162 return cstring_undefined;
166 /*@only@*/ cstring cstring_copyLength (char *s, int len)
168 char *res = mstring_create (len + 1);
170 strncpy (res, s, size_fromInt (len));
175 bool cstring_containsChar (cstring c, char ch)
177 if (cstring_isDefined (c))
179 return (strchr (c, ch) != NULL);
188 ** Replaces all occurances of old in s with new.
191 # if defined (WIN32) || defined (OS2)
192 void cstring_replaceAll (cstring s, char old, char snew)
195 llassert (old != snew);
197 if (cstring_isDefined (s))
199 char *sp = strchr (s, old);
204 sp = strchr (sp, old);
211 void cstring_replaceLit (/*@unique@*/ cstring s, char *old, char *snew)
214 llassert (strlen (old) >= strlen (snew));
216 if (cstring_isDefined (s))
218 char *sp = strstr (s, old);
222 int lendiff = size_toInt (strlen (old) - strlen (snew));
225 while (*tsnew != '\0')
232 while (*(sp + lendiff) != '\0')
234 *sp = *(sp + lendiff);
241 sp = strstr (s, old);
247 ** removes all chars in clist from s
250 void cstring_stripChars (cstring s, const char *clist)
252 if (cstring_isDefined (s))
255 int size = cstring_length (s);
257 for (i = 0; i < size; i++)
261 if (strchr (clist, c) != NULL)
263 /* strip this char */
268 for (j = i; j < size; j++)
280 bool cstring_contains (/*@unique@*/ cstring c, cstring sub)
282 if (cstring_isDefined (c))
284 llassert (cstring_isDefined (sub));
286 return (strstr (c, sub) != NULL);
294 static char lookLike (char c) /*@*/
296 if (c == 'I' || c == 'l')
300 else if (c == 'O' || c == 'o')
318 cmpcode cstring_genericEqual (cstring s, cstring t,
320 bool caseinsensitive,
323 if (s == t) return CGE_SAME;
324 else if (cstring_isUndefined (s))
326 return cstring_isEmpty (t) ? CGE_SAME : CGE_DISTINCT;
328 else if (cstring_isUndefined (t))
330 return cstring_isEmpty (s) ? CGE_SAME : CGE_DISTINCT;
335 bool diffcase = FALSE;
336 bool difflookalike = FALSE;
340 if (nchars > 0 && i >= nchars)
347 ; /* no difference */
349 else if (caseinsensitive
350 && (toupper ((int) *t) == toupper ((int) *s)))
354 else if (lookalike && (lookLike (*t) == lookLike (*s)))
356 difflookalike = TRUE;
367 if (*s == '\0' && *t != '\0')
376 else if (difflookalike)
378 return CGE_LOOKALIKE;
389 bool cstring_equalFree (/*@only@*/ cstring c1, /*@only@*/ cstring c2)
391 bool res = cstring_equal (c1, c2);
397 bool cstring_equal (cstring c1, cstring c2)
399 if (c1 == c2) return TRUE;
400 else if (cstring_isUndefined (c1)) return cstring_isEmpty (c2);
401 else if (cstring_isUndefined (c2)) return cstring_isEmpty (c1);
402 else return (strcmp (c1, c2) == 0);
405 bool cstring_equalLen (cstring c1, cstring c2, int len)
407 if (c1 == c2) return TRUE;
408 else if (cstring_isUndefined (c1)) return cstring_isEmpty (c2);
409 else if (cstring_isUndefined (c2)) return cstring_isEmpty (c1);
410 else return (strncmp (c1, c2, size_fromInt (len)) == 0);
413 bool cstring_equalCaseInsensitive (cstring c1, cstring c2)
415 if (c1 == c2) return TRUE;
416 else if (cstring_isUndefined (c1)) return cstring_isEmpty (c2);
417 else if (cstring_isUndefined (c2)) return cstring_isEmpty (c1);
418 else return (cstring_genericEqual (c1, c2, 0, TRUE, FALSE) != CGE_DISTINCT);
421 bool cstring_equalLenCaseInsensitive (cstring c1, cstring c2, int len)
425 if (c1 == c2) return TRUE;
426 else if (cstring_isUndefined (c1)) return cstring_isEmpty (c2);
427 else if (cstring_isUndefined (c2)) return cstring_isEmpty (c1);
428 else return (cstring_genericEqual (c1, c2, len, TRUE, FALSE) != CGE_DISTINCT);
431 bool cstring_equalPrefix (cstring c1, char *c2)
433 llassert (c2 != NULL);
435 if (cstring_isUndefined (c1))
437 return (strlen (c2) == 0);
440 return (strncmp (c1, c2, strlen (c2)) == 0);
443 bool cstring_equalCanonicalPrefix (cstring c1, char *c2)
445 llassert (c2 != NULL);
447 if (cstring_isUndefined (c1))
449 return (strlen (c2) == 0);
452 # if defined (WIN32) || defined (OS2)
454 ** If one has a drive specification, but the other doesn't, skip it.
457 if (strchr (c1, ':') == NULL
458 && strchr (c2, ':') != NULL)
460 c2 = strchr (c2 + 1, ':');
464 if (strchr (c2, ':') == NULL
465 && strchr (c1, ':') != NULL)
467 c1 = strchr (c1 + 1, ':');
472 int len = size_toInt (strlen (c2));
476 if (cstring_length (c1) < len)
481 for (i = 0; i < len; i++)
483 if (c1[slen] == c2[i]
484 || (osd_isConnectChar (c1[slen]) && osd_isConnectChar (c2[i])))
491 ** We allow \\ to match \ because MS-DOS screws up the directory
497 && c1[slen - 1] == '\\'
498 && c2[i - 1] == '\\'))
501 if (c1[slen] != c2[i])
513 if (slen >= cstring_length (c1))
522 return (strncmp (c1, c2, strlen (c2)) == 0);
526 int cstring_xcompare (cstring *c1, cstring *c2)
528 return (cstring_compare (*c1, *c2));
531 int cstring_compare (cstring c1, cstring c2)
539 else if (cstring_isUndefined (c1))
541 if (cstring_isEmpty (c2))
550 else if (cstring_isUndefined (c2))
552 if (cstring_isEmpty (c1))
563 res = strcmp (c1, c2);
569 void cstring_markOwned (/*@owned@*/ cstring s)
574 void cstring_free (/*@only@*/ cstring s)
576 if (cstring_isDefined (s))
582 cstring cstring_fromChars (/*@exposed@*/ const char *cp)
587 /*@exposed@*/ char *cstring_toCharsSafe (cstring s)
589 static /*@only@*/ cstring emptystring = cstring_undefined;
591 if (cstring_isDefined (s))
597 if (cstring_isUndefined (emptystring))
599 emptystring = cstring_newEmpty ();
606 int cstring_length (cstring s)
608 if (cstring_isDefined (s))
610 return size_toInt (strlen (s));
616 cstring_capitalize (cstring s)
618 if (!cstring_isEmpty (s))
620 cstring ret = cstring_copy (s);
622 cstring_setChar (ret, 1, (char) toupper ((int) cstring_firstChar (ret)));
626 return cstring_undefined;
630 cstring_capitalizeFree (cstring s)
632 if (!cstring_isEmpty (s))
634 cstring_setChar (s, 1, (char) toupper ((int) cstring_firstChar (s)));
642 cstring_clip (cstring s, int len)
644 if (cstring_isUndefined (s) || cstring_length (s) <= len)
650 llassert (s != NULL);
658 cstring_elide (cstring s, int len)
660 if (cstring_isUndefined (s) || cstring_length (s) <= len)
662 return cstring_copy (s);
666 cstring sc = cstring_create (len);
668 strncpy (sc, s, size_fromInt (len));
669 *(sc + len - 1) = '\0';
670 *(sc + len - 2) = '.';
671 *(sc + len - 3) = '.';
672 *(sc + len - 4) = '.';
678 cstring_fill (cstring s, int n)
680 cstring t = cstring_create (n + 1);
682 int len = cstring_length (s);
687 for (i = 0; i < n; i++)
695 for (i = 0; i < len; i++)
699 for (i = 0; i < n - len; i++)
710 cstring_downcase (cstring s)
712 if (cstring_isDefined (s))
714 cstring t = cstring_create (strlen (s) + 1);
718 while ((c = *s) != '\0')
720 if (c >= 'A' && c <= 'Z')
733 return cstring_undefined;
737 /*@notnull@*/ cstring
738 cstring_appendChar (/*@only@*/ cstring s1, char c)
740 int l = cstring_length (s1);
743 s = (char *) dmalloc (sizeof (*s) * (l + 2));
745 if (cstring_isDefined (s1))
762 cstring_concatFree (cstring s, cstring t)
764 cstring res = cstring_concat (s, t);
771 cstring_concatFree1 (cstring s, cstring t)
773 cstring res = cstring_concat (s, t);
780 cstring_concatChars (cstring s, char *t)
782 cstring res = cstring_concat (s, cstring_fromChars (t));
789 cstring_concatLength (cstring s1, char *s2, int len)
791 cstring tmp = cstring_copyLength (s2, len);
792 cstring res = cstring_concat (s1, tmp);
800 cstring_concat (cstring s, cstring t)
802 char *ret = mstring_create (cstring_length (s) + cstring_length (t));
804 if (cstring_isDefined (s))
808 if (cstring_isDefined (t))
816 /*@notnull@*/ /*@only@*/ cstring
817 cstring_prependCharO (char c, /*@only@*/ cstring s1)
819 cstring res = cstring_prependChar (c, s1);
825 /*@notnull@*/ /*@only@*/ cstring
826 cstring_prependChar (char c, /*@temp@*/ cstring s1)
828 int l = cstring_length (s1);
829 char *s = (char *) dmalloc (sizeof (*s) * (l + 2));
833 if (cstring_isDefined (s1))
835 /*@-mayaliasunique@*/
837 /*@=mayaliasunique@*/
846 cstring_hasNonAlphaNumBar (cstring s)
850 if (cstring_isUndefined (s)) return FALSE;
852 while ((c = (int) *s) != (int) '\0')
854 if ((isalnum (c) == 0) && (c != (int) '_')
855 && (c != (int) '.') && (c != (int) CONNECTCHAR))
866 /*@only@*/ /*@notnull@*/ cstring
867 cstring_create (int n)
869 char *s = dmalloc (sizeof (*s) * (n + 1));
876 lsymbol cstring_toSymbol (cstring s)
878 lsymbol res = lsymbol_fromChars (cstring_toCharsSafe (s));
885 cstring cstring_bsearch (cstring key, char **table, int nentries)
887 if (cstring_isDefined (key))
891 int mid = (high + low + 1) / 2;
893 cstring res = cstring_undefined;
895 while (low <= high && mid < nentries)
899 llassert (mid != last);
900 llassert (mid >= 0 && mid < nentries);
902 cmp = cstring_compare (key, table[mid]);
909 else if (cmp < 0) /* key is before table[mid] */
913 else /* key of after table[mid] */
919 mid = (high + low + 1) / 2;
922 if (mid != 0 && mid < nentries - 1)
924 llassert (cstring_compare (key, table[mid - 1]) > 0);
925 llassert (cstring_compare (key, table[mid + 1]) < 0);
931 return cstring_undefined;
934 extern /*@observer@*/ cstring cstring_advanceWhiteSpace (cstring s)
936 if (cstring_isDefined (s)) {
939 while (*t != '\0' && isspace ((int) *t)) {
946 return cstring_undefined;