]> andersk Git - splint.git/blob - src/flags.c
Renamed lclintMacros.nf splintMacros.nf
[splint.git] / src / flags.c
1 /*
2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2002 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: splint@cs.virginia.edu
21 ** To report a bug: splint-bug@cs.virginia.edu
22 ** For more information: http://www.splint.org
23 */
24 /*
25 ** flags.c
26 */
27
28 # include "splintMacros.nf"
29 # include "basic.h"
30 # include "portab.h"
31
32 /*
33 ** from the CC man page:
34 **
35 **  -Idir          Search for #include files whose names do not begin with a
36 **                    slash (/) in the following order: (1) in the directory of
37 **                    the dir argument, (2) in the directories specified by -I
38 **                    options, (3) in the standard directory (/usr/include).
39 */
40
41 /* needed for string literals literals */
42
43 typedef struct { 
44   flagkind kind;
45   /*@null@*/ /*@observer@*/ char *name;
46   /*@null@*/ /*@observer@*/ char *describe;
47 } flagcatinfo;
48
49 static flagcatinfo categories[] =
50 {
51   { FK_ABSTRACT, "abstract", "abstraction violations, representation access" } ,
52   { FK_ALIAS, "aliasing", "unexpected or dangerous aliasing" } ,
53   { FK_USE, "alluse", "all declarations are used" } ,
54   { FK_ANSI, "ansi", "violations of constraints imposed by ANSI/ISO standard" } ,
55   { FK_ARRAY, "arrays", "special checking involving arrays" } ,
56   { FK_BOOL, "booleans", "checking and naming of boolean types" } ,
57   { FK_COMMENTS, "comments", "warnings about (normal) comments" } ,
58   { FK_SYNCOMMENTS, "syncomments", "interpretation of annotation comments" } ,
59   { FK_COMPLETE, "complete", "completely defined, used, or specified system" } ,
60   { FK_CONTROL, "controlflow", "suspicious control structures" } ,
61   { FK_DEBUG, "debug", "flags for debugging splint" } ,
62   { FK_DECL, "declarations", "consistency of declarations" } ,
63   { FK_DEF, "definition", "undefined storage errors" } ,
64   { FK_DIRECT, "directories", "set directores" } ,
65   { FK_DISPLAY, "display", "control what is displayed" } ,
66   { FK_EFFECT, "effect", "statements with no effects" } ,
67   { FK_ERRORS, "errors", "control expected errors, summary reporting" } ,
68   { FK_EXPORT, "export", "control what may be exported" } ,
69   { FK_EXPOSURE, "exposure", "representation exposure" } ,
70   { FK_EXTENSIBLE, "extensible", "user-defined checks and annotations" },
71   { FK_FILES, "files", "control system files" } ,
72   { FK_FORMAT, "format", "control format of warning messages" } ,
73   { FK_GLOBALS, "globals", "use of global and file static variables" },
74   { FK_HEADERS, "headers", "control inclusion and generation of header files" },
75   { FK_HELP, "help", "on-line help" },
76   { FK_BOUNDS, "memorybounds", "out-of-bounds memory accesses" },
77   { FK_HINTS, "hints", "control display of warning hints" },
78   { FK_SYSTEMFUNCTIONS, "systemfunctions", "special properties of exit and main" },
79   { FK_IMPLICIT, "implicit", "control implicit annotations and interpretations" } ,
80   { FK_INIT, "initializations", "initialization files" } ,
81   { FK_ITER, "iterators", "checking iterator definitions and uses" } ,
82   { FK_LEAK, "leaks", "memory leaks" } ,
83   { FK_LIBS, "libraries", "loading and dumping of user and standard libraries" } ,
84   { FK_LIMITS, "limits", "violations of set limits" } ,
85   { FK_MACROS, "macros", "expansion, definition and use of macros" },
86   { FK_MEMORY, "memory", "memory management" } ,
87   { FK_MODIFIES, "modification", "modification errors" } ,
88   { FK_NAMES, "names", "naming conventions and limits" } ,
89   { FK_NULL, "null", "misuses of null pointers" } ,
90   { FK_NUMBERS, "numbers", "control type-checking of numeric types" } ,
91   { FK_OPS, "operations", "checking of primitive operations" } ,
92   { FK_PARAMS, "parameters", "function and macro parameters" } ,
93   { FK_SPEED, "performance", "speeding up checking" } ,
94   { FK_POINTER, "pointers", "pointers" } ,
95   { FK_PRED, "predicates", "condition test expressions" } ,
96   { FK_PREFIX, "prefixes", "set naming prefixes and control checking" } ,
97   { FK_PREPROC, "preproc", "defines and undefines for the preprocessor" } ,
98   { FK_PROTOS, "prototypes", "function prototypes" } ,
99   { FK_DEAD, "released", "using storage that has been deallocated" } ,
100   { FK_IGNORERET, "returnvals", "ignored return values" },
101   { FK_SECURITY, "security", "possible security vulnerability" },
102   { FK_SPEC, "specifications", "checks involving .lcl specifications" } ,
103   { FK_SUPPRESS, "suppress", "local and global suppression of messages" } ,
104   { FK_TYPEEQ, "typeequivalence", "control what types are equivalent" } ,
105   { FK_BEHAVIOR, "undefined", "code with undefined or implementation-defined behavior" } ,
106   { FK_UNRECOG, "unrecognized", "unrecognized identifiers" } ,
107   { FK_UNSPEC, "unconstrained", "checking in the presence of unconstrained functions" } ,
108   { FK_WARNUSE, "warnuse", "use of possibly problematic function" } ,
109   { FK_ITS4, "its4", "its4 compatibility flags (report warnings for uses of possibly insecure functions)" } ,
110   { FK_SYNTAX, NULL, NULL } ,
111   { FK_TYPE, NULL, NULL } ,
112   { FK_SECRET, NULL, NULL } ,
113   { FK_OBSOLETE, NULL, NULL } ,
114   { FK_NONE, NULL, NULL }  /* must be last */
115 } ; 
116
117 typedef enum {
118   ARG_NONE,
119   ARG_NUMBER,    /* number */
120   ARG_CHAR,      /* char */
121   ARG_STRING,    /* string */
122   ARG_FILE,      /* filename (also a string) */
123   ARG_DIRECTORY, /* directory (also a string) */
124   ARG_PATH,      /* path */
125   ARG_SPECIAL   /* ? */
126 } argcode;
127
128 static /*@observer@*/ cstring argcode_unparse (argcode arg)
129 {
130   switch (arg) 
131     {
132     case ARG_STRING: return cstring_makeLiteralTemp ("string"); 
133     case ARG_FILE: return cstring_makeLiteralTemp ("filename"); 
134     case ARG_DIRECTORY: return cstring_makeLiteralTemp ("directory");
135     case ARG_PATH: return cstring_makeLiteralTemp ("path"); 
136     case ARG_NUMBER: return cstring_makeLiteralTemp ("number");
137     case ARG_CHAR: return cstring_makeLiteralTemp ("character");
138     case ARG_NONE: 
139       BADBRANCH;
140     case ARG_SPECIAL:
141       BADBRANCH;
142     }
143 }      
144
145 typedef struct { 
146   flagkind main;
147   flagkind sub;
148   bool isSpecial;  /* setting this flag may set other flags (or values) */
149   bool isIdem;     /* idempotent - always sets to TRUE */
150   bool isGlobal;   /* cannot be set locally (using control comments) */
151   bool isModeFlag; /* set by modes */
152   argcode argtype;
153   /*@observer@*/ char *flag;
154   flagcode code; 
155   /*@observer@*/ /*@null@*/ char *desc;
156   bn_mstring hint; 
157   int nreported; 
158   int nsuppressed; 
159 } fflag;
160
161 typedef fflag flaglist[];
162
163 # include "flags.def"
164
165 /*@iter allFlags (yield observer fflag f); @*/
166 # define allFlags(m_f) \
167   { /*@+enumint@*/ flagcode m_i; for (m_i = 0; m_i < NUMFLAGS; m_i++) { fflag m_f = flags[m_i]; /*@=enumint@*/
168 # define end_allFlags }}
169
170 static bn_mstring mode_names[] =
171
172   "weak", "standard", "checks", "strict", NULL, 
173 };
174
175 /*@iter allModes (yield bn_mstring modename)@*/
176 # define allModes(m_m) \
177   { int m_ii = 0; while (mstring_isDefined (mode_names[m_ii])) \
178       { bn_mstring m_m = mode_names[m_ii]; m_ii++; 
179
180 # define end_allModes }}
181
182 /*@+enumint@*/
183
184 static cstring getFlagModeSettings (flagcode p_flag) /*@modifies internalState@*/ ;
185 static cstring describeFlagCode (flagcode p_flag) /*@*/ ;
186 static cstringSList sortedFlags (void) /*@*/ ;
187 static /*@observer@*/ cstring categoryName (flagkind p_kind) /*@*/ ;
188
189 static flagcode flags_identifyFlagAux (cstring p_s, bool p_quiet) /*@modifies g_msgstream@*/ ;
190
191 # if 0
192 static /*@unused@*/ cstring listModes (void) /*@*/ ;
193 # endif
194
195 bool flagcode_isSpecialFlag (flagcode f)
196 {
197   return (flags[f].isSpecial);
198 }
199
200 bool flagcode_isGlobalFlag (flagcode f)
201 {
202   return (flags[f].isGlobal);
203 }
204
205 bool flagcode_isIdemFlag (flagcode f)
206 {
207   return (flags[f].isIdem);
208 }
209
210 bool flagcode_isModeFlag (flagcode f)
211 {
212   return (flags[f].isModeFlag);
213 }
214
215 bool flagcode_isNameChecksFlag (flagcode f)
216 {
217   return (flags[f].main == FK_NAMES);
218 }
219
220 /*
221 ** Internal consistency check on the flags.
222 */
223
224 void flags_initMod ()
225 {
226   allFlagCodes (code)
227     {
228       /*@+enumint@*/
229       if (flags[code].code != code)
230         {
231           fprintf (stderr, 
232                    "*** ERROR: inconsistent flag %s / %d / %d", 
233                    flags[code].flag,
234                    flags[code].code, code);
235           
236           llbug (message ("*** ERROR: inconsistent flag %s / %d / %d", 
237                           cstring_fromChars (flags[code].flag),
238                           flags[code].code, code));
239         }
240       /*@=enumint@*/
241     } end_allFlagCodes;
242 }
243
244 void
245 summarizeErrors ()
246 {
247   bool hadOne = FALSE;
248   int sumrep = 0;
249   int sumsup = 0;
250
251   char *buf = mstring_create (128);
252
253   allFlags (f)
254     {
255       if (f.nreported > 0 || f.nsuppressed > 0)
256         {
257           int nrep = f.nreported;
258           int nsup = f.nsuppressed;
259           cstring fs = cstring_fill (cstring_fromChars (f.flag), 23);
260
261           if (!hadOne)
262             {
263               llmsgplain (cstring_makeLiteral
264                           ("\nError Type                Reported  Suppressed\n"
265                            "===================       ========  ========="));
266               hadOne = TRUE;
267             }
268
269           sprintf (buf, "%s%7d   %9d", cstring_toCharsSafe (fs), nrep, nsup);
270
271           sumrep += nrep;
272           sumsup += nsup;
273           
274           cstring_free (fs);
275           llmsg (cstring_copy (cstring_fromChars (buf)));
276         }
277     } end_allFlags;
278
279   if (hadOne)
280     {
281       cstring ts = cstring_fill (cstring_makeLiteralTemp ("Total"), 23);
282
283       llmsglit ("                          ========  =========");
284
285       sprintf (buf, "%s%7d   %9d", cstring_toCharsSafe (ts), sumrep, sumsup);
286       cstring_free (ts);
287       llmsgplain (cstring_copy (cstring_fromChars (buf)));
288     }
289
290   sfree (buf);
291 }
292
293 /*@+enumindex@*/
294
295 void
296 flagcode_recordError (flagcode f)
297 {
298   if (f != INVALID_FLAG)
299     {
300       if (f == FLG_WARNFLAGS)
301         {
302           ; /* don't count these */
303         }
304       else
305         {
306           flags[f].nreported = flags[f].nreported + 1;
307         }
308     }
309   else
310     {
311       llcontbug (message ("flagcode_recordError: invalid flag: %d", (int) f));
312     }
313 }
314
315 void
316 flagcode_recordSuppressed (flagcode f)
317 {
318   llassertprint (f != INVALID_FLAG, ("flagcode: %s", flagcode_unparse (f)));
319
320   flags[f].nsuppressed = flags[f].nsuppressed + 1;
321 }
322
323 int
324 flagcode_numReported (flagcode f)
325 {
326   llassert (f != INVALID_FLAG);
327
328   return (flags[f].nreported);
329 }
330
331 /*@observer@*/ cstring
332 flagcodeHint (flagcode f)
333 {
334   llassert (f != INVALID_FLAG);
335
336   if (mstring_isDefined (flags[f].hint))
337     {
338       return (cstring_fromChars (flags[f].hint));
339     }
340   else
341     {
342       return (cstring_fromChars (flags[f].desc));
343     }
344 }
345
346 static int categorySize (flagkind kind) /*@*/ 
347 {
348   int n = 0;
349
350   
351   allFlags (f)
352     {
353       if (f.main == kind || f.sub == kind)
354         {
355                   n++;
356         }
357     } end_allFlags;
358
359   return n;
360 }
361
362 flagkind identifyCategory (cstring s)
363 {
364   int i;
365
366   for (i = 0; categories[i].kind != FK_NONE; i++)
367     {
368       if (mstring_isDefined (categories[i].name))
369         {
370           if (cstring_equalLit (s, categories[i].name))
371             {
372               return categories[i].kind;
373             }
374         }
375     }
376
377   return FK_NONE;
378 }
379
380 static /*@observer@*/ cstring categoryName (flagkind kind)
381 {
382   int i;
383
384   for (i = 0; categories[i].kind != FK_NONE; i++)
385     {
386       if (categories[i].kind == kind)
387         {
388           return (cstring_fromChars (categories[i].name));
389         }
390     }
391   
392   return (cstring_makeLiteralTemp ("<No Category>"));
393 }
394
395 static int categoryIndex (flagkind kind)
396 {
397   int i;
398
399   for (i = 0; categories[i].kind != FK_NONE; i++)
400     {
401       if (categories[i].kind == kind)
402         {
403           return i;
404         }
405     }
406
407   return -1;
408 }
409
410 void printCategory (flagkind kind)
411 {
412   int index = categoryIndex (kind);
413
414   llassert (index >= 0);
415
416   llmsg (message ("%s (%d flags)\n\3%s\n\n", 
417                   cstring_fromChars (categories[index].name), 
418                   categorySize (kind),
419                   cstring_fromChars (categories[index].describe)));
420
421   allFlags (f)
422     {
423       if (f.main == kind || f.sub == kind)
424         {
425           llmsg (message ("   %s\n\6%q", cstring_fromChars (f.flag), 
426                           describeFlagCode (f.code)));
427         }
428     } end_allFlags;
429 }
430
431 void 
432 listAllCategories (void)
433 {
434   int i;
435
436   for (i = 0; categories[i].kind != FK_NONE; i++)
437     {
438       flagkind kind = categories[i].kind ;
439
440       if (categories[i].describe != NULL)
441         {
442           llmsg (message ("%s (%d flags)\n\3%s", 
443                           categoryName (kind), 
444                           categorySize (kind),
445                           cstring_fromChars (categories[i].describe)));
446         }
447     }
448 }
449
450 void
451 printAllFlags (bool desc, bool full)
452 {
453   if (full)
454     {
455       cstringSList fl = sortedFlags ();
456
457       cstringSList_elements (fl, el)
458         {
459           llmsg (message ("%q\n\n", describeFlag (el)));
460         } end_cstringSList_elements ;
461
462       cstringSList_free (fl);
463     }
464   else
465     {
466       allFlags (f)
467         {
468           if (f.code != INVALID_FLAG && f.main != FK_OBSOLETE)
469             {
470               if (mstring_isDefined (f.desc))
471                 {
472                   if (desc)
473                     {
474                       llmsg (message ("%s --- %s", cstring_fromChars (f.flag),
475                                       cstring_fromChars (f.desc)));
476                     }
477                 }
478             }
479         } end_allFlags;
480     }
481 }
482
483 void
484 printFlagManual (void)
485 {
486   /*
487   ** Prints all flags by category, in order they appear in flags.def
488   */
489
490   flagkind lastCategory = FK_NONE;
491
492   allFlags (f) {
493     cstring flagname;
494     cstring flagtype = cstring_undefined;
495
496     if (f.main != lastCategory)
497       {
498         llmsg (message ("\n%s\n%s\n",
499                         categoryName (f.main),
500                         cstring_makeLiteralTemp ("===================================")));
501
502         lastCategory = f.main;
503       }
504
505     if (f.argtype == ARG_NONE || f.argtype == ARG_SPECIAL)
506       {
507         flagname = cstring_fromCharsNew (f.flag);
508       }
509     else
510       {
511         if (flagcode_hasString (f.code)) 
512           {
513             flagname = message ("%s <%s>", cstring_fromChars (f.flag), argcode_unparse (f.argtype));
514
515             if (cstring_isDefined (context_getString (f.code)))
516               {
517                 flagname = message ("%q [%s]", flagname,
518                                     context_getString (f.code));
519               }
520           }
521         else if (f.argtype == ARG_CHAR)
522           {
523             flagname = message ("%s <%s> [%c]", cstring_fromChars (f.flag), argcode_unparse (f.argtype),
524                                 (char) context_getValue (f.code));
525           }
526         else 
527           {
528             llassert (f.argtype == ARG_NUMBER);
529             flagname = message ("%s <%s> [%d]", cstring_fromChars (f.flag), argcode_unparse (f.argtype),
530                                 context_getValue (f.code));
531           }
532       }
533
534     if (f.isIdem)
535       {
536         flagtype = message("%q<->", flagtype);
537       }
538     
539     if (f.isGlobal)
540       {
541         flagtype = message ("%q<G>", flagtype);
542       }
543
544     if (f.isSpecial)
545       {
546         flagtype = message("%q<S>", flagtype);
547       }
548     
549     if (f.isModeFlag)
550       {
551         flagtype = message ("%q<M:%q>", flagtype, getFlagModeSettings (f.code));
552       }
553     else /* its a plain flag */
554       {
555         flagtype = message ("%q<P:%s>", flagtype,
556                             cstring_makeLiteralTemp (context_getFlag (f.code) ? "+" : "-"));
557       }
558     
559     llmsg (message ("%s: %s", flagname, flagtype));
560
561     if (mstring_isDefined (f.hint))
562       {
563         llgenindentmsgnoloc (cstring_fromCharsNew (f.hint));
564       }
565     else
566       {
567         llgenindentmsgnoloc (message ("%q.", cstring_capitalize (cstring_fromChars (f.desc))));
568       }
569   } end_allFlags ;
570 }
571
572 cstring
573 describeFlagCode (flagcode flag)
574 {
575   cstring ret = cstring_undefined;
576   fflag f;
577   
578   if (flagcode_isInvalid (flag))
579     {
580       return (cstring_makeLiteral ("<invalid>"));
581     }
582
583   context_resetAllFlags ();
584   
585   f = flags[flag];
586   ret = cstring_copy (cstring_fromChars (f.desc));
587   
588   if (f.sub != FK_NONE)
589     {
590       ret = message ("%q\nCategories: %s, %s",
591                      ret, 
592                      categoryName (f.main),
593                      categoryName (f.sub));
594     }
595   else 
596     {
597       if (f.main != FK_NONE)
598         {
599           cstring cname = categoryName (f.main);
600           
601           if (cstring_isDefined (cname))
602             {
603               ret = message ("%q\nCategory: %s",
604                              ret, cname);
605             }
606         }
607     }
608   
609   if (f.isModeFlag)
610     {
611       ret = message ("%q\nMode Settings: %q",
612                      ret, getFlagModeSettings (flag));
613     }
614   else
615     {
616       ret = message ("%q\nDefault Setting: %s",
617                      ret, 
618                      cstring_makeLiteralTemp (context_getFlag (flag) ? "+" : "-"));
619     }
620   
621   if (f.isGlobal)
622     {
623       ret = message("%q\nSet globally only", ret);
624     }
625   else
626     {
627       ret = message("%q\nSet locally", ret);
628     }
629   
630   switch (f.argtype)
631     {
632     case ARG_NONE:
633     case ARG_SPECIAL:
634       break;
635     case ARG_NUMBER:
636       ret = message("%q\nNumeric Argument.  Default: %d",
637                     ret,
638                     context_getValue (flag));
639       break;
640     case ARG_CHAR:
641       ret = message("%q\nCharacter Argument.  Default: %h",
642                     ret, (char) context_getValue (flag));
643       break;
644     case ARG_STRING:
645     case ARG_FILE:
646     case ARG_PATH:
647     case ARG_DIRECTORY:
648       {
649       if (cstring_isDefined (context_getString (flag)))
650         {
651           ret = message("%q\n%q argument.  Default: %s",
652                         ret,
653                         cstring_capitalize (argcode_unparse (f.argtype)),
654                         context_getString (flag));
655         }
656       else
657         {
658           ret = message("%q\n%s argument.  No default.", 
659                         ret,
660                         cstring_capitalize (argcode_unparse (f.argtype)));
661         }
662       break;
663       }
664     }
665   
666   if (mstring_isDefined (f.hint))
667     {
668       ret = message("%q\n\3%s", ret, cstring_fromChars (f.hint));
669     }
670   
671   return ret;
672 }
673   
674 static cstring getFlagModeSettings (flagcode flag)
675 {
676   cstring res = cstring_undefined;
677   
678   allModes (mname)
679     {
680       context_setModeNoWarn (cstring_fromChars (mname));
681       
682       res = message ("%q%s", res, cstring_makeLiteralTemp (context_getFlag (flag) ? "+" : "-"));
683     } end_allModes;
684
685   return res;
686 }
687
688 cstring
689 describeFlag (cstring flagname)
690 {
691   cstring oflagname = cstring_copy (flagname);
692   flagcode f = flags_identifyFlag (flagname);
693
694   if (flagcode_isSkip (f))
695     {
696       cstring_free (oflagname);
697       return cstring_undefined;
698     }
699   else if (flagcode_isValid (f))
700     {
701       if (cstring_equal (flagname, oflagname))
702         {
703           cstring_free (oflagname);
704           return (message ("%s\n\3%q", flagname, describeFlagCode (f)));
705         }
706       else
707         {
708           return (message ("%q (standardized name: %s)\n\3%q",
709                            oflagname, flagname, describeFlagCode (f)));
710         }
711     }
712   else
713     {
714       if (isMode (flagname))
715         {
716           cstring_free (oflagname);
717
718           return
719             (message ("%s: predefined mode (see Manual for information)",
720                       flagname));
721         }
722       else
723         {
724           return (message ("%q: <invalid flag>", oflagname));
725         }
726     }
727 }
728
729 static cstringSList
730 sortedFlags (void)
731 {
732   cstringSList s = cstringSList_new ();
733
734   allFlags (f)
735     {
736       if (f.desc != NULL)
737         {
738           s = cstringSList_add (s, cstring_fromChars (f.flag));
739         }
740     } end_allFlags;
741
742   cstringSList_alphabetize (s);
743
744   return s;
745 }
746
747 void printAlphaFlags ()
748 {
749   cstringSList fl = sortedFlags ();
750
751   cstringSList_printSpaced (fl, 3, 1, context_getLineLen () - 25); 
752   cstringSList_free (fl);
753 }
754
755 /*@observer@*/ cstring
756 flagcode_unparse (flagcode code)
757 {
758   if (code == INVALID_FLAG)
759     {
760       return cstring_makeLiteralTemp ("<invalid flag>");
761     }
762
763   return cstring_fromChars (flags[code].flag);
764 }
765
766 /*
767 ** Transforms a flag into its cannonical form.
768 **
769 ** The following transformations are made:
770 **
771 **    function      -> fcn
772 **    variable      -> var
773 **    constant      -> const
774 **    iterator      -> iter
775 **    parameter     -> param
776 **    unrecognized  -> unrecog
777 **    qualifier     -> qual         
778 **    declaration   -> decl
779 **    globalias     -> (no change)
780 **    global        -> glob
781 **    modifies      -> mods
782 **    modify        -> mod
783 **    pointer       -> ptr
784 **    implies       -> imp
785 **    implicit      -> imp
786 **    implied       -> imp
787 **    unconstrained -> unspec       
788 **    unconst       -> unspec
789 **    memory        -> mem
790 **    length        -> len
791 */
792
793 static void
794 canonicalizeFlag (cstring s)
795 {
796   int i = 0;
797   static bn_mstring transform[] = 
798     { 
799       "function", "fcn",
800       "variable", "var",
801       "constant", "const",
802       "iterator", "iter",
803       "parameter", "param",
804       "unrecognized", "unrecog",
805       "qualifier", "qual",
806       "declaration", "decl",
807       "globals", "globs", 
808       "modifies", "mods", 
809       "modify", "mod",
810       "pointer", "ptr",
811       "implies", "imp",
812       "implicit", "imp",
813       "implied", "imp",
814       "unconstrained", "uncon",
815       "unconst", "uncon",
816       "memory", "mem",
817       "length", "len",
818       "return", "ret",
819       "system", "sys",
820       NULL
821       } ;
822   char *current;
823
824   while ((current = transform[i]) != NULL)
825     {
826       if (cstring_containsLit (s, current))
827         {
828           cstring_replaceLit (s, current, transform[i+1]);
829         }
830       i += 2;
831     }
832
833   /* remove whitespace, -'s, and _'s */
834   cstring_stripChars (s, " -_");
835 }
836
837 flagcode
838 flags_identifyFlag (cstring s)
839 {
840   return flags_identifyFlagAux (s, FALSE);
841 }
842
843 flagcode
844 flags_identifyFlagQuiet (cstring s)
845 {
846   return flags_identifyFlagAux (s, TRUE);
847 }
848
849 static flagcode
850 flags_identifyFlagAux (cstring s, bool quiet)
851 {
852   if (cstring_length (s) == 0) {
853     /* evs 2000-06-25: A malformed flag. */
854     return INVALID_FLAG;
855   }
856
857   if (cstring_firstChar (s) == 'I')
858     {
859       return FLG_INCLUDEPATH; /* no space after -I */
860     }
861
862   if (cstring_firstChar (s) == 'S') 
863     {
864       return FLG_SPECPATH;    /* no space after -S */
865     }
866
867   if (cstring_firstChar (s) == 'D') 
868     {
869       return FLG_DEFINE;      /* no space after -D */
870     }
871
872   if (cstring_firstChar (s) == 'U') 
873     {
874       return FLG_UNDEFINE;    /* no space after -D */
875     }
876
877   canonicalizeFlag (s);
878
879   allFlags (f)
880     {
881       if (cstring_equal (cstring_fromChars (f.flag), s))
882         {
883           return (f.code);
884         }
885     } end_allFlags;
886
887   /*
888   ** Synonyms
889   */
890
891   if (cstring_equalLit (s, "pred"))
892     {
893       return FLG_PREDBOOL;
894     }
895
896   if (cstring_equalLit (s, "modobserverstrict"))
897     {
898       return FLG_MODOBSERVERUNCON;
899     }
900
901   if (cstring_equalLit (s, "czechnames"))
902     {
903       return FLG_CZECH;
904     }
905
906   if (cstring_equalLit (s, "slovaknames"))
907     {
908       return FLG_SLOVAK;
909     }
910
911   if (cstring_equalLit (s, "czechoslovaknames"))
912     {
913       return FLG_CZECHOSLOVAK;
914     }
915
916   if (cstring_equalLit (s, "globunspec")
917            || cstring_equalLit (s, "globuncon"))
918     {
919       return FLG_GLOBUNSPEC;
920     }
921
922   if (cstring_equalLit (s, "modglobsunspec")
923            || cstring_equalLit (s, "modglobsuncon")
924            || cstring_equalLit (s, "modglobsnomods"))
925     {
926       return FLG_MODGLOBSUNSPEC;
927     }
928
929   if (cstring_equalLit (s, "export"))
930     {
931       return FLG_EXPORTANY;
932     }
933
934   if (cstring_equalLit (s, "macrospec"))
935     {
936       return FLG_MACRODECL;
937     }
938   
939   if (cstring_equalLit (s, "ansireservedlocal"))
940     {
941       return FLG_ANSIRESERVEDLOCAL;
942     }
943
944   if (cstring_equalLit (s, "warnposix"))
945     {
946       return FLG_WARNPOSIX;
947     }
948
949   if (cstring_equalLit (s, "defuse"))
950     {
951       return FLG_USEDEF;
952     }
953
954   if (cstring_equalLit (s, "macroundef"))
955     {
956       return FLG_MACROUNDEF;
957     }
958
959   if (cstring_equalLit (s, "showcol"))
960     {
961       return FLG_SHOWCOL;
962     }
963
964   if (cstring_equalLit (s, "intbool"))
965     {
966       return FLG_BOOLINT;
967     }
968
969   if (cstring_equalLit (s, "intchar"))
970     {
971       return FLG_CHARINT;
972     }
973
974   if (cstring_equalLit (s, "intenum"))
975     {
976       return FLG_ENUMINT;
977     }
978
979   /*
980   ** Backwards compatibility for our American friends...
981   */
982
983   if (cstring_equalLit (s, "ansilib"))
984     {
985       return FLG_ANSILIB;
986     }
987
988   if (cstring_equalLit (s, "ansistrictlib"))
989     {
990       return FLG_STRICTLIB;
991     }
992
993   if (cstring_equalLit (s, "skipansiheaders"))
994     {
995       return FLG_SKIPANSIHEADERS;
996     }
997
998   if (cstring_equalLit (s, "ansireserved"))
999     {
1000       return FLG_ANSIRESERVED;
1001     }
1002
1003   if (cstring_equalLit (s, "ansireservedinternal"))
1004     {
1005       return FLG_ANSIRESERVEDLOCAL;
1006     }
1007
1008   /*
1009   ** Obsolete Flags
1010   */
1011   
1012   if (cstring_equalLit (s, "accessunspec"))
1013     {
1014       if (!quiet) 
1015         {
1016           llerror_flagWarning 
1017             (cstring_makeLiteral
1018              ("accessunspec flag is no longer supported.  It has been replaced by accessmodule, accessfile and "
1019               "accessfunction to provide more precise control of accessibility "
1020               "of representations.  For more information, "
1021               "see splint -help accessmodule"));
1022         }
1023       
1024       return SKIP_FLAG;
1025     }
1026   else if (cstring_equalLit (s, "ansilimits"))
1027     {
1028           llerror_flagWarning 
1029             (cstring_makeLiteral
1030              ("ansilimits flag is no longer supported.  It has been replaced by ansi89limits and "
1031               "iso99limits to select either the lower translation limits imposed by the ANSI89 "
1032               "standard or the typically higher limits prescribed by ISO C99."));
1033
1034       return SKIP_FLAG;
1035     }
1036   else if (cstring_equalLit (s, "staticmods"))
1037     {
1038       if (!quiet) 
1039         {
1040           llerror_flagWarning 
1041             (cstring_makeLiteral
1042              ("staticmods flag is obsolete.  You probably "
1043               "want impcheckmodstatics.  For more information, "
1044               "see splint -help impcheckmodstatics"));
1045         }
1046
1047       return SKIP_FLAG;
1048     }
1049   else if (cstring_equalLit (s, "bool"))
1050     {
1051       if (!quiet) 
1052         {
1053           llerror_flagWarning
1054             (cstring_makeLiteral ("bool flag is obsolete.  It never really "
1055                                   "made sense in the first place."));
1056         }
1057       
1058       return SKIP_FLAG;
1059     }
1060   else if (cstring_equalLit (s, "shiftsigned"))
1061     {
1062       if (!quiet) 
1063         {
1064           llerror_flagWarning
1065             (cstring_makeLiteral ("shiftsigned flag is obsolete.  You probably "
1066                                   "want bitwisesigned, shiftnegative or shiftsize."));
1067         }
1068       
1069       return SKIP_FLAG;
1070     }
1071   else if (cstring_equalLit (s, "ansi"))
1072     {
1073       if (!quiet) 
1074         {
1075           llerror_flagWarning
1076             (cstring_makeLiteral ("ansi flag is obsolete.  You probably "
1077                                   "want noparams and/or oldstyle."));
1078         }
1079       
1080       return SKIP_FLAG;
1081     }
1082   else if (cstring_equalLit (s, "stdio"))
1083     {
1084       if (!quiet) 
1085         {
1086           llerror_flagWarning 
1087             (cstring_makeLiteral
1088              ("stdio flag is obsolete.  You may "
1089               "want strictlib or one of the gloabls "
1090               "checking flags.  For more information, "
1091               "see splint -help strictlib or splint -help flags globals"));
1092         }
1093       
1094       return SKIP_FLAG;
1095     }
1096   else
1097     {
1098       return INVALID_FLAG;
1099     }
1100 }
1101
1102 void setValueFlag (flagcode opt, cstring arg)
1103 {
1104   switch (opt)
1105     {
1106     case FLG_EXPECT:
1107     case FLG_LCLEXPECT:
1108     case FLG_LIMIT:  
1109     case FLG_LINELEN:
1110     case FLG_INDENTSPACES:
1111     case FLG_BUGSLIMIT:
1112     case FLG_EXTERNALNAMELEN:
1113     case FLG_INTERNALNAMELEN:
1114     case FLG_CONTROLNESTDEPTH:
1115     case FLG_STRINGLITERALLEN:
1116     case FLG_NUMSTRUCTFIELDS:
1117     case FLG_NUMENUMMEMBERS:
1118     case FLG_INCLUDENEST:
1119       {
1120         int val = cstring_toPosInt (arg);
1121
1122         if (val < 0)
1123           {
1124             llerror 
1125               (FLG_BADFLAG,
1126                message 
1127                ("Flag %s must be followed by a positive number number.  "
1128                 "Followed by %s",
1129                 flagcode_unparse (opt), arg));
1130           }
1131         else
1132           {
1133             context_setValueAndFlag (opt, val);
1134           }
1135       }
1136       break;
1137     case FLG_COMMENTCHAR:
1138       {
1139         if (cstring_length (arg) != 1)
1140           {
1141             llfatalerrorLoc
1142               (message
1143                ("Flag %s should be followed by a single character.  Followed by %s",
1144                 flagcode_unparse (opt), arg));
1145           }
1146         else
1147           {
1148             context_setCommentMarkerChar (cstring_firstChar (arg));
1149           }
1150       }
1151       break;
1152     BADDEFAULT;
1153     }
1154 }
1155
1156 void setStringFlag (flagcode opt, /*@only@*/ cstring arg)
1157 {
1158   switch (opt)
1159     {
1160     case FLG_TMPDIR:
1161       {
1162         if (cstring_lastChar (arg) == CONNECTCHAR)
1163           {
1164             context_setString (opt, arg);
1165           }
1166         else
1167           {
1168             context_setString (opt, cstring_appendChar (arg, CONNECTCHAR));
1169           }
1170         break;
1171       }
1172     default:
1173       {
1174         context_setString (opt, arg);
1175         break;
1176       }
1177     }
1178 }
1179
1180 cstring
1181 describeModes ()
1182 {
1183   cstring s = cstring_makeLiteral ("Flag                    ");
1184   cstringSList sflags = sortedFlags ();
1185
1186   allModes (modename)
1187     {
1188       s = message ("%q%9s", s, cstring_fromChars (modename));
1189     } end_allModes;
1190   
1191   s = message ("%q\n", s);
1192
1193   cstringSList_elements (sflags, flagname)
1194     {
1195       flagcode code = flags_identifyFlag (flagname);
1196       fflag currentflag = flags[code];
1197       
1198       if (mstring_isDefined (currentflag.desc) && flagcode_isModeFlag (code))
1199         {
1200           s = message ("%q\n%27s", s, 
1201                        cstring_fromChars (currentflag.flag));
1202           
1203           allModes (modename)
1204             {
1205               context_setMode (cstring_fromChars (modename));
1206               
1207               if (context_getFlag (code))
1208                 {
1209                   s = message ("%q%9s", s, cstring_makeLiteralTemp ("+"));
1210                 }
1211               else
1212                 {
1213                   s = message ("%q%9s", s, cstring_makeLiteralTemp (" "));
1214                 }
1215
1216               context_resetModeFlags ();
1217             } end_allModes;
1218         }
1219     } end_cstringSList_elements;
1220   
1221   cstringSList_free (sflags);
1222
1223   s = cstring_appendChar (s, '\n');
1224
1225   return (s);
1226 }
1227
1228 # if 0
1229 static /*@unused@*/ cstring
1230 listModes (void)
1231 {
1232   cstring s = cstring_makeLiteral ("\t");
1233   int i = 0;
1234
1235   allModes (modename)
1236     {
1237       if (i != 0 && (i % 4 == 0))
1238         {
1239           s = message ("%q\n\t%15s", s, cstring_fromChars (modename));
1240         }
1241       else
1242         {
1243           s = message ("%q%15s", s, cstring_fromChars (modename));
1244         }
1245       i++;
1246     } end_allModes;
1247
1248   return s;
1249 }
1250 # endif
1251
1252 bool
1253 isMode (cstring s)
1254 {
1255   allModes (modename)
1256     {
1257       if (mstring_isDefined (modename))
1258         {
1259           if (cstring_equalLit (s, modename))
1260             {
1261               return TRUE;
1262             }
1263         }
1264      } end_allModes;
1265
1266   return FALSE;
1267 }
1268
1269 extern bool flagcode_hasArgument (flagcode f)
1270 {
1271   return (flags[f].argtype != ARG_NONE);
1272 }
1273
1274 extern bool flagcode_hasNumber (flagcode f)
1275 {
1276   return (flags[f].argtype == ARG_NUMBER);
1277 }
1278
1279 extern bool flagcode_hasChar (flagcode f)
1280 {
1281   return (flags[f].argtype == ARG_CHAR);
1282 }
1283
1284 extern bool flagcode_hasString (flagcode f)
1285 {
1286   return (flags[f].argtype == ARG_STRING
1287           || flags[f].argtype == ARG_FILE
1288           || flags[f].argtype == ARG_DIRECTORY
1289           || flags[f].argtype == ARG_PATH);
1290 }
1291
1292 extern int flagcode_valueIndex (flagcode f)
1293 {
1294   /*@unchecked@*/ static bool initialized = FALSE;
1295   int i;
1296   /*@unchecked@*/ static flagcode valueFlags[NUMVALUEFLAGS];
1297   
1298   if (!initialized)
1299     {
1300       int nv = 0;
1301
1302       allFlagCodes (code)
1303         {
1304           if (flagcode_hasNumber (code) || flagcode_hasChar (code))
1305             {
1306               llassert (nv < NUMVALUEFLAGS);
1307               DPRINTF (("Value flag: %s [%d]", flagcode_unparse (code), (int) code));
1308               valueFlags[nv] = code;
1309               nv++;
1310             }
1311         } end_allFlagCodes;
1312
1313       llassertprint (nv == NUMVALUEFLAGS,
1314                      ("Number of value flags: %d (expected %d)",
1315                       nv, (int) NUMVALUEFLAGS));
1316       initialized = TRUE;
1317     }
1318
1319   for (i = 0; i < NUMVALUEFLAGS; i++)
1320     {
1321       /* static valueFlags must be defined */
1322       /*@-usedef@*/ if (f == valueFlags[i]) /*@=usedef@*/
1323         {
1324           return i;
1325         }
1326     }
1327
1328   fprintf (stderr, "Cannot find value flag: %d", (int) f);
1329   exit (EXIT_FAILURE);
1330   /* Cannot do this...might call recursively...
1331   llfatalbug (message ("Cannot fine value flag: %d", (int) f));
1332   BADEXIT;
1333   */
1334 }
1335
1336 extern int flagcode_stringIndex (flagcode f)
1337 {
1338   /*@unchecked@*/ static bool initialized = FALSE;
1339   /*@unchecked@*/ static flagcode stringFlags[NUMSTRINGFLAGS];
1340   int i;
1341
1342
1343   if (!initialized)
1344     {
1345       int nv = 0;
1346
1347       allFlagCodes (code)
1348         {
1349           if (flagcode_hasString (code))
1350             {
1351               llassertprint (nv < NUMSTRINGFLAGS, ("Incorrect number of string flags: %d (need at least %d)", NUMSTRINGFLAGS, nv));
1352               stringFlags[nv] = code;
1353               nv++;
1354             }
1355         } end_allFlagCodes;
1356
1357       llassertprint (nv == NUMSTRINGFLAGS,
1358                      ("number of string flags: %d (expected %d)",
1359                       nv, NUMSTRINGFLAGS));
1360       initialized = TRUE;
1361     }
1362
1363   for (i = 0; i < NUMSTRINGFLAGS; i++)
1364     {
1365       /*@-usedef@*/ if (f == stringFlags[i]) /*@=usedef@*/
1366         {
1367           return i;
1368         }
1369     }
1370
1371   llbug (message ("Bad string flag: %s", flagcode_unparse (f)));
1372   BADEXIT;
1373 }
1374
1375 bool flagcode_isNamePrefixFlag (flagcode f)
1376 {
1377   switch (f)
1378     {
1379     case FLG_MACROVARPREFIX:
1380     case FLG_TAGPREFIX:
1381     case FLG_ENUMPREFIX:
1382     case FLG_FILESTATICPREFIX:
1383     case FLG_GLOBPREFIX:
1384     case FLG_TYPEPREFIX:
1385     case FLG_EXTERNALPREFIX:
1386     case FLG_LOCALPREFIX:
1387     case FLG_UNCHECKEDMACROPREFIX:
1388     case FLG_CONSTPREFIX:
1389     case FLG_ITERPREFIX:
1390     case FLG_DECLPARAMPREFIX:
1391       return TRUE;
1392     default:
1393       return FALSE;
1394     }
1395 }
1396         
This page took 3.444116 seconds and 5 git commands to generate.