]> andersk Git - splint.git/blob - src/cstring.c
commitng to fix cvs archive. Code works with gcc272 but not 295. Currently passed...
[splint.git] / src / cstring.c
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
39 static /*@only@*/ /*@notnull@*/ 
40 cstring cstring_newEmpty (void)
41 {
42   return (cstring_create (0));
43 }
44
45 char cstring_firstChar (cstring s) 
46 {
47   llassert (cstring_isDefined (s));
48   llassert (cstring_length (s) > 0);
49
50   return (s[0]);
51 }
52
53 char 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
63 cstring 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
71 cstring 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
92 int 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
111 cstring 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
134 void 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
142 char 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
175 bool 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)
192 void 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
211 void 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
250 void 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
280 bool 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
294 static 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
318 cmpcode 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
389 bool 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
397 bool 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
405 bool 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
413 bool 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
421 bool 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
431 bool 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
443 bool 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
526 int cstring_xcompare (cstring *c1, cstring *c2)
527 {
528   return (cstring_compare (*c1, *c2));
529 }
530
531 int 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
569 void cstring_markOwned (/*@owned@*/ cstring s)
570 {
571   sfreeEventually (s);
572 }
573
574 void cstring_free (/*@only@*/ cstring s)
575 {
576   if (cstring_isDefined (s)) 
577     {
578       sfree (s);
579     }
580 }
581
582 cstring 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
606 int cstring_length (cstring s)
607 {
608   if (cstring_isDefined (s))
609     {
610       return size_toInt (strlen (s));
611     }
612   return 0;
613 }
614
615 cstring
616 cstring_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
629 cstring
630 cstring_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
641 cstring
642 cstring_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
658 cstring_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
678 cstring_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
709 cstring
710 cstring_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 
738 cstring_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 
762 cstring_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 
771 cstring_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 
780 cstring_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 
789 cstring_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 
800 cstring_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 
817 cstring_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 
826 cstring_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
845 bool
846 cstring_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 
867 cstring_create (int n)
868 {
869   char *s = dmalloc (sizeof (*s) * (n + 1));
870
871   *s = '\0';
872   return s;
873 }
874
875 # ifndef NOLCL
876 lsymbol 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
885 cstring 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
934 extern /*@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.135247 seconds and 5 git commands to generate.