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