]> andersk Git - splint.git/blame - src/cstring.c
Added check of user specified post conditions.
[splint.git] / src / cstring.c
CommitLineData
616915dd 1/*
2** LCLint - annotation-assisted static program checker
3** Copyright (C) 1994-2000 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 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
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 "lclintMacros.nf"
35# include "basic.h"
36# include "osd.h"
37# include "portab.h"
38
39static /*@only@*/ /*@notnull@*/
40cstring cstring_newEmpty (void)
41{
42 return (cstring_create (0));
43}
44
45char cstring_firstChar (cstring s)
46{
47 llassert (cstring_isDefined (s));
48 llassert (cstring_length (s) > 0);
49
50 return (s[0]);
51}
52
53char cstring_getChar (cstring s, int n)
54{
55 int length = cstring_length (s);
56
57 llassert (cstring_isDefined (s));
58 llassert (n >= 1 && n <= length);
59
60 return (s[n - 1]);
61}
62
63cstring cstring_suffix (cstring s, int n)
64{
65 llassert (cstring_isDefined (s));
66 llassert (n <= cstring_length (s));
67
68 return (s + n);
69}
70
71cstring cstring_prefix (cstring s, int n)
72{
73 cstring t;
74 char c;
75 llassert (cstring_isDefined (s));
76 llassert (n <= cstring_length (s));
77
78 c = *(s + n);
79 /*@-mods@*/ /* The modifications cancel out. */
80 *(s + n) = '\0';
81 t = cstring_copy (s);
82 *(s + n) = c;
83 /*@=mods@*/
84
85 return t;
86}
87
88/* effects If s = [0-9]*, returns s as an int.
89** else returns -1.
90*/
91
92int cstring_toPosInt (cstring s)
93{
94 int val = 0;
95
96 cstring_chars (s, c)
97 {
98 if (isdigit ((unsigned char) c))
99 {
100 val = (val * 10) + (int)(c - '0');
101 }
102 else
103 {
104 return -1;
105 }
106 } end_cstring_chars ;
107
108 return val;
109}
110
111cstring cstring_beforeChar (cstring s, char c)
112{
113 if (cstring_isDefined (s))
114 {
115 char *cp = strchr (s, c);
116
117 if (cp != NULL)
118 {
119 cstring ret;
120
121 /*@-mods@*/
122 *cp = '\0';
123 ret = cstring_copy (s);
124 *cp = c;
125 /*@=mods@*/ /* modification is undone */
126
127 return ret;
128 }
129 }
130
131 return cstring_undefined;
132}
133
134void cstring_setChar (cstring s, int n, char c)
135{
136 llassert (cstring_isDefined (s));
137 llassert (n > 0 && n <= cstring_length (s));
138
139 s[n - 1] = c;
140}
141
142char cstring_lastChar (cstring s)
143{
144 int length;
145
146 llassert (cstring_isDefined (s));
147
148 length = cstring_length (s);
149 llassert (length > 0);
150
151 return (s[length - 1]);
152}
153
154/*@only@*/ cstring cstring_copy (cstring s)
155{
156 if (cstring_isDefined (s))
157 {
158 return (mstring_copy (s));
159 }
160 else
161 {
162 return cstring_undefined;
163 }
164}
165
166/*@only@*/ cstring cstring_copyLength (char *s, int len)
167{
168 char *res = mstring_create (len + 1);
169
170 strncpy (res, s, size_fromInt (len));
171 res[len] = '\0';
172 return res;
173}
174
175bool cstring_containsChar (cstring c, char ch)
176{
177 if (cstring_isDefined (c))
178 {
179 return (strchr (c, ch) != NULL);
180 }
181 else
182 {
183 return FALSE;
184 }
185}
186
187/*
188** Replaces all occurances of old in s with new.
189*/
190
191# if defined (WIN32) || defined (OS2)
192void cstring_replaceAll (cstring s, char old, char snew)
193{
194
195 llassert (old != snew);
196
197 if (cstring_isDefined (s))
198 {
199 char *sp = strchr (s, old);
200
201 while (sp != NULL)
202 {
203 *sp = snew;
204 sp = strchr (sp, old);
205 }
206
207 }
208}
209# endif
210
211void cstring_replaceLit (/*@unique@*/ cstring s, char *old, char *snew)
212{
213
214 llassert (strlen (old) >= strlen (snew));
215
216 if (cstring_isDefined (s))
217 {
218 char *sp = strstr (s, old);
219
220 while (sp != NULL)
221 {
222 int lendiff = size_toInt (strlen (old) - strlen (snew));
223 char *tsnew = snew;
224
225 while (*tsnew != '\0')
226 {
227 *sp++ = *tsnew++;
228 }
229
230 if (lendiff > 0)
231 {
232 while (*(sp + lendiff) != '\0')
233 {
234 *sp = *(sp + lendiff);
235 sp++;
236 }
237
238 *sp = '\0';
239 }
240
241 sp = strstr (s, old);
242 }
243 }
244}
245
246/*
247** removes all chars in clist from s
248*/
249
250void cstring_stripChars (cstring s, const char *clist)
251{
252 if (cstring_isDefined (s))
253 {
254 int i;
255 int size = cstring_length (s);
256
257 for (i = 0; i < size; i++)
258 {
259 char c = s[i];
260
261 if (strchr (clist, c) != NULL)
262 {
263 /* strip this char */
264 int j;
265
266 size--;
267
268 for (j = i; j < size; j++)
269 {
270 s[j] = s[j+1];
271 }
272
273 s[size] = '\0';
274 i--;
275 }
276 }
277 }
278}
279
280bool cstring_contains (/*@unique@*/ cstring c, cstring sub)
281{
282 if (cstring_isDefined (c))
283 {
284 llassert (cstring_isDefined (sub));
285
286 return (strstr (c, sub) != NULL);
287 }
288 else
289 {
290 return FALSE;
291 }
292}
293
294static char lookLike (char c) /*@*/
295{
296 if (c == 'I' || c == 'l')
297 {
298 return '1';
299 }
300 else if (c == 'O' || c == 'o')
301 {
302 return '0';
303 }
304 else if (c == 'Z')
305 {
306 return '2';
307 }
308 else if (c == 'S')
309 {
310 return '5';
311 }
312 else
313 {
314 return c;
315 }
316}
317
318cmpcode cstring_genericEqual (cstring s, cstring t,
319 int nchars,
320 bool caseinsensitive,
321 bool lookalike)
322{
323 if (s == t) return CGE_SAME;
324 else if (cstring_isUndefined (s))
325 {
326 return cstring_isEmpty (t) ? CGE_SAME : CGE_DISTINCT;
327 }
328 else if (cstring_isUndefined (t))
329 {
330 return cstring_isEmpty (s) ? CGE_SAME : CGE_DISTINCT;
331 }
332 else
333 {
334 int i = 0;
335 bool diffcase = FALSE;
336 bool difflookalike = FALSE;
337
338 while (*s != '\0')
339 {
340 if (nchars > 0 && i >= nchars)
341 {
342 break;
343 }
344
345 if (*t == *s)
346 {
347 ; /* no difference */
348 }
349 else if (caseinsensitive
350 && (toupper ((int) *t) == toupper ((int) *s)))
351 {
352 diffcase = TRUE;
353 }
354 else if (lookalike && (lookLike (*t) == lookLike (*s)))
355 {
356 difflookalike = TRUE;
357 }
358 else
359 {
360 return CGE_DISTINCT;
361 }
362 i++;
363 s++;
364 t++;
365 }
366
367 if (*s == '\0' && *t != '\0')
368 {
369 return CGE_DISTINCT;
370 }
371
372 if (diffcase)
373 {
374 return CGE_CASE;
375 }
376 else if (difflookalike)
377 {
378 return CGE_LOOKALIKE;
379 }
380 else
381 {
382 return CGE_SAME;
383 }
384 }
385}
386
387
388
389bool cstring_equalFree (/*@only@*/ cstring c1, /*@only@*/ cstring c2)
390{
391 bool res = cstring_equal (c1, c2);
392 cstring_free (c1);
393 cstring_free (c2);
394 return res;
395}
396
397bool cstring_equal (cstring c1, cstring c2)
398{
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);
403}
404
405bool cstring_equalLen (cstring c1, cstring c2, int len)
406{
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);
411}
412
413bool cstring_equalCaseInsensitive (cstring c1, cstring c2)
414{
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);
419}
420
421bool cstring_equalLenCaseInsensitive (cstring c1, cstring c2, int len)
422{
423 llassert (len >= 0);
424
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);
429}
430
431bool cstring_equalPrefix (cstring c1, char *c2)
432{
433 llassert (c2 != NULL);
434
435 if (cstring_isUndefined (c1))
436 {
437 return (strlen (c2) == 0);
438 }
439
440 return (strncmp (c1, c2, strlen (c2)) == 0);
441}
442
443bool cstring_equalCanonicalPrefix (cstring c1, char *c2)
444{
445 llassert (c2 != NULL);
446
447 if (cstring_isUndefined (c1))
448 {
449 return (strlen (c2) == 0);
450 }
451
452# if defined (WIN32) || defined (OS2)
453 /*
454 ** If one has a drive specification, but the other doesn't, skip it.
455 */
456
457 if (strchr (c1, ':') == NULL
458 && strchr (c2, ':') != NULL)
459 {
460 c2 = strchr (c2 + 1, ':');
461 }
462 else
463 {
464 if (strchr (c2, ':') == NULL
465 && strchr (c1, ':') != NULL)
466 {
467 c1 = strchr (c1 + 1, ':');
468 }
469 }
470
471 {
472 int len = size_toInt (strlen (c2));
473 int i = 0;
474 int slen = 0;
475
476 if (cstring_length (c1) < len)
477 {
478 return FALSE;
479 }
480
481 for (i = 0; i < len; i++)
482 {
483 if (c1[slen] == c2[i]
484 || (osd_isConnectChar (c1[slen]) && osd_isConnectChar (c2[i])))
485 {
486 ;
487 }
488 else
489 {
490 /*
491 ** We allow \\ to match \ because MS-DOS screws up the directory
492 ** names.
493 */
494
495 if (c1[slen] == '\\'
496 && (slen > 0
497 && c1[slen - 1] == '\\'
498 && c2[i - 1] == '\\'))
499 {
500 slen++;
501 if (c1[slen] != c2[i])
502 {
503 return FALSE;
504 }
505 }
506 else
507 {
508 return FALSE;
509 }
510 }
511
512 slen++;
513 if (slen >= cstring_length (c1))
514 {
515 return FALSE;
516 }
517 }
518 }
519
520 return TRUE;
521# else
522 return (strncmp (c1, c2, strlen (c2)) == 0);
523# endif
524}
525
526int cstring_xcompare (cstring *c1, cstring *c2)
527{
528 return (cstring_compare (*c1, *c2));
529}
530
531int cstring_compare (cstring c1, cstring c2)
532{
533 int res;
534
535 if (c1 == c2)
536 {
537 res = 0;
538 }
539 else if (cstring_isUndefined (c1))
540 {
541 if (cstring_isEmpty (c2))
542 {
543 res = 0;
544 }
545 else
546 {
547 res = 1;
548 }
549 }
550 else if (cstring_isUndefined (c2))
551 {
552 if (cstring_isEmpty (c1))
553 {
554 res = 0;
555 }
556 else
557 {
558 res = -1;
559 }
560 }
561 else
562 {
563 res = strcmp (c1, c2);
564 }
565
566 return (res);
567}
568
569void cstring_markOwned (/*@owned@*/ cstring s)
570{
571 sfreeEventually (s);
572}
573
574void cstring_free (/*@only@*/ cstring s)
575{
576 if (cstring_isDefined (s))
577 {
578 sfree (s);
579 }
580}
581
582cstring cstring_fromChars (/*@exposed@*/ const char *cp)
583{
584 return (cstring) cp;
585}
586
587/*@exposed@*/ char *cstring_toCharsSafe (cstring s)
588{
589 static /*@only@*/ cstring emptystring = cstring_undefined;
590
591 if (cstring_isDefined (s))
592 {
593 return (char *) s;
594 }
595 else
596 {
597 if (cstring_isUndefined (emptystring))
598 {
599 emptystring = cstring_newEmpty ();
600 }
601
602 return emptystring;
603 }
604}
605
606int cstring_length (cstring s)
607{
608 if (cstring_isDefined (s))
609 {
610 return size_toInt (strlen (s));
611 }
612 return 0;
613}
614
615cstring
616cstring_capitalize (cstring s)
617{
618 if (!cstring_isEmpty (s))
619 {
620 cstring ret = cstring_copy (s);
621
622 cstring_setChar (ret, 1, (char) toupper ((int) cstring_firstChar (ret)));
623 return ret;
624 }
625
626 return cstring_undefined;
627}
628
629cstring
630cstring_capitalizeFree (cstring s)
631{
632 if (!cstring_isEmpty (s))
633 {
634 cstring_setChar (s, 1, (char) toupper ((int) cstring_firstChar (s)));
635 return s;
636 }
637
638 return s;
639}
640
641cstring
642cstring_clip (cstring s, int len)
643{
644 if (cstring_isUndefined (s) || cstring_length (s) <= len)
645 {
646 ;
647 }
648 else
649 {
650 llassert (s != NULL);
651 *(s + len) = '\0';
652 }
653
654 return s;
655}
656
657/*@only@*/ cstring
658cstring_elide (cstring s, int len)
659{
660 if (cstring_isUndefined (s) || cstring_length (s) <= len)
661 {
662 return cstring_copy (s);
663 }
664 else
665 {
666 cstring sc = cstring_create (len);
667
668 strncpy (sc, s, size_fromInt (len));
669 *(sc + len - 1) = '\0';
670 *(sc + len - 2) = '.';
671 *(sc + len - 3) = '.';
672 *(sc + len - 4) = '.';
673 return sc;
674 }
675}
676
677/*@only@*/ cstring
678cstring_fill (cstring s, int n)
679{
680 cstring t = cstring_create (n + 1);
681 cstring ot = t;
682 int len = cstring_length (s);
683 int i;
684
685 if (len > n)
686 {
687 for (i = 0; i < n; i++)
688 {
689 *t++ = *s++;
690 }
691 *t = '\0';
692 }
693 else
694 {
695 for (i = 0; i < len; i++)
696 {
697 *t++ = *s++;
698 }
699 for (i = 0; i < n - len; i++)
700 {
701 *t++ = ' ';
702 }
703 *t = '\0';
704 }
705
706 return ot;
707}
708
709cstring
710cstring_downcase (cstring s)
711{
712 if (cstring_isDefined (s))
713 {
714 cstring t = cstring_create (strlen (s) + 1);
715 cstring ot = t;
716 char c;
717
718 while ((c = *s) != '\0')
719 {
720 if (c >= 'A' && c <= 'Z')
721 {
722 c = c - 'A' + 'a';
723 }
724 *t++ = c;
725 s++;
726 }
727 *t = '\0';
728
729 return ot;
730 }
731 else
732 {
733 return cstring_undefined;
734 }
735}
736
737/*@notnull@*/ cstring
738cstring_appendChar (/*@only@*/ cstring s1, char c)
739{
740 int l = cstring_length (s1);
741 char *s;
742
743 s = (char *) dmalloc (sizeof (*s) * (l + 2));
744
745 if (cstring_isDefined (s1))
746 {
747 strcpy (s, s1);
748 *(s + l) = c;
749 *(s + l + 1) = '\0';
750 sfree (s1);
751 }
752 else
753 {
754 *(s) = c;
755 *(s + 1) = '\0';
756 }
757
758 return s;
759}
760
761/*@only@*/ cstring
762cstring_concatFree (cstring s, cstring t)
763{
764 cstring res = cstring_concat (s, t);
765 cstring_free (s);
766 cstring_free (t);
767 return res;
768}
769
770/*@only@*/ cstring
771cstring_concatFree1 (cstring s, cstring t)
772{
773 cstring res = cstring_concat (s, t);
774 cstring_free (s);
775 return res;
776}
777
778# ifndef NOLCL
779/*@only@*/ cstring
780cstring_concatChars (cstring s, char *t)
781{
782 cstring res = cstring_concat (s, cstring_fromChars (t));
783 cstring_free (s);
784 return res;
785}
786# endif
787
788/*@only@*/ cstring
789cstring_concatLength (cstring s1, char *s2, int len)
790{
791 cstring tmp = cstring_copyLength (s2, len);
792 cstring res = cstring_concat (s1, tmp);
793 cstring_free (tmp);
794 cstring_free (s1);
795
796 return res;
797}
798
799/*@only@*/ cstring
800cstring_concat (cstring s, cstring t)
801{
802 char *ret = mstring_create (cstring_length (s) + cstring_length (t));
803
804 if (cstring_isDefined (s))
805 {
806 strcpy (ret, s);
807 }
808 if (cstring_isDefined (t))
809 {
810 strcat (ret, t);
811 }
812
813 return ret;
814}
815
816/*@notnull@*/ /*@only@*/ cstring
817cstring_prependCharO (char c, /*@only@*/ cstring s1)
818{
819 cstring res = cstring_prependChar (c, s1);
820
821 cstring_free (s1);
822 return (res);
823}
824
825/*@notnull@*/ /*@only@*/ cstring
826cstring_prependChar (char c, /*@temp@*/ cstring s1)
827{
828 int l = cstring_length (s1);
829 char *s = (char *) dmalloc (sizeof (*s) * (l + 2));
830
831 *(s) = c;
832
833 if (cstring_isDefined (s1))
834 {
835 /*@-mayaliasunique@*/
836 strcpy (s + 1, s1);
837 /*@=mayaliasunique@*/
838 }
839
840 *(s + l + 1) = '\0';
841 return s;
842}
843
844# ifndef NOLCL
845bool
846cstring_hasNonAlphaNumBar (cstring s)
847{
848 int c;
849
850 if (cstring_isUndefined (s)) return FALSE;
851
852 while ((c = (int) *s) != (int) '\0')
853 {
854 if ((isalnum (c) == 0) && (c != (int) '_')
855 && (c != (int) '.') && (c != (int) CONNECTCHAR))
856 {
857 return TRUE;
858 }
859
860 s++;
861 }
862 return FALSE;
863}
864# endif
865
866/*@only@*/ /*@notnull@*/ cstring
867cstring_create (int n)
868{
869 char *s = dmalloc (sizeof (*s) * (n + 1));
870
871 *s = '\0';
872 return s;
873}
874
875# ifndef NOLCL
876lsymbol cstring_toSymbol (cstring s)
877{
878 lsymbol res = lsymbol_fromChars (cstring_toCharsSafe (s));
879
880 cstring_free (s);
881 return res;
882}
883# endif
884
885cstring cstring_bsearch (cstring key, char **table, int nentries)
886{
887 if (cstring_isDefined (key))
888 {
889 int low = 0;
890 int high = nentries;
891 int mid = (high + low + 1) / 2;
892 int last = -1;
893 cstring res = cstring_undefined;
894
895 while (low <= high && mid < nentries)
896 {
897 int cmp;
898
899 llassert (mid != last);
900 llassert (mid >= 0 && mid < nentries);
901
902 cmp = cstring_compare (key, table[mid]);
903
904 if (cmp == 0)
905 {
906 res = table[mid];
907 break;
908 }
909 else if (cmp < 0) /* key is before table[mid] */
910 {
911 high = mid - 1;
912 }
913 else /* key of after table[mid] */
914 {
915 low = mid + 1;
916 }
917
918 last = mid;
919 mid = (high + low + 1) / 2;
920 }
921
922 if (mid != 0 && mid < nentries - 1)
923 {
924 llassert (cstring_compare (key, table[mid - 1]) > 0);
925 llassert (cstring_compare (key, table[mid + 1]) < 0);
926 }
927
928 return res;
929 }
930
931 return cstring_undefined;
932}
933
934extern /*@observer@*/ cstring cstring_advanceWhiteSpace (cstring s)
935{
936 if (cstring_isDefined (s)) {
937 char *t = s;
938
939 while (*t != '\0' && isspace ((int) *t)) {
940 t++;
941 }
942
943 return t;
944 }
945
946 return cstring_undefined;
947}
948
949
950
This page took 0.829894 seconds and 5 git commands to generate.