]> andersk Git - splint.git/blob - src/flags.c
o Make lltok an abstract type, a pointer to structure instead of a plain
[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: info@splint.org
21 ** To report a bug: splint-bug@splint.org
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 # ifdef WIN32
144 /* Make Microsoft VC++ happy */
145 # pragma warning (disable:4715) 
146 # endif
147 }      
148
149 typedef struct { 
150   flagkind main;
151   flagkind sub;
152   bool isSpecial;  /* setting this flag may set other flags (or values) */
153   bool isIdem;     /* idempotent - always sets to TRUE */
154   bool isGlobal;   /* cannot be set locally (using control comments) */
155   bool isModeFlag; /* set by modes */
156   argcode argtype;
157   /*@observer@*/ char *flag;
158   flagcode code; 
159   /*@observer@*/ /*@null@*/ char *desc;
160   bn_mstring hint; 
161   int nreported; 
162   int nsuppressed; 
163 } fflag;
164
165 typedef fflag flaglist[];
166
167 # include "flags.def"
168
169 /*@iter allFlags (yield observer fflag f); @*/
170 # define allFlags(m_f) \
171   { /*@+enumint@*/ flagcode m_i; for (m_i = 0; m_i < NUMFLAGS; m_i++) { fflag m_f = flags[m_i]; /*@=enumint@*/
172 # define end_allFlags }}
173
174 static bn_mstring mode_names[] =
175
176   "weak", "standard", "checks", "strict", NULL, 
177 };
178
179 /*@iter allModes (yield bn_mstring modename)@*/
180 # define allModes(m_m) \
181   { int m_ii = 0; while (mstring_isDefined (mode_names[m_ii])) \
182       { bn_mstring m_m = mode_names[m_ii]; m_ii++; 
183
184 # define end_allModes }}
185
186 /*@+enumint@*/
187
188 static cstring getFlagModeSettings (flagcode p_flag) /*@modifies internalState@*/ ;
189 static cstring describeFlagCode (flagcode p_flag) /*@*/ ;
190 static cstringSList sortedFlags (void) /*@*/ ;
191 static /*@observer@*/ cstring categoryName (flagkind p_kind) /*@*/ ;
192
193 static flagcode flags_identifyFlagAux (cstring p_s, bool p_quiet) /*@modifies g_warningstream@*/ ;
194
195 # if 0
196 static /*@unused@*/ cstring listModes (void) /*@*/ ;
197 # endif
198
199 bool flagcode_isSpecialFlag (flagcode f)
200 {
201   return (flags[f].isSpecial);
202 }
203
204 bool flagcode_isGlobalFlag (flagcode f)
205 {
206   return (flags[f].isGlobal);
207 }
208
209 bool flagcode_isIdemFlag (flagcode f)
210 {
211   return (flags[f].isIdem);
212 }
213
214 bool flagcode_isModeFlag (flagcode f)
215 {
216   return (flags[f].isModeFlag);
217 }
218
219 bool flagcode_isNameChecksFlag (flagcode f)
220 {
221   return (flags[f].main == FK_NAMES);
222 }
223
224 bool flagcode_isMessageControlFlag (flagcode f)
225 {
226   /*
227   ** True if opt controls the display of messages.
228   ** These flags must be processed first.
229   */
230
231   return (f == FLG_SHOWSCAN 
232           || f == FLG_WARNRC 
233           || f == FLG_PARENFILEFORMAT
234           || f == FLG_MESSAGESTREAMSTDERR
235           || f == FLG_MESSAGESTREAMSTDOUT
236           || f == FLG_WARNINGSTREAMSTDERR
237           || f == FLG_WARNINGSTREAMSTDOUT
238           || f == FLG_ERRORSTREAMSTDERR
239           || f == FLG_ERRORSTREAMSTDOUT
240           || f == FLG_MESSAGESTREAM
241           || f == FLG_WARNINGSTREAM
242           || f == FLG_ERRORSTREAM
243           || f == FLG_STREAMOVERWRITE);
244 }
245
246 /*
247 ** Internal consistency check on the flags.
248 */
249
250 void flags_initMod ()
251 {
252   allFlagCodes (code)
253     {
254       /*@+enumint@*/
255       if (flags[code].code != code)
256         {
257           fprintf (stderr, 
258                    "*** ERROR: inconsistent flag %s / %d / %d", 
259                    flags[code].flag,
260                    flags[code].code, code);
261           
262           llbug (message ("*** ERROR: inconsistent flag %s / %d / %d", 
263                           cstring_fromChars (flags[code].flag),
264                           flags[code].code, code));
265         }
266       /*@=enumint@*/
267     } end_allFlagCodes;
268 }
269
270 void
271 summarizeErrors ()
272 {
273   bool hadOne = FALSE;
274   int sumrep = 0;
275   int sumsup = 0;
276
277   char *buf = mstring_create (128);
278
279   allFlags (f)
280     {
281       if (f.nreported > 0 || f.nsuppressed > 0)
282         {
283           int nrep = f.nreported;
284           int nsup = f.nsuppressed;
285           cstring fs = cstring_fill (cstring_fromChars (f.flag), 23);
286
287           if (!hadOne)
288             {
289               llmsgplain (cstring_makeLiteral
290                           ("\nError Type                Reported  Suppressed\n"
291                            "===================       ========  ========="));
292               hadOne = TRUE;
293             }
294
295           sprintf (buf, "%s%7d   %9d", cstring_toCharsSafe (fs), nrep, nsup);
296
297           sumrep += nrep;
298           sumsup += nsup;
299           
300           cstring_free (fs);
301           llmsg (cstring_copy (cstring_fromChars (buf)));
302         }
303     } end_allFlags;
304
305   if (hadOne)
306     {
307       cstring ts = cstring_fill (cstring_makeLiteralTemp ("Total"), 23);
308
309       llmsglit ("                          ========  =========");
310
311       sprintf (buf, "%s%7d   %9d", cstring_toCharsSafe (ts), sumrep, sumsup);
312       cstring_free (ts);
313       llmsgplain (cstring_copy (cstring_fromChars (buf)));
314     }
315
316   sfree (buf);
317 }
318
319 /*@+enumindex@*/
320
321 void
322 flagcode_recordError (flagcode f)
323 {
324   if (f != INVALID_FLAG)
325     {
326       if (f == FLG_WARNFLAGS)
327         {
328           ; /* don't count these */
329         }
330       else
331         {
332           /*drl bee: ec*/
333           /*drl bee: ec*/
334           flags[f].nreported = flags[f].nreported + 1;
335         }
336     }
337   else
338     {
339       llcontbug (message ("flagcode_recordError: invalid flag: %d", (int) f));
340     }
341 }
342
343 void
344 flagcode_recordSuppressed (flagcode f)
345 {
346   llassertprint (f != INVALID_FLAG, ("flagcode: %s", flagcode_unparse (f)));
347
348   /*drl bee: ec*/
349     /*drl bee: ec*/   flags[f].nsuppressed = flags[f].nsuppressed + 1;
350 }
351
352 int
353 flagcode_numReported (flagcode f)
354 {
355   llassert (f != INVALID_FLAG);
356
357   return (flags[f].nreported);
358 }
359
360 /*@observer@*/ cstring
361 flagcodeHint (flagcode f)
362 {
363   llassert (f != INVALID_FLAG);
364
365   /*drl bee: ec*/
366   if (mstring_isDefined (flags[f].hint))
367     {
368       return (cstring_fromChars (flags[f].hint));
369     }
370   else
371     {
372       return (cstring_fromChars (flags[f].desc));
373     }
374 }
375
376 static int categorySize (flagkind kind) /*@*/ 
377 {
378   int n = 0;
379
380   
381   allFlags (f)
382     {
383       if (f.main == kind || f.sub == kind)
384         {
385                   n++;
386         }
387     } end_allFlags;
388
389   return n;
390 }
391
392 flagkind identifyCategory (cstring s)
393 {
394   int i;
395
396   for (i = 0; categories[i].kind != FK_NONE; i++)
397     {
398         /*drl bee: mRug*/
399       if (mstring_isDefined (categories[i].name))
400         {
401           if (cstring_equalLit (s, categories[i].name))
402             {
403               return categories[i].kind;
404             }
405         }
406     }
407
408   return FK_NONE;
409 }
410
411 static /*@observer@*/ cstring categoryName (flagkind kind)
412 {
413   int i;
414
415   for (i = 0; categories[i].kind != FK_NONE; i++)
416     {
417         /*drl bee: mrUg*/
418       if (categories[i].kind == kind)
419         {
420           return (cstring_fromChars (categories[i].name));
421         }
422     }
423   
424   return (cstring_makeLiteralTemp ("<No Category>"));
425 }
426
427 static int categoryIndex (flagkind kind)
428 {
429   int i;
430
431   for (i = 0; categories[i].kind != FK_NONE; i++)
432     {
433         /*drl bee: mRug*/
434       if (categories[i].kind == kind)
435         {
436           return i;
437         }
438     }
439
440   return -1;
441 }
442
443 void printCategory (flagkind kind)
444 {
445   int index = categoryIndex (kind);
446
447   llassert (index >= 0);
448         /*drl bee: mRug*/
449   llmsg (message ("%s (%d flags)\n\3%s\n\n", 
450                   cstring_fromChars (categories[index].name), 
451                   categorySize (kind),
452                   cstring_fromChars (categories[index].describe)));
453
454   allFlags (f)
455     {
456       if (f.main == kind || f.sub == kind)
457         {
458           llmsg (message ("   %s\n\6%q", cstring_fromChars (f.flag), 
459                           describeFlagCode (f.code)));
460         }
461     } end_allFlags;
462 }
463
464 void 
465 listAllCategories (void)
466 {
467   int i;
468
469   for (i = 0; categories[i].kind != FK_NONE; i++)
470     {
471               /*drl bee: mRug*/
472       flagkind kind = categories[i].kind ;
473
474       if (categories[i].describe != NULL)
475         {
476           llmsg (message ("%s (%d flags)\n\3%s", 
477                           categoryName (kind), 
478                           categorySize (kind),
479                           cstring_fromChars (categories[i].describe)));
480         }
481     }
482 }
483
484 void
485 printAllFlags (bool desc, bool full)
486 {
487   if (full)
488     {
489       cstringSList fl = sortedFlags ();
490
491       cstringSList_elements (fl, el)
492         {
493           /*@i22@*/ /*find out why this is necessary*/
494           cstring tmp;
495           tmp = cstring_copy(el);
496           llmsg (message ("%q\n\n", describeFlag (tmp)));
497           cstring_free(tmp);
498         } end_cstringSList_elements ;
499
500       cstringSList_free (fl);
501     }
502   else
503     {
504       allFlags (f)
505         {
506           if (f.code != INVALID_FLAG && f.main != FK_OBSOLETE)
507             {
508               if (mstring_isDefined (f.desc))
509                 {
510                   if (desc)
511                     {
512                       llmsg (message ("%s --- %s", cstring_fromChars (f.flag),
513                                       cstring_fromChars (f.desc)));
514                     }
515                 }
516             }
517         } end_allFlags;
518     }
519 }
520
521 void
522 printFlagManual (bool html)
523 {
524   /*
525   ** Prints all flags by category, in order they appear in flags.def
526   */
527
528   flagkind lastCategory = FK_NONE;
529
530   allFlags (f) {
531     cstring flagname;
532     cstring flagtype = cstring_undefined;
533
534     if (f.main != lastCategory)
535       {
536         if (html)
537           {
538             llmsg (message ("\n<h4>%s</h4>\n", categoryName (f.main)));
539           }
540         else
541           {
542             llmsg (message ("\n%s\n%s\n",
543                             categoryName (f.main),
544                             cstring_makeLiteralTemp ("===================================")));
545           }
546
547         lastCategory = f.main;
548       }
549
550     if (f.argtype == ARG_NONE || f.argtype == ARG_SPECIAL)
551       {
552         if (html) 
553           {
554             flagname = message ("<tt>%s</tt>", cstring_fromChars (f.flag));
555           }
556         else
557           {
558             flagname = cstring_fromCharsNew (f.flag);
559           }
560       }
561     else
562       {
563         if (flagcode_hasString (f.code)) 
564           {
565             if (html)
566               {
567                 flagname = message ("<tt>%s <em>&lt;%s&gt;</em></tt>",
568                                     cstring_fromChars (f.flag), argcode_unparse (f.argtype));
569               }
570             else
571               {
572                 flagname = message ("%s <%s>", cstring_fromChars (f.flag), argcode_unparse (f.argtype));
573               }
574             
575             if (cstring_isDefined (context_getString (f.code)))
576               {
577                 if (html)
578                   {
579                     flagname = message ("%q <font color=\"blue\">[%s]</font>", flagname,
580                                         context_getString (f.code));
581                   }
582                 else
583                   {
584                     flagname = message ("%q [%s]", flagname,
585                                         context_getString (f.code));
586                   }
587               }
588           }
589         else if (f.argtype == ARG_CHAR)
590           {
591             if (html)
592               {
593                 flagname = message ("<tt>%s <em>&lt;%s&gt;</em></tt> <font color=\"blue\">[%c]</font>",
594                                     cstring_fromChars (f.flag), argcode_unparse (f.argtype),
595                                     (char) context_getValue (f.code));
596               }
597             else
598               {
599                 flagname = message ("%s <%s> [%c]", cstring_fromChars (f.flag), argcode_unparse (f.argtype),
600                                     (char) context_getValue (f.code));
601               }
602           }
603         else 
604           {
605             llassert (f.argtype == ARG_NUMBER);
606
607             if (html)
608               {
609                 flagname = message ("<tt>%s <em>&lt;%s&gt;</em> <font color=\"blue\">[%d]</font>",
610                                     cstring_fromChars (f.flag), argcode_unparse (f.argtype),
611                                     context_getValue (f.code));
612               }
613             else
614               {
615                 flagname = message ("%s <%s> [%d]", cstring_fromChars (f.flag), argcode_unparse (f.argtype),
616                                     context_getValue (f.code));
617               }
618           }
619       }
620
621     if (f.isIdem)
622       {
623         if (html)
624           {
625             flagtype = message("%q<font color=\"green\">-</font>", flagtype);
626           }
627         else
628           {
629             flagtype = message("%q<->", flagtype);
630           }
631       }
632     
633     if (f.isGlobal)
634       {
635         if (html)
636           {
637             flagtype = message ("%q<font color=\"green\"><em>global</em></font>", flagtype);
638           }
639         else
640           {
641             flagtype = message ("%q<G>", flagtype);
642           }
643       }
644
645     if (f.isSpecial)
646       {
647         if (html)
648           {
649             flagtype = message ("%q<font color=\"orange\"><em>shortcut</em></font>", flagtype);
650           }
651         else
652           {
653             flagtype = message("%q<S>", flagtype);
654           }
655       }
656     
657     if (f.isModeFlag)
658       {
659         if (html)
660           {
661             flagtype = message ("%q mode:<tt>%q</tt>>", flagtype, getFlagModeSettings (f.code));
662           }
663         else
664           {
665             flagtype = message ("%q<M:%q>", flagtype, getFlagModeSettings (f.code));
666           }
667       }
668     else /* its a plain flag */
669       {
670         if (html)
671           {
672             flagtype = message ("%q plain:<tt>%s</tt>", flagtype,
673                                 cstring_makeLiteralTemp (context_getFlag (f.code) ? "+" : "-"));
674           }
675         else
676           {
677             flagtype = message ("%q<P:%s>", flagtype,
678                                 cstring_makeLiteralTemp (context_getFlag (f.code) ? "+" : "-"));
679           }
680       }
681     
682     llmsg (message ("%s: %s", flagname, flagtype));
683
684     if (html)
685       {
686         llgenindentmsgnoloc (cstring_makeLiteral ("<blockquote>"));
687       }
688
689     if (mstring_isDefined (f.hint))
690       {
691         llgenindentmsgnoloc (cstring_fromCharsNew (f.hint));
692       }
693     else
694       {
695         llgenindentmsgnoloc (message ("%q.", cstring_capitalize (cstring_fromChars (f.desc))));
696       }
697
698     if (html)
699       {
700         llgenindentmsgnoloc (cstring_makeLiteral ("</blockquote>"));
701       }
702   } end_allFlags ;
703 }
704
705 cstring
706 describeFlagCode (flagcode flag)
707 {
708   cstring ret = cstring_undefined;
709   fflag f;
710   
711   if (flagcode_isInvalid (flag))
712     {
713       return (cstring_makeLiteral ("<invalid>"));
714     }
715
716   context_resetAllFlags ();
717   
718   /*drl bee: mRug*/
719   f = flags[flag];
720   ret = cstring_copy (cstring_fromChars (f.desc));
721   
722   if (f.sub != FK_NONE)
723     {
724       ret = message ("%q\nCategories: %s, %s",
725                      ret, 
726                      categoryName (f.main),
727                      categoryName (f.sub));
728     }
729   else 
730     {
731       if (f.main != FK_NONE)
732         {
733           cstring cname = categoryName (f.main);
734           
735           if (cstring_isDefined (cname))
736             {
737               ret = message ("%q\nCategory: %s",
738                              ret, cname);
739             }
740         }
741     }
742   
743   if (f.isModeFlag)
744     {
745       ret = message ("%q\nMode Settings: %q",
746                      ret, getFlagModeSettings (flag));
747     }
748   else
749     {
750       ret = message ("%q\nDefault Setting: %s",
751                      ret, 
752                      cstring_makeLiteralTemp (context_getFlag (flag) ? "+" : "-"));
753     }
754   
755   if (f.isGlobal)
756     {
757       ret = message("%q\nSet globally only", ret);
758     }
759   else
760     {
761       ret = message("%q\nSet locally", ret);
762     }
763   
764   switch (f.argtype)
765     {
766     case ARG_NONE:
767     case ARG_SPECIAL:
768       break;
769     case ARG_NUMBER:
770       ret = message("%q\nNumeric Argument.  Default: %d",
771                     ret,
772                     context_getValue (flag));
773       break;
774     case ARG_CHAR:
775       ret = message("%q\nCharacter Argument.  Default: %h",
776                     ret, (char) context_getValue (flag));
777       break;
778     case ARG_STRING:
779     case ARG_FILE:
780     case ARG_PATH:
781     case ARG_DIRECTORY:
782       {
783       if (cstring_isDefined (context_getString (flag)))
784         {
785           ret = message("%q\n%q argument.  Default: %s",
786                         ret,
787                         cstring_capitalize (argcode_unparse (f.argtype)),
788                         context_getString (flag));
789         }
790       else
791         {
792           ret = message("%q\n%s argument.  No default.", 
793                         ret,
794                         cstring_capitalize (argcode_unparse (f.argtype)));
795         }
796       break;
797       }
798     }
799   
800   if (mstring_isDefined (f.hint))
801     {
802       ret = message("%q\n\3%s", ret, cstring_fromChars (f.hint));
803     }
804   
805   return ret;
806 }
807   
808 static cstring getFlagModeSettings (flagcode flag)
809 {
810   cstring res = cstring_undefined;
811   
812   allModes (mname)
813     {
814       context_setModeNoWarn (cstring_fromChars (mname));
815       
816       res = message ("%q%s", res, cstring_makeLiteralTemp (context_getFlag (flag) ? "+" : "-"));
817     } end_allModes;
818
819   return res;
820 }
821
822 cstring
823 describeFlag (cstring flagname)
824 {
825   cstring oflagname = cstring_copy (flagname);
826   flagcode f = flags_identifyFlag (flagname);
827
828   if (flagcode_isSkip (f))
829     {
830       cstring_free (oflagname);
831       return cstring_undefined;
832     }
833   else if (flagcode_isValid (f))
834     {
835       if (cstring_equal (flagname, oflagname))
836         {
837           cstring_free (oflagname);
838           return (message ("%s\n\3%q", flagname, describeFlagCode (f)));
839         }
840       else
841         {
842           return (message ("%q (standardized name: %s)\n\3%q",
843                            oflagname, flagname, describeFlagCode (f)));
844         }
845     }
846   else
847     {
848       if (isMode (flagname))
849         {
850           cstring_free (oflagname);
851
852           return
853             (message ("%s: predefined mode (see Manual for information)",
854                       flagname));
855         }
856       else
857         {
858           return (message ("%q: <invalid flag>", oflagname));
859         }
860     }
861 }
862
863 static cstringSList
864 sortedFlags (void)
865 {
866   cstringSList s = cstringSList_new ();
867
868   allFlags (f)
869     {
870       if (f.desc != NULL)
871         {
872           s = cstringSList_add (s, cstring_fromChars (f.flag));
873         }
874     } end_allFlags;
875
876   cstringSList_alphabetize (s);
877
878   return s;
879 }
880
881 void printAlphaFlags ()
882 {
883   cstringSList fl = sortedFlags ();
884
885   cstringSList_printSpaced (fl, 3, 1, context_getLineLen () - 25); 
886   cstringSList_free (fl);
887 }
888
889 /*@observer@*/ cstring
890 flagcode_unparse (flagcode code)
891 {
892   if (code == INVALID_FLAG)
893     {
894       return cstring_makeLiteralTemp ("<invalid flag>");
895     }
896
897   return cstring_fromChars (flags[code].flag);
898 }
899
900 /*
901 ** Transforms a flag into its cannonical form.
902 **
903 ** The following transformations are made:
904 **
905 **    function      -> fcn
906 **    variable      -> var
907 **    constant      -> const
908 **    iterator      -> iter
909 **    parameter     -> param
910 **    unrecognized  -> unrecog
911 **    qualifier     -> qual         
912 **    declaration   -> decl
913 **    globalias     -> (no change)
914 **    global        -> glob
915 **    modifies      -> mods
916 **    modify        -> mod
917 **    pointer       -> ptr
918 **    implies       -> imp
919 **    implicit      -> imp
920 **    implied       -> imp
921 **    unconstrained -> unspec       
922 **    unconst       -> unspec
923 **    memory        -> mem
924 **    length        -> len
925 */
926
927 static /*@only@*/ cstring
928 canonicalizeFlag (cstring s)
929 {
930   int i = 0;
931   cstring res = cstring_copy (s);
932   static bn_mstring transform[] = 
933     { 
934       "function", "fcn",
935       "variable", "var",
936       "constant", "const",
937       "iterator", "iter",
938       "parameter", "param",
939       "unrecognized", "unrecog",
940       "qualifier", "qual",
941       "declaration", "decl",
942       "globals", "globs", 
943       "modifies", "mods", 
944       "modify", "mod",
945       "pointer", "ptr",
946       "implies", "imp",
947       "implicit", "imp",
948       "implied", "imp",
949       "unconstrained", "uncon",
950       "unconst", "uncon",
951       "memory", "mem",
952       "length", "len",
953       "return", "ret",
954       "system", "sys",
955       NULL
956       } ;
957   char *current;
958   
959   /*drl bee: ia*/
960   while ((current = transform[i]) != NULL)
961     {
962       if (cstring_containsLit (res, current))
963         {
964           cstring_replaceLit (res, current, transform[i+1]);
965         }
966       i += 2;
967     }
968
969   /* remove whitespace, -'s, and _'s */
970   cstring_stripChars (res, " -_");
971   return res;
972 }
973
974 flagcode
975 flags_identifyFlag (cstring s)
976 {
977   return flags_identifyFlagAux (s, FALSE);
978 }
979
980 flagcode
981 flags_identifyFlagQuiet (cstring s)
982 {
983   return flags_identifyFlagAux (s, TRUE);
984 }
985
986 static flagcode
987 flags_identifyFlagAux (cstring s, bool quiet)
988 {
989   cstring cflag;
990   flagcode res;
991
992   if (cstring_length (s) == 0) {
993     /* evs 2000-06-25: A malformed flag. */
994     return INVALID_FLAG;
995   }
996
997   if (cstring_firstChar (s) == 'I')
998     {
999       return FLG_INCLUDEPATH; /* no space after -I */
1000     }
1001
1002   if (cstring_firstChar (s) == 'S') 
1003     {
1004       return FLG_SPECPATH;    /* no space after -S */
1005     }
1006
1007   if (cstring_firstChar (s) == 'D') 
1008     {
1009       return FLG_DEFINE;      /* no space after -D */
1010     }
1011
1012   if (cstring_firstChar (s) == 'U') 
1013     {
1014       return FLG_UNDEFINE;    /* no space after -D */
1015     }
1016
1017   cflag = canonicalizeFlag (s);
1018   res = INVALID_FLAG;
1019
1020   allFlags (f)
1021     {
1022       if (cstring_equal (cstring_fromChars (f.flag), cflag))
1023         {
1024           res = f.code;
1025           break;
1026         }
1027     } end_allFlags;
1028   
1029   if (res == INVALID_FLAG)
1030     {
1031       /*
1032       ** Synonyms
1033       */
1034       
1035       if (cstring_equalLit (cflag, "pred"))
1036         {
1037           res = FLG_PREDBOOL;
1038         }
1039       else if (cstring_equalLit (cflag, "modobserverstrict"))
1040         {
1041           res = FLG_MODOBSERVERUNCON;
1042         }
1043       else if (cstring_equalLit (cflag, "czechnames"))
1044         {
1045           res = FLG_CZECH;
1046         }
1047       else if (cstring_equalLit (cflag, "slovaknames"))
1048         {
1049           res = FLG_SLOVAK;
1050         }
1051       else if (cstring_equalLit (cflag, "czechoslovaknames"))
1052         {
1053           res = FLG_CZECHOSLOVAK;
1054         }
1055       else if (cstring_equalLit (cflag, "globunspec")
1056                || cstring_equalLit (cflag, "globuncon"))
1057         {
1058           res = FLG_GLOBUNSPEC;
1059         }
1060       else if (cstring_equalLit (cflag, "modglobsunspec")
1061                || cstring_equalLit (cflag, "modglobsuncon")
1062                || cstring_equalLit (cflag, "modglobsnomods"))
1063         {
1064           res = FLG_MODGLOBSUNSPEC;
1065         }
1066       else if (cstring_equalLit (cflag, "export"))
1067         {
1068           res = FLG_EXPORTANY;
1069         }
1070       else if (cstring_equalLit (cflag, "macrospec"))
1071         {
1072           res = FLG_MACRODECL;
1073         }
1074       else if (cstring_equalLit (cflag, "ansireservedlocal"))
1075         {
1076           res = FLG_ISORESERVEDLOCAL;
1077         }
1078       else if (cstring_equalLit (cflag, "warnposix"))
1079         {
1080           res = FLG_WARNPOSIX;
1081         }
1082       else if (cstring_equalLit (cflag, "defuse"))
1083         {
1084           res = FLG_USEDEF;
1085         }
1086       else if (cstring_equalLit (cflag, "macroundef"))
1087         {
1088           res = FLG_MACROUNDEF;
1089         }
1090       else if (cstring_equalLit (cflag, "showcol"))
1091         {
1092           res = FLG_SHOWCOL;
1093         }
1094       else if (cstring_equalLit (cflag, "intbool"))
1095         {
1096           res = FLG_BOOLINT;
1097         }
1098       else if (cstring_equalLit (cflag, "intchar"))
1099         {
1100           res = FLG_CHARINT;
1101         }
1102       else if (cstring_equalLit (cflag, "intenum"))
1103         {
1104           res = FLG_ENUMINT;
1105         }
1106       /*
1107       ** Backwards compatibility for our American friends...
1108       */
1109       
1110       else if (cstring_equalLit (cflag, "ansilib"))
1111         {
1112           res = FLG_ANSILIB;
1113         }
1114       else if (cstring_equalLit (cflag, "ansistrictlib"))
1115         {
1116           res = FLG_STRICTLIB;
1117         }
1118       else if (cstring_equalLit (cflag, "skipansiheaders"))
1119         {
1120           res = FLG_SKIPISOHEADERS;
1121         }
1122       else if (cstring_equalLit (cflag, "ansireserved"))
1123         {
1124           res = FLG_ISORESERVED;
1125         }
1126       else if (cstring_equalLit (cflag, "ansireservedinternal"))
1127         {
1128           res = FLG_ISORESERVEDLOCAL;
1129         }
1130       
1131       /*
1132       ** Obsolete Flags
1133       */
1134       
1135       else if (cstring_equalLit (cflag, "accessunspec"))
1136         {
1137           if (!quiet) 
1138             {
1139               llerror_flagWarning 
1140                 (cstring_makeLiteral
1141                  ("accessunspec flag is no longer supported.  It has been replaced by accessmodule, accessfile and "
1142                   "accessfunction to provide more precise control of accessibility "
1143                   "of representations.  For more information, "
1144                   "see splint -help accessmodule"));
1145             }
1146           
1147           res = SKIP_FLAG;
1148         }
1149       else if (cstring_equalLit (cflag, "ansilimits"))
1150         {
1151           llerror_flagWarning 
1152             (cstring_makeLiteral
1153              ("ansilimits flag is no longer supported.  It has been replaced by ansi89limits and "
1154               "iso99limits to select either the lower translation limits imposed by the ANSI89 "
1155               "standard or the typically higher limits prescribed by ISO C99."));
1156           
1157           res = SKIP_FLAG;
1158         }
1159       else if (cstring_equalLit (cflag, "staticmods"))
1160         {
1161           if (!quiet) 
1162             {
1163               llerror_flagWarning 
1164                 (cstring_makeLiteral
1165                  ("staticmods flag is obsolete.  You probably "
1166                   "want impcheckmodstatics.  For more information, "
1167                   "see splint -help impcheckmodstatics"));
1168             }
1169           
1170           res = SKIP_FLAG;
1171         }
1172       else if (cstring_equalLit (cflag, "bool"))
1173         {
1174           if (!quiet) 
1175             {
1176               llerror_flagWarning
1177                 (cstring_makeLiteral ("bool flag is obsolete.  It never really "
1178                                       "made sense in the first place."));
1179             }
1180           
1181           res = SKIP_FLAG;
1182         }
1183       else if (cstring_equalLit (cflag, "shiftsigned"))
1184         {
1185           if (!quiet) 
1186             {
1187               llerror_flagWarning
1188                 (cstring_makeLiteral ("shiftsigned flag is obsolete.  You probably "
1189                                       "want bitwisesigned, shiftnegative or shiftimplementation."));
1190             }
1191           
1192           res = SKIP_FLAG;
1193         }
1194       else if (cstring_equalLit (cflag, "ansi"))
1195         {
1196           if (!quiet) 
1197             {
1198               llerror_flagWarning
1199                 (cstring_makeLiteral ("ansi flag is obsolete.  You probably "
1200                                       "want noparams and/or oldstyle."));
1201             }
1202           
1203           res = SKIP_FLAG;
1204         }
1205       else if (cstring_equalLit (cflag, "usestderr"))
1206         {
1207           if (!quiet)
1208             {
1209               llerror_flagWarning 
1210                 (cstring_makeLiteral
1211                  ("usestderr flag is obsolete. This has been replaced "
1212                   "by more precise flags for controlling the warning, "
1213                   "status message and fatal error streams independently: message-stream-stdout, "
1214                   "message-stream-stderr, message-stream <file>, "
1215                   "warning-stream-stdout, warning-stream-stderr, warning-stream <file>, "
1216                   "error-stream-stdout, error-stream-stderr, error-stream <file>."));
1217             }
1218           
1219           res = SKIP_FLAG;
1220         }
1221
1222       else if (cstring_equalLit (cflag, "stdio"))
1223         {
1224           if (!quiet) 
1225             {
1226               llerror_flagWarning 
1227                 (cstring_makeLiteral
1228                  ("stdio flag is obsolete.  You may "
1229                   "want strictlib or one of the gloabls "
1230                   "checking flags.  For more information, "
1231                   "see splint -help strictlib or splint -help flags globals"));
1232             }
1233           
1234           res = SKIP_FLAG;
1235         }
1236       else
1237         {
1238           res = INVALID_FLAG;
1239         }
1240     }
1241
1242   cstring_free (cflag);
1243   return res;
1244 }
1245
1246 void setValueFlag (flagcode opt, cstring arg)
1247 {
1248   switch (opt)
1249     {
1250     case FLG_EXPECT:
1251     case FLG_LCLEXPECT:
1252     case FLG_LIMIT:  
1253     case FLG_LINELEN:
1254     case FLG_INDENTSPACES:
1255     case FLG_BUGSLIMIT:
1256     case FLG_EXTERNALNAMELEN:
1257     case FLG_INTERNALNAMELEN:
1258     case FLG_CONTROLNESTDEPTH:
1259     case FLG_STRINGLITERALLEN:
1260     case FLG_NUMSTRUCTFIELDS:
1261     case FLG_NUMENUMMEMBERS:
1262     case FLG_INCLUDENEST:
1263       {
1264         int val = cstring_toPosInt (arg);
1265
1266         if (val < 0)
1267           {
1268             llerror 
1269               (FLG_BADFLAG,
1270                message 
1271                ("Flag %s must be followed by a positive number number.  "
1272                 "Followed by %s",
1273                 flagcode_unparse (opt), arg));
1274           }
1275         else
1276           {
1277             context_setValueAndFlag (opt, val);
1278           }
1279       }
1280       break;
1281     case FLG_COMMENTCHAR:
1282       {
1283         if (cstring_length (arg) != 1)
1284           {
1285             llfatalerrorLoc
1286               (message
1287                ("Flag %s should be followed by a single character.  Followed by %s",
1288                 flagcode_unparse (opt), arg));
1289           }
1290         else
1291           {
1292             context_setCommentMarkerChar (cstring_firstChar (arg));
1293           }
1294       }
1295       break;
1296     BADDEFAULT;
1297     }
1298 }
1299
1300 void setStringFlag (flagcode opt, /*@only@*/ cstring arg)
1301 {
1302   switch (opt)
1303     {
1304     case FLG_TMPDIR:
1305       {
1306         if (cstring_lastChar (arg) == CONNECTCHAR)
1307           {
1308             context_setString (opt, arg);
1309           }
1310         else
1311           {
1312             context_setString (opt, cstring_appendChar (arg, CONNECTCHAR));
1313           }
1314         break;
1315       }
1316     default:
1317       {
1318         context_setString (opt, arg);
1319         break;
1320       }
1321     }
1322 }
1323
1324 cstring
1325 describeModes ()
1326 {
1327   cstring s = cstring_makeLiteral ("Flag                    ");
1328   cstringSList sflags = sortedFlags ();
1329
1330   allModes (modename)
1331     {
1332       s = message ("%q%9s", s, cstring_fromChars (modename));
1333     } end_allModes;
1334   
1335   s = message ("%q\n", s);
1336
1337   cstringSList_elements (sflags, flagname)
1338     {
1339       flagcode code = flags_identifyFlag (flagname);
1340       fflag currentflag = flags[code];
1341       
1342       if (mstring_isDefined (currentflag.desc) && flagcode_isModeFlag (code))
1343         {
1344           s = message ("%q\n%27s", s, 
1345                        cstring_fromChars (currentflag.flag));
1346           
1347           allModes (modename)
1348             {
1349               context_setMode (cstring_fromChars (modename));
1350               
1351               if (context_getFlag (code))
1352                 {
1353                   s = message ("%q%9s", s, cstring_makeLiteralTemp ("+"));
1354                 }
1355               else
1356                 {
1357                   s = message ("%q%9s", s, cstring_makeLiteralTemp (" "));
1358                 }
1359
1360               context_resetModeFlags ();
1361             } end_allModes;
1362         }
1363     } end_cstringSList_elements;
1364   
1365   cstringSList_free (sflags);
1366
1367   s = cstring_appendChar (s, '\n');
1368
1369   return (s);
1370 }
1371
1372 # if 0
1373 static /*@unused@*/ cstring
1374 listModes (void)
1375 {
1376   cstring s = cstring_makeLiteral ("\t");
1377   int i = 0;
1378
1379   allModes (modename)
1380     {
1381       if (i != 0 && (i % 4 == 0))
1382         {
1383           s = message ("%q\n\t%15s", s, cstring_fromChars (modename));
1384         }
1385       else
1386         {
1387           s = message ("%q%15s", s, cstring_fromChars (modename));
1388         }
1389       i++;
1390     } end_allModes;
1391
1392   return s;
1393 }
1394 # endif
1395
1396 bool
1397 isMode (cstring s)
1398 {
1399   allModes (modename)
1400     {
1401       if (mstring_isDefined (modename))
1402         {
1403           if (cstring_equalLit (s, modename))
1404             {
1405               return TRUE;
1406             }
1407         }
1408      } end_allModes;
1409
1410   return FALSE;
1411 }
1412
1413 extern bool flagcode_hasArgument (flagcode f)
1414 {
1415   return (flags[f].argtype != ARG_NONE);
1416 }
1417
1418 extern bool flagcode_hasNumber (flagcode f)
1419 {
1420   return (flags[f].argtype == ARG_NUMBER);
1421 }
1422
1423 extern bool flagcode_hasChar (flagcode f)
1424 {
1425   return (flags[f].argtype == ARG_CHAR);
1426 }
1427
1428 extern bool flagcode_hasString (flagcode f)
1429 {
1430   return (flags[f].argtype == ARG_STRING
1431           || flags[f].argtype == ARG_FILE
1432           || flags[f].argtype == ARG_DIRECTORY
1433           || flags[f].argtype == ARG_PATH);
1434 }
1435
1436 extern int flagcode_valueIndex (flagcode f)
1437 {
1438   /*@unchecked@*/ static bool initialized = FALSE;
1439   int i;
1440   /*@unchecked@*/ static flagcode valueFlags[NUMVALUEFLAGS];
1441   
1442   if (!initialized)
1443     {
1444       int nv = 0;
1445
1446       allFlagCodes (code)
1447         {
1448           if (flagcode_hasNumber (code) || flagcode_hasChar (code))
1449             {
1450               llassert (nv < NUMVALUEFLAGS);
1451               DPRINTF (("Value flag: %s [%d]", flagcode_unparse (code), (int) code));
1452               valueFlags[nv] = code;
1453               nv++;
1454             }
1455         } end_allFlagCodes;
1456
1457       llassertprint (nv == NUMVALUEFLAGS,
1458                      ("Number of value flags: %d (expected %d)",
1459                       nv, (int) NUMVALUEFLAGS));
1460       initialized = TRUE;
1461     }
1462
1463   for (i = 0; i < NUMVALUEFLAGS; i++)
1464     {
1465       /* static valueFlags must be defined */
1466       /*@-usedef@*/
1467       /*drl bee: sta*/
1468       if (f == valueFlags[i]) /*@=usedef@*/
1469         {
1470           return i;
1471         }
1472     }
1473
1474   fprintf (stderr, "Cannot find value flag: %d", (int) f);
1475   exit (EXIT_FAILURE);
1476   /* Cannot do this...might call recursively...
1477   llfatalbug (message ("Cannot fine value flag: %d", (int) f));
1478   BADEXIT;
1479   */
1480 }
1481
1482 extern int flagcode_stringIndex (flagcode f)
1483 {
1484   /*@unchecked@*/ static bool initialized = FALSE;
1485   /*@unchecked@*/ static flagcode stringFlags[NUMSTRINGFLAGS];
1486   int i;
1487
1488
1489   if (!initialized)
1490     {
1491       int nv = 0;
1492
1493       allFlagCodes (code)
1494         {
1495           if (flagcode_hasString (code))
1496             {
1497               llassertprint (nv < NUMSTRINGFLAGS, ("Incorrect number of string flags: %d (need at least %d)", NUMSTRINGFLAGS, nv));
1498               stringFlags[nv] = code;
1499               nv++;
1500             }
1501         } end_allFlagCodes;
1502
1503       llassertprint (nv == NUMSTRINGFLAGS,
1504                      ("number of string flags: %d (expected %d)",
1505                       nv, NUMSTRINGFLAGS));
1506       initialized = TRUE;
1507     }
1508
1509   for (i = 0; i < NUMSTRINGFLAGS; i++)
1510     {
1511               /*drl bee: sta*/
1512       /*@-usedef@*/ if (f == stringFlags[i]) /*@=usedef@*/
1513         {
1514           return i;
1515         }
1516     }
1517
1518   llbug (message ("Bad string flag: %s", flagcode_unparse (f)));
1519   BADEXIT;
1520 }
1521
1522 bool flagcode_isNamePrefixFlag (flagcode f)
1523 {
1524   switch (f)
1525     {
1526     case FLG_MACROVARPREFIX:
1527     case FLG_TAGPREFIX:
1528     case FLG_ENUMPREFIX:
1529     case FLG_FILESTATICPREFIX:
1530     case FLG_GLOBPREFIX:
1531     case FLG_TYPEPREFIX:
1532     case FLG_EXTERNALPREFIX:
1533     case FLG_LOCALPREFIX:
1534     case FLG_UNCHECKEDMACROPREFIX:
1535     case FLG_CONSTPREFIX:
1536     case FLG_ITERPREFIX:
1537     case FLG_DECLPARAMPREFIX:
1538       return TRUE;
1539     default:
1540       return FALSE;
1541     }
1542 }
1543         
This page took 0.31978 seconds and 5 git commands to generate.