]> andersk Git - splint.git/blob - src/flags.c
fc272e012119ece85e0aba9921765300e6a23cf7
[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 void
906 canonicalizeFlag (cstring s)
907 {
908   int i = 0;
909   static bn_mstring transform[] = 
910     { 
911       "function", "fcn",
912       "variable", "var",
913       "constant", "const",
914       "iterator", "iter",
915       "parameter", "param",
916       "unrecognized", "unrecog",
917       "qualifier", "qual",
918       "declaration", "decl",
919       "globals", "globs", 
920       "modifies", "mods", 
921       "modify", "mod",
922       "pointer", "ptr",
923       "implies", "imp",
924       "implicit", "imp",
925       "implied", "imp",
926       "unconstrained", "uncon",
927       "unconst", "uncon",
928       "memory", "mem",
929       "length", "len",
930       "return", "ret",
931       "system", "sys",
932       NULL
933       } ;
934   char *current;
935   
936   /*drl bee: ia*/
937   while ((current = transform[i]) != NULL)
938     {
939       if (cstring_containsLit (s, current))
940         {
941           cstring_replaceLit (s, current, transform[i+1]);
942         }
943       i += 2;
944     }
945
946   /* remove whitespace, -'s, and _'s */
947   cstring_stripChars (s, " -_");
948 }
949
950 flagcode
951 flags_identifyFlag (cstring s)
952 {
953   return flags_identifyFlagAux (s, FALSE);
954 }
955
956 flagcode
957 flags_identifyFlagQuiet (cstring s)
958 {
959   return flags_identifyFlagAux (s, TRUE);
960 }
961
962 static flagcode
963 flags_identifyFlagAux (cstring s, bool quiet)
964 {
965   if (cstring_length (s) == 0) {
966     /* evs 2000-06-25: A malformed flag. */
967     return INVALID_FLAG;
968   }
969
970   if (cstring_firstChar (s) == 'I')
971     {
972       return FLG_INCLUDEPATH; /* no space after -I */
973     }
974
975   if (cstring_firstChar (s) == 'S') 
976     {
977       return FLG_SPECPATH;    /* no space after -S */
978     }
979
980   if (cstring_firstChar (s) == 'D') 
981     {
982       return FLG_DEFINE;      /* no space after -D */
983     }
984
985   if (cstring_firstChar (s) == 'U') 
986     {
987       return FLG_UNDEFINE;    /* no space after -D */
988     }
989
990   canonicalizeFlag (s);
991
992   allFlags (f)
993     {
994       if (cstring_equal (cstring_fromChars (f.flag), s))
995         {
996           return (f.code);
997         }
998     } end_allFlags;
999
1000   /*
1001   ** Synonyms
1002   */
1003
1004   if (cstring_equalLit (s, "pred"))
1005     {
1006       return FLG_PREDBOOL;
1007     }
1008
1009   if (cstring_equalLit (s, "modobserverstrict"))
1010     {
1011       return FLG_MODOBSERVERUNCON;
1012     }
1013
1014   if (cstring_equalLit (s, "czechnames"))
1015     {
1016       return FLG_CZECH;
1017     }
1018
1019   if (cstring_equalLit (s, "slovaknames"))
1020     {
1021       return FLG_SLOVAK;
1022     }
1023
1024   if (cstring_equalLit (s, "czechoslovaknames"))
1025     {
1026       return FLG_CZECHOSLOVAK;
1027     }
1028
1029   if (cstring_equalLit (s, "globunspec")
1030            || cstring_equalLit (s, "globuncon"))
1031     {
1032       return FLG_GLOBUNSPEC;
1033     }
1034
1035   if (cstring_equalLit (s, "modglobsunspec")
1036            || cstring_equalLit (s, "modglobsuncon")
1037            || cstring_equalLit (s, "modglobsnomods"))
1038     {
1039       return FLG_MODGLOBSUNSPEC;
1040     }
1041
1042   if (cstring_equalLit (s, "export"))
1043     {
1044       return FLG_EXPORTANY;
1045     }
1046
1047   if (cstring_equalLit (s, "macrospec"))
1048     {
1049       return FLG_MACRODECL;
1050     }
1051   
1052   if (cstring_equalLit (s, "ansireservedlocal"))
1053     {
1054       return FLG_ANSIRESERVEDLOCAL;
1055     }
1056
1057   if (cstring_equalLit (s, "warnposix"))
1058     {
1059       return FLG_WARNPOSIX;
1060     }
1061
1062   if (cstring_equalLit (s, "defuse"))
1063     {
1064       return FLG_USEDEF;
1065     }
1066
1067   if (cstring_equalLit (s, "macroundef"))
1068     {
1069       return FLG_MACROUNDEF;
1070     }
1071
1072   if (cstring_equalLit (s, "showcol"))
1073     {
1074       return FLG_SHOWCOL;
1075     }
1076
1077   if (cstring_equalLit (s, "intbool"))
1078     {
1079       return FLG_BOOLINT;
1080     }
1081
1082   if (cstring_equalLit (s, "intchar"))
1083     {
1084       return FLG_CHARINT;
1085     }
1086
1087   if (cstring_equalLit (s, "intenum"))
1088     {
1089       return FLG_ENUMINT;
1090     }
1091
1092   /*
1093   ** Backwards compatibility for our American friends...
1094   */
1095
1096   if (cstring_equalLit (s, "ansilib"))
1097     {
1098       return FLG_ANSILIB;
1099     }
1100
1101   if (cstring_equalLit (s, "ansistrictlib"))
1102     {
1103       return FLG_STRICTLIB;
1104     }
1105
1106   if (cstring_equalLit (s, "skipansiheaders"))
1107     {
1108       return FLG_SKIPANSIHEADERS;
1109     }
1110
1111   if (cstring_equalLit (s, "ansireserved"))
1112     {
1113       return FLG_ANSIRESERVED;
1114     }
1115
1116   if (cstring_equalLit (s, "ansireservedinternal"))
1117     {
1118       return FLG_ANSIRESERVEDLOCAL;
1119     }
1120
1121   /*
1122   ** Obsolete Flags
1123   */
1124   
1125   if (cstring_equalLit (s, "accessunspec"))
1126     {
1127       if (!quiet) 
1128         {
1129           llerror_flagWarning 
1130             (cstring_makeLiteral
1131              ("accessunspec flag is no longer supported.  It has been replaced by accessmodule, accessfile and "
1132               "accessfunction to provide more precise control of accessibility "
1133               "of representations.  For more information, "
1134               "see splint -help accessmodule"));
1135         }
1136       
1137       return SKIP_FLAG;
1138     }
1139   else if (cstring_equalLit (s, "ansilimits"))
1140     {
1141           llerror_flagWarning 
1142             (cstring_makeLiteral
1143              ("ansilimits flag is no longer supported.  It has been replaced by ansi89limits and "
1144               "iso99limits to select either the lower translation limits imposed by the ANSI89 "
1145               "standard or the typically higher limits prescribed by ISO C99."));
1146
1147       return SKIP_FLAG;
1148     }
1149   else if (cstring_equalLit (s, "staticmods"))
1150     {
1151       if (!quiet) 
1152         {
1153           llerror_flagWarning 
1154             (cstring_makeLiteral
1155              ("staticmods flag is obsolete.  You probably "
1156               "want impcheckmodstatics.  For more information, "
1157               "see splint -help impcheckmodstatics"));
1158         }
1159
1160       return SKIP_FLAG;
1161     }
1162   else if (cstring_equalLit (s, "bool"))
1163     {
1164       if (!quiet) 
1165         {
1166           llerror_flagWarning
1167             (cstring_makeLiteral ("bool flag is obsolete.  It never really "
1168                                   "made sense in the first place."));
1169         }
1170       
1171       return SKIP_FLAG;
1172     }
1173   else if (cstring_equalLit (s, "shiftsigned"))
1174     {
1175       if (!quiet) 
1176         {
1177           llerror_flagWarning
1178             (cstring_makeLiteral ("shiftsigned flag is obsolete.  You probably "
1179                                   "want bitwisesigned, shiftnegative or shiftsize."));
1180         }
1181       
1182       return SKIP_FLAG;
1183     }
1184   else if (cstring_equalLit (s, "ansi"))
1185     {
1186       if (!quiet) 
1187         {
1188           llerror_flagWarning
1189             (cstring_makeLiteral ("ansi flag is obsolete.  You probably "
1190                                   "want noparams and/or oldstyle."));
1191         }
1192       
1193       return SKIP_FLAG;
1194     }
1195   else if (cstring_equalLit (s, "stdio"))
1196     {
1197       if (!quiet) 
1198         {
1199           llerror_flagWarning 
1200             (cstring_makeLiteral
1201              ("stdio flag is obsolete.  You may "
1202               "want strictlib or one of the gloabls "
1203               "checking flags.  For more information, "
1204               "see splint -help strictlib or splint -help flags globals"));
1205         }
1206       
1207       return SKIP_FLAG;
1208     }
1209   else
1210     {
1211       return INVALID_FLAG;
1212     }
1213 }
1214
1215 void setValueFlag (flagcode opt, cstring arg)
1216 {
1217   switch (opt)
1218     {
1219     case FLG_EXPECT:
1220     case FLG_LCLEXPECT:
1221     case FLG_LIMIT:  
1222     case FLG_LINELEN:
1223     case FLG_INDENTSPACES:
1224     case FLG_BUGSLIMIT:
1225     case FLG_EXTERNALNAMELEN:
1226     case FLG_INTERNALNAMELEN:
1227     case FLG_CONTROLNESTDEPTH:
1228     case FLG_STRINGLITERALLEN:
1229     case FLG_NUMSTRUCTFIELDS:
1230     case FLG_NUMENUMMEMBERS:
1231     case FLG_INCLUDENEST:
1232       {
1233         int val = cstring_toPosInt (arg);
1234
1235         if (val < 0)
1236           {
1237             llerror 
1238               (FLG_BADFLAG,
1239                message 
1240                ("Flag %s must be followed by a positive number number.  "
1241                 "Followed by %s",
1242                 flagcode_unparse (opt), arg));
1243           }
1244         else
1245           {
1246             context_setValueAndFlag (opt, val);
1247           }
1248       }
1249       break;
1250     case FLG_COMMENTCHAR:
1251       {
1252         if (cstring_length (arg) != 1)
1253           {
1254             llfatalerrorLoc
1255               (message
1256                ("Flag %s should be followed by a single character.  Followed by %s",
1257                 flagcode_unparse (opt), arg));
1258           }
1259         else
1260           {
1261             context_setCommentMarkerChar (cstring_firstChar (arg));
1262           }
1263       }
1264       break;
1265     BADDEFAULT;
1266     }
1267 }
1268
1269 void setStringFlag (flagcode opt, /*@only@*/ cstring arg)
1270 {
1271   switch (opt)
1272     {
1273     case FLG_TMPDIR:
1274       {
1275         if (cstring_lastChar (arg) == CONNECTCHAR)
1276           {
1277             context_setString (opt, arg);
1278           }
1279         else
1280           {
1281             context_setString (opt, cstring_appendChar (arg, CONNECTCHAR));
1282           }
1283         break;
1284       }
1285     default:
1286       {
1287         context_setString (opt, arg);
1288         break;
1289       }
1290     }
1291 }
1292
1293 cstring
1294 describeModes ()
1295 {
1296   cstring s = cstring_makeLiteral ("Flag                    ");
1297   cstringSList sflags = sortedFlags ();
1298
1299   allModes (modename)
1300     {
1301       s = message ("%q%9s", s, cstring_fromChars (modename));
1302     } end_allModes;
1303   
1304   s = message ("%q\n", s);
1305
1306   cstringSList_elements (sflags, flagname)
1307     {
1308       flagcode code = flags_identifyFlag (flagname);
1309       fflag currentflag = flags[code];
1310       
1311       if (mstring_isDefined (currentflag.desc) && flagcode_isModeFlag (code))
1312         {
1313           s = message ("%q\n%27s", s, 
1314                        cstring_fromChars (currentflag.flag));
1315           
1316           allModes (modename)
1317             {
1318               context_setMode (cstring_fromChars (modename));
1319               
1320               if (context_getFlag (code))
1321                 {
1322                   s = message ("%q%9s", s, cstring_makeLiteralTemp ("+"));
1323                 }
1324               else
1325                 {
1326                   s = message ("%q%9s", s, cstring_makeLiteralTemp (" "));
1327                 }
1328
1329               context_resetModeFlags ();
1330             } end_allModes;
1331         }
1332     } end_cstringSList_elements;
1333   
1334   cstringSList_free (sflags);
1335
1336   s = cstring_appendChar (s, '\n');
1337
1338   return (s);
1339 }
1340
1341 # if 0
1342 static /*@unused@*/ cstring
1343 listModes (void)
1344 {
1345   cstring s = cstring_makeLiteral ("\t");
1346   int i = 0;
1347
1348   allModes (modename)
1349     {
1350       if (i != 0 && (i % 4 == 0))
1351         {
1352           s = message ("%q\n\t%15s", s, cstring_fromChars (modename));
1353         }
1354       else
1355         {
1356           s = message ("%q%15s", s, cstring_fromChars (modename));
1357         }
1358       i++;
1359     } end_allModes;
1360
1361   return s;
1362 }
1363 # endif
1364
1365 bool
1366 isMode (cstring s)
1367 {
1368   allModes (modename)
1369     {
1370       if (mstring_isDefined (modename))
1371         {
1372           if (cstring_equalLit (s, modename))
1373             {
1374               return TRUE;
1375             }
1376         }
1377      } end_allModes;
1378
1379   return FALSE;
1380 }
1381
1382 extern bool flagcode_hasArgument (flagcode f)
1383 {
1384   return (flags[f].argtype != ARG_NONE);
1385 }
1386
1387 extern bool flagcode_hasNumber (flagcode f)
1388 {
1389   return (flags[f].argtype == ARG_NUMBER);
1390 }
1391
1392 extern bool flagcode_hasChar (flagcode f)
1393 {
1394   return (flags[f].argtype == ARG_CHAR);
1395 }
1396
1397 extern bool flagcode_hasString (flagcode f)
1398 {
1399   return (flags[f].argtype == ARG_STRING
1400           || flags[f].argtype == ARG_FILE
1401           || flags[f].argtype == ARG_DIRECTORY
1402           || flags[f].argtype == ARG_PATH);
1403 }
1404
1405 extern int flagcode_valueIndex (flagcode f)
1406 {
1407   /*@unchecked@*/ static bool initialized = FALSE;
1408   int i;
1409   /*@unchecked@*/ static flagcode valueFlags[NUMVALUEFLAGS];
1410   
1411   if (!initialized)
1412     {
1413       int nv = 0;
1414
1415       allFlagCodes (code)
1416         {
1417           if (flagcode_hasNumber (code) || flagcode_hasChar (code))
1418             {
1419               llassert (nv < NUMVALUEFLAGS);
1420               DPRINTF (("Value flag: %s [%d]", flagcode_unparse (code), (int) code));
1421               valueFlags[nv] = code;
1422               nv++;
1423             }
1424         } end_allFlagCodes;
1425
1426       llassertprint (nv == NUMVALUEFLAGS,
1427                      ("Number of value flags: %d (expected %d)",
1428                       nv, (int) NUMVALUEFLAGS));
1429       initialized = TRUE;
1430     }
1431
1432   for (i = 0; i < NUMVALUEFLAGS; i++)
1433     {
1434       /* static valueFlags must be defined */
1435       /*@-usedef@*/
1436       /*drl bee: sta*/
1437       if (f == valueFlags[i]) /*@=usedef@*/
1438         {
1439           return i;
1440         }
1441     }
1442
1443   fprintf (stderr, "Cannot find value flag: %d", (int) f);
1444   exit (EXIT_FAILURE);
1445   /* Cannot do this...might call recursively...
1446   llfatalbug (message ("Cannot fine value flag: %d", (int) f));
1447   BADEXIT;
1448   */
1449 }
1450
1451 extern int flagcode_stringIndex (flagcode f)
1452 {
1453   /*@unchecked@*/ static bool initialized = FALSE;
1454   /*@unchecked@*/ static flagcode stringFlags[NUMSTRINGFLAGS];
1455   int i;
1456
1457
1458   if (!initialized)
1459     {
1460       int nv = 0;
1461
1462       allFlagCodes (code)
1463         {
1464           if (flagcode_hasString (code))
1465             {
1466               llassertprint (nv < NUMSTRINGFLAGS, ("Incorrect number of string flags: %d (need at least %d)", NUMSTRINGFLAGS, nv));
1467               stringFlags[nv] = code;
1468               nv++;
1469             }
1470         } end_allFlagCodes;
1471
1472       llassertprint (nv == NUMSTRINGFLAGS,
1473                      ("number of string flags: %d (expected %d)",
1474                       nv, NUMSTRINGFLAGS));
1475       initialized = TRUE;
1476     }
1477
1478   for (i = 0; i < NUMSTRINGFLAGS; i++)
1479     {
1480               /*drl bee: sta*/
1481       /*@-usedef@*/ if (f == stringFlags[i]) /*@=usedef@*/
1482         {
1483           return i;
1484         }
1485     }
1486
1487   llbug (message ("Bad string flag: %s", flagcode_unparse (f)));
1488   BADEXIT;
1489 }
1490
1491 bool flagcode_isNamePrefixFlag (flagcode f)
1492 {
1493   switch (f)
1494     {
1495     case FLG_MACROVARPREFIX:
1496     case FLG_TAGPREFIX:
1497     case FLG_ENUMPREFIX:
1498     case FLG_FILESTATICPREFIX:
1499     case FLG_GLOBPREFIX:
1500     case FLG_TYPEPREFIX:
1501     case FLG_EXTERNALPREFIX:
1502     case FLG_LOCALPREFIX:
1503     case FLG_UNCHECKEDMACROPREFIX:
1504     case FLG_CONSTPREFIX:
1505     case FLG_ITERPREFIX:
1506     case FLG_DECLPARAMPREFIX:
1507       return TRUE;
1508     default:
1509       return FALSE;
1510     }
1511 }
1512         
This page took 0.145259 seconds and 3 git commands to generate.