]> andersk Git - splint.git/blob - src/flags.c
Fixed up for win32 building (winconfig.h required)
[splint.git] / src / flags.c
1 /*
2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2002 University of Virginia,
4 **         Massachusetts Institute of Technology
5 **
6 ** This program is free software; you can redistribute it and/or modify it
7 ** under the terms of the GNU General Public License as published by the
8 ** Free Software Foundation; either version 2 of the License, or (at your
9 ** option) any later version.
10 ** 
11 ** This program is distributed in the hope that it will be useful, but
12 ** WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 ** General Public License for more details.
15 ** 
16 ** The GNU General Public License is available from http://www.gnu.org/ or
17 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18 ** MA 02111-1307, USA.
19 **
20 ** For information on splint: splint@cs.virginia.edu
21 ** To report a bug: splint-bug@cs.virginia.edu
22 ** For more information: http://www.splint.org
23 */
24 /*
25 ** flags.c
26 */
27
28 # include "splintMacros.nf"
29 # include "basic.h"
30 # include "portab.h"
31
32 /*
33 ** from the CC man page:
34 **
35 **  -Idir          Search for #include files whose names do not begin with a
36 **                    slash (/) in the following order: (1) in the directory of
37 **                    the dir argument, (2) in the directories specified by -I
38 **                    options, (3) in the standard directory (/usr/include).
39 */
40
41 /* needed for string literals literals */
42
43 typedef struct { 
44   flagkind kind;
45   /*@null@*/ /*@observer@*/ char *name;
46   /*@null@*/ /*@observer@*/ char *describe;
47 } flagcatinfo;
48
49 static flagcatinfo categories[] =
50 {
51   { FK_ABSTRACT, "abstract", "abstraction violations, representation access" } ,
52   { FK_ALIAS, "aliasing", "unexpected or dangerous aliasing" } ,
53   { FK_USE, "alluse", "all declarations are used" } ,
54   { FK_ANSI, "ansi", "violations of constraints imposed by ANSI/ISO standard" } ,
55   { FK_ARRAY, "arrays", "special checking involving arrays" } ,
56   { FK_BOOL, "booleans", "checking and naming of boolean types" } ,
57   { FK_COMMENTS, "comments", "warnings about (normal) comments" } ,
58   { FK_SYNCOMMENTS, "syncomments", "interpretation of annotation comments" } ,
59   { FK_COMPLETE, "complete", "completely defined, used, or specified system" } ,
60   { FK_CONTROL, "controlflow", "suspicious control structures" } ,
61   { FK_DEBUG, "debug", "flags for debugging splint" } ,
62   { FK_DECL, "declarations", "consistency of declarations" } ,
63   { FK_DEF, "definition", "undefined storage errors" } ,
64   { FK_DIRECT, "directories", "set directores" } ,
65   { FK_DISPLAY, "display", "control what is displayed" } ,
66   { FK_EFFECT, "effect", "statements with no effects" } ,
67   { FK_ERRORS, "errors", "control expected errors, summary reporting" } ,
68   { FK_EXPORT, "export", "control what may be exported" } ,
69   { FK_EXPOSURE, "exposure", "representation exposure" } ,
70   { FK_EXTENSIBLE, "extensible", "user-defined checks and annotations" },
71   { FK_FILES, "files", "control system files" } ,
72   { FK_FORMAT, "format", "control format of warning messages" } ,
73   { FK_GLOBALS, "globals", "use of global and file static variables" },
74   { FK_HEADERS, "headers", "control inclusion and generation of header files" },
75   { FK_HELP, "help", "on-line help" },
76   { FK_BOUNDS, "memorybounds", "out-of-bounds memory accesses" },
77   { FK_HINTS, "hints", "control display of warning hints" },
78   { FK_SYSTEMFUNCTIONS, "systemfunctions", "special properties of exit and main" },
79   { FK_IMPLICIT, "implicit", "control implicit annotations and interpretations" } ,
80   { FK_INIT, "initializations", "initialization files" } ,
81   { FK_ITER, "iterators", "checking iterator definitions and uses" } ,
82   { FK_LEAK, "leaks", "memory leaks" } ,
83   { FK_LIBS, "libraries", "loading and dumping of user and standard libraries" } ,
84   { FK_LIMITS, "limits", "violations of set limits" } ,
85   { FK_MACROS, "macros", "expansion, definition and use of macros" },
86   { FK_MEMORY, "memory", "memory management" } ,
87   { FK_MODIFIES, "modification", "modification errors" } ,
88   { FK_NAMES, "names", "naming conventions and limits" } ,
89   { FK_NULL, "null", "misuses of null pointers" } ,
90   { FK_NUMBERS, "numbers", "control type-checking of numeric types" } ,
91   { FK_OPS, "operations", "checking of primitive operations" } ,
92   { FK_PARAMS, "parameters", "function and macro parameters" } ,
93   { FK_SPEED, "performance", "speeding up checking" } ,
94   { FK_POINTER, "pointers", "pointers" } ,
95   { FK_PRED, "predicates", "condition test expressions" } ,
96   { FK_PREFIX, "prefixes", "set naming prefixes and control checking" } ,
97   { FK_PREPROC, "preproc", "defines and undefines for the preprocessor" } ,
98   { FK_PROTOS, "prototypes", "function prototypes" } ,
99   { FK_DEAD, "released", "using storage that has been deallocated" } ,
100   { FK_IGNORERET, "returnvals", "ignored return values" },
101   { FK_SECURITY, "security", "possible security vulnerability" },
102   { FK_SPEC, "specifications", "checks involving .lcl specifications" } ,
103   { FK_SUPPRESS, "suppress", "local and global suppression of messages" } ,
104   { FK_TYPEEQ, "typeequivalence", "control what types are equivalent" } ,
105   { FK_BEHAVIOR, "undefined", "code with undefined or implementation-defined behavior" } ,
106   { FK_UNRECOG, "unrecognized", "unrecognized identifiers" } ,
107   { FK_UNSPEC, "unconstrained", "checking in the presence of unconstrained functions" } ,
108   { FK_WARNUSE, "warnuse", "use of possibly problematic function" } ,
109   { FK_ITS4, "its4", "its4 compatibility flags (report warnings for uses of possibly insecure functions)" } ,
110   { FK_SYNTAX, NULL, NULL } ,
111   { FK_TYPE, NULL, NULL } ,
112   { FK_SECRET, NULL, NULL } ,
113   { FK_OBSOLETE, NULL, NULL } ,
114   { FK_NONE, NULL, NULL }  /* must be last */
115 } ; 
116
117 typedef enum {
118   ARG_NONE,
119   ARG_NUMBER,    /* number */
120   ARG_CHAR,      /* char */
121   ARG_STRING,    /* string */
122   ARG_FILE,      /* filename (also a string) */
123   ARG_DIRECTORY, /* directory (also a string) */
124   ARG_PATH,      /* path */
125   ARG_SPECIAL   /* ? */
126 } argcode;
127
128 static /*@observer@*/ cstring argcode_unparse (argcode arg)
129 {
130   switch (arg) 
131     {
132     case ARG_STRING: return cstring_makeLiteralTemp ("string"); 
133     case ARG_FILE: return cstring_makeLiteralTemp ("filename"); 
134     case ARG_DIRECTORY: return cstring_makeLiteralTemp ("directory");
135     case ARG_PATH: return cstring_makeLiteralTemp ("path"); 
136     case ARG_NUMBER: return cstring_makeLiteralTemp ("number");
137     case ARG_CHAR: return cstring_makeLiteralTemp ("character");
138     case ARG_NONE: 
139       BADBRANCH;
140     case ARG_SPECIAL:
141       BADBRANCH;
142     }
143 # 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           llmsg (message ("%q\n\n", describeFlag (el)));
472         } end_cstringSList_elements ;
473
474       cstringSList_free (fl);
475     }
476   else
477     {
478       allFlags (f)
479         {
480           if (f.code != INVALID_FLAG && f.main != FK_OBSOLETE)
481             {
482               if (mstring_isDefined (f.desc))
483                 {
484                   if (desc)
485                     {
486                       llmsg (message ("%s --- %s", cstring_fromChars (f.flag),
487                                       cstring_fromChars (f.desc)));
488                     }
489                 }
490             }
491         } end_allFlags;
492     }
493 }
494
495 void
496 printFlagManual (bool html)
497 {
498   /*
499   ** Prints all flags by category, in order they appear in flags.def
500   */
501
502   flagkind lastCategory = FK_NONE;
503
504   allFlags (f) {
505     cstring flagname;
506     cstring flagtype = cstring_undefined;
507
508     if (f.main != lastCategory)
509       {
510         if (html)
511           {
512             llmsg (message ("\n<h4>%s</h4>\n", categoryName (f.main)));
513           }
514         else
515           {
516             llmsg (message ("\n%s\n%s\n",
517                             categoryName (f.main),
518                             cstring_makeLiteralTemp ("===================================")));
519           }
520
521         lastCategory = f.main;
522       }
523
524     if (f.argtype == ARG_NONE || f.argtype == ARG_SPECIAL)
525       {
526         if (html) 
527           {
528             flagname = message ("<tt>%s</tt>", cstring_fromChars (f.flag));
529           }
530         else
531           {
532             flagname = cstring_fromCharsNew (f.flag);
533           }
534       }
535     else
536       {
537         if (flagcode_hasString (f.code)) 
538           {
539             if (html)
540               {
541                 flagname = message ("<tt>%s <em>&lt;%s&gt;</em></tt>",
542                                     cstring_fromChars (f.flag), argcode_unparse (f.argtype));
543               }
544             else
545               {
546                 flagname = message ("%s <%s>", cstring_fromChars (f.flag), argcode_unparse (f.argtype));
547               }
548             
549             if (cstring_isDefined (context_getString (f.code)))
550               {
551                 if (html)
552                   {
553                     flagname = message ("%q <font color=\"blue\">[%s]</font>", flagname,
554                                         context_getString (f.code));
555                   }
556                 else
557                   {
558                     flagname = message ("%q [%s]", flagname,
559                                         context_getString (f.code));
560                   }
561               }
562           }
563         else if (f.argtype == ARG_CHAR)
564           {
565             if (html)
566               {
567                 flagname = message ("<tt>%s <em>&lt;%s&gt;</em></tt> <font color=\"blue\">[%c]</font>",
568                                     cstring_fromChars (f.flag), argcode_unparse (f.argtype),
569                                     (char) context_getValue (f.code));
570               }
571             else
572               {
573                 flagname = message ("%s <%s> [%c]", cstring_fromChars (f.flag), argcode_unparse (f.argtype),
574                                     (char) context_getValue (f.code));
575               }
576           }
577         else 
578           {
579             llassert (f.argtype == ARG_NUMBER);
580
581             if (html)
582               {
583                 flagname = message ("<tt>%s <em>&lt;%s&gt;</em> <font color=\"blue\">[%d]</font>",
584                                     cstring_fromChars (f.flag), argcode_unparse (f.argtype),
585                                     context_getValue (f.code));
586               }
587             else
588               {
589                 flagname = message ("%s <%s> [%d]", cstring_fromChars (f.flag), argcode_unparse (f.argtype),
590                                     context_getValue (f.code));
591               }
592           }
593       }
594
595     if (f.isIdem)
596       {
597         if (html)
598           {
599             flagtype = message("%q<font color=\"green\">-</font>", flagtype);
600           }
601         else
602           {
603             flagtype = message("%q<->", flagtype);
604           }
605       }
606     
607     if (f.isGlobal)
608       {
609         if (html)
610           {
611             flagtype = message ("%q<font color=\"green\"><em>global</em></font>", flagtype);
612           }
613         else
614           {
615             flagtype = message ("%q<G>", flagtype);
616           }
617       }
618
619     if (f.isSpecial)
620       {
621         if (html)
622           {
623             flagtype = message ("%q<font color=\"orange\"><em>shortcut</em></font>", flagtype);
624           }
625         else
626           {
627             flagtype = message("%q<S>", flagtype);
628           }
629       }
630     
631     if (f.isModeFlag)
632       {
633         if (html)
634           {
635             flagtype = message ("%q mode:<tt>%q</tt>>", flagtype, getFlagModeSettings (f.code));
636           }
637         else
638           {
639             flagtype = message ("%q<M:%q>", flagtype, getFlagModeSettings (f.code));
640           }
641       }
642     else /* its a plain flag */
643       {
644         if (html)
645           {
646             flagtype = message ("%q plain:<tt>%s</tt>", flagtype,
647                                 cstring_makeLiteralTemp (context_getFlag (f.code) ? "+" : "-"));
648           }
649         else
650           {
651             flagtype = message ("%q<P:%s>", flagtype,
652                                 cstring_makeLiteralTemp (context_getFlag (f.code) ? "+" : "-"));
653           }
654       }
655     
656     llmsg (message ("%s: %s", flagname, flagtype));
657
658     if (html)
659       {
660         llgenindentmsgnoloc (cstring_makeLiteral ("<blockquote>"));
661       }
662
663     if (mstring_isDefined (f.hint))
664       {
665         llgenindentmsgnoloc (cstring_fromCharsNew (f.hint));
666       }
667     else
668       {
669         llgenindentmsgnoloc (message ("%q.", cstring_capitalize (cstring_fromChars (f.desc))));
670       }
671
672     if (html)
673       {
674         llgenindentmsgnoloc (cstring_makeLiteral ("</blockquote>"));
675       }
676   } end_allFlags ;
677 }
678
679 cstring
680 describeFlagCode (flagcode flag)
681 {
682   cstring ret = cstring_undefined;
683   fflag f;
684   
685   if (flagcode_isInvalid (flag))
686     {
687       return (cstring_makeLiteral ("<invalid>"));
688     }
689
690   context_resetAllFlags ();
691   
692   /*drl bee: mRug*/
693   f = flags[flag];
694   ret = cstring_copy (cstring_fromChars (f.desc));
695   
696   if (f.sub != FK_NONE)
697     {
698       ret = message ("%q\nCategories: %s, %s",
699                      ret, 
700                      categoryName (f.main),
701                      categoryName (f.sub));
702     }
703   else 
704     {
705       if (f.main != FK_NONE)
706         {
707           cstring cname = categoryName (f.main);
708           
709           if (cstring_isDefined (cname))
710             {
711               ret = message ("%q\nCategory: %s",
712                              ret, cname);
713             }
714         }
715     }
716   
717   if (f.isModeFlag)
718     {
719       ret = message ("%q\nMode Settings: %q",
720                      ret, getFlagModeSettings (flag));
721     }
722   else
723     {
724       ret = message ("%q\nDefault Setting: %s",
725                      ret, 
726                      cstring_makeLiteralTemp (context_getFlag (flag) ? "+" : "-"));
727     }
728   
729   if (f.isGlobal)
730     {
731       ret = message("%q\nSet globally only", ret);
732     }
733   else
734     {
735       ret = message("%q\nSet locally", ret);
736     }
737   
738   switch (f.argtype)
739     {
740     case ARG_NONE:
741     case ARG_SPECIAL:
742       break;
743     case ARG_NUMBER:
744       ret = message("%q\nNumeric Argument.  Default: %d",
745                     ret,
746                     context_getValue (flag));
747       break;
748     case ARG_CHAR:
749       ret = message("%q\nCharacter Argument.  Default: %h",
750                     ret, (char) context_getValue (flag));
751       break;
752     case ARG_STRING:
753     case ARG_FILE:
754     case ARG_PATH:
755     case ARG_DIRECTORY:
756       {
757       if (cstring_isDefined (context_getString (flag)))
758         {
759           ret = message("%q\n%q argument.  Default: %s",
760                         ret,
761                         cstring_capitalize (argcode_unparse (f.argtype)),
762                         context_getString (flag));
763         }
764       else
765         {
766           ret = message("%q\n%s argument.  No default.", 
767                         ret,
768                         cstring_capitalize (argcode_unparse (f.argtype)));
769         }
770       break;
771       }
772     }
773   
774   if (mstring_isDefined (f.hint))
775     {
776       ret = message("%q\n\3%s", ret, cstring_fromChars (f.hint));
777     }
778   
779   return ret;
780 }
781   
782 static cstring getFlagModeSettings (flagcode flag)
783 {
784   cstring res = cstring_undefined;
785   
786   allModes (mname)
787     {
788       context_setModeNoWarn (cstring_fromChars (mname));
789       
790       res = message ("%q%s", res, cstring_makeLiteralTemp (context_getFlag (flag) ? "+" : "-"));
791     } end_allModes;
792
793   return res;
794 }
795
796 cstring
797 describeFlag (cstring flagname)
798 {
799   cstring oflagname = cstring_copy (flagname);
800   flagcode f = flags_identifyFlag (flagname);
801
802   if (flagcode_isSkip (f))
803     {
804       cstring_free (oflagname);
805       return cstring_undefined;
806     }
807   else if (flagcode_isValid (f))
808     {
809       if (cstring_equal (flagname, oflagname))
810         {
811           cstring_free (oflagname);
812           return (message ("%s\n\3%q", flagname, describeFlagCode (f)));
813         }
814       else
815         {
816           return (message ("%q (standardized name: %s)\n\3%q",
817                            oflagname, flagname, describeFlagCode (f)));
818         }
819     }
820   else
821     {
822       if (isMode (flagname))
823         {
824           cstring_free (oflagname);
825
826           return
827             (message ("%s: predefined mode (see Manual for information)",
828                       flagname));
829         }
830       else
831         {
832           return (message ("%q: <invalid flag>", oflagname));
833         }
834     }
835 }
836
837 static cstringSList
838 sortedFlags (void)
839 {
840   cstringSList s = cstringSList_new ();
841
842   allFlags (f)
843     {
844       if (f.desc != NULL)
845         {
846           s = cstringSList_add (s, cstring_fromChars (f.flag));
847         }
848     } end_allFlags;
849
850   cstringSList_alphabetize (s);
851
852   return s;
853 }
854
855 void printAlphaFlags ()
856 {
857   cstringSList fl = sortedFlags ();
858
859   cstringSList_printSpaced (fl, 3, 1, context_getLineLen () - 25); 
860   cstringSList_free (fl);
861 }
862
863 /*@observer@*/ cstring
864 flagcode_unparse (flagcode code)
865 {
866   if (code == INVALID_FLAG)
867     {
868       return cstring_makeLiteralTemp ("<invalid flag>");
869     }
870
871   return cstring_fromChars (flags[code].flag);
872 }
873
874 /*
875 ** Transforms a flag into its cannonical form.
876 **
877 ** The following transformations are made:
878 **
879 **    function      -> fcn
880 **    variable      -> var
881 **    constant      -> const
882 **    iterator      -> iter
883 **    parameter     -> param
884 **    unrecognized  -> unrecog
885 **    qualifier     -> qual         
886 **    declaration   -> decl
887 **    globalias     -> (no change)
888 **    global        -> glob
889 **    modifies      -> mods
890 **    modify        -> mod
891 **    pointer       -> ptr
892 **    implies       -> imp
893 **    implicit      -> imp
894 **    implied       -> imp
895 **    unconstrained -> unspec       
896 **    unconst       -> unspec
897 **    memory        -> mem
898 **    length        -> len
899 */
900
901 static void
902 canonicalizeFlag (cstring s)
903 {
904   int i = 0;
905   static bn_mstring transform[] = 
906     { 
907       "function", "fcn",
908       "variable", "var",
909       "constant", "const",
910       "iterator", "iter",
911       "parameter", "param",
912       "unrecognized", "unrecog",
913       "qualifier", "qual",
914       "declaration", "decl",
915       "globals", "globs", 
916       "modifies", "mods", 
917       "modify", "mod",
918       "pointer", "ptr",
919       "implies", "imp",
920       "implicit", "imp",
921       "implied", "imp",
922       "unconstrained", "uncon",
923       "unconst", "uncon",
924       "memory", "mem",
925       "length", "len",
926       "return", "ret",
927       "system", "sys",
928       NULL
929       } ;
930   char *current;
931   
932   /*drl bee: ia*/
933   while ((current = transform[i]) != NULL)
934     {
935       if (cstring_containsLit (s, current))
936         {
937           cstring_replaceLit (s, current, transform[i+1]);
938         }
939       i += 2;
940     }
941
942   /* remove whitespace, -'s, and _'s */
943   cstring_stripChars (s, " -_");
944 }
945
946 flagcode
947 flags_identifyFlag (cstring s)
948 {
949   return flags_identifyFlagAux (s, FALSE);
950 }
951
952 flagcode
953 flags_identifyFlagQuiet (cstring s)
954 {
955   return flags_identifyFlagAux (s, TRUE);
956 }
957
958 static flagcode
959 flags_identifyFlagAux (cstring s, bool quiet)
960 {
961   if (cstring_length (s) == 0) {
962     /* evs 2000-06-25: A malformed flag. */
963     return INVALID_FLAG;
964   }
965
966   if (cstring_firstChar (s) == 'I')
967     {
968       return FLG_INCLUDEPATH; /* no space after -I */
969     }
970
971   if (cstring_firstChar (s) == 'S') 
972     {
973       return FLG_SPECPATH;    /* no space after -S */
974     }
975
976   if (cstring_firstChar (s) == 'D') 
977     {
978       return FLG_DEFINE;      /* no space after -D */
979     }
980
981   if (cstring_firstChar (s) == 'U') 
982     {
983       return FLG_UNDEFINE;    /* no space after -D */
984     }
985
986   canonicalizeFlag (s);
987
988   allFlags (f)
989     {
990       if (cstring_equal (cstring_fromChars (f.flag), s))
991         {
992           return (f.code);
993         }
994     } end_allFlags;
995
996   /*
997   ** Synonyms
998   */
999
1000   if (cstring_equalLit (s, "pred"))
1001     {
1002       return FLG_PREDBOOL;
1003     }
1004
1005   if (cstring_equalLit (s, "modobserverstrict"))
1006     {
1007       return FLG_MODOBSERVERUNCON;
1008     }
1009
1010   if (cstring_equalLit (s, "czechnames"))
1011     {
1012       return FLG_CZECH;
1013     }
1014
1015   if (cstring_equalLit (s, "slovaknames"))
1016     {
1017       return FLG_SLOVAK;
1018     }
1019
1020   if (cstring_equalLit (s, "czechoslovaknames"))
1021     {
1022       return FLG_CZECHOSLOVAK;
1023     }
1024
1025   if (cstring_equalLit (s, "globunspec")
1026            || cstring_equalLit (s, "globuncon"))
1027     {
1028       return FLG_GLOBUNSPEC;
1029     }
1030
1031   if (cstring_equalLit (s, "modglobsunspec")
1032            || cstring_equalLit (s, "modglobsuncon")
1033            || cstring_equalLit (s, "modglobsnomods"))
1034     {
1035       return FLG_MODGLOBSUNSPEC;
1036     }
1037
1038   if (cstring_equalLit (s, "export"))
1039     {
1040       return FLG_EXPORTANY;
1041     }
1042
1043   if (cstring_equalLit (s, "macrospec"))
1044     {
1045       return FLG_MACRODECL;
1046     }
1047   
1048   if (cstring_equalLit (s, "ansireservedlocal"))
1049     {
1050       return FLG_ANSIRESERVEDLOCAL;
1051     }
1052
1053   if (cstring_equalLit (s, "warnposix"))
1054     {
1055       return FLG_WARNPOSIX;
1056     }
1057
1058   if (cstring_equalLit (s, "defuse"))
1059     {
1060       return FLG_USEDEF;
1061     }
1062
1063   if (cstring_equalLit (s, "macroundef"))
1064     {
1065       return FLG_MACROUNDEF;
1066     }
1067
1068   if (cstring_equalLit (s, "showcol"))
1069     {
1070       return FLG_SHOWCOL;
1071     }
1072
1073   if (cstring_equalLit (s, "intbool"))
1074     {
1075       return FLG_BOOLINT;
1076     }
1077
1078   if (cstring_equalLit (s, "intchar"))
1079     {
1080       return FLG_CHARINT;
1081     }
1082
1083   if (cstring_equalLit (s, "intenum"))
1084     {
1085       return FLG_ENUMINT;
1086     }
1087
1088   /*
1089   ** Backwards compatibility for our American friends...
1090   */
1091
1092   if (cstring_equalLit (s, "ansilib"))
1093     {
1094       return FLG_ANSILIB;
1095     }
1096
1097   if (cstring_equalLit (s, "ansistrictlib"))
1098     {
1099       return FLG_STRICTLIB;
1100     }
1101
1102   if (cstring_equalLit (s, "skipansiheaders"))
1103     {
1104       return FLG_SKIPANSIHEADERS;
1105     }
1106
1107   if (cstring_equalLit (s, "ansireserved"))
1108     {
1109       return FLG_ANSIRESERVED;
1110     }
1111
1112   if (cstring_equalLit (s, "ansireservedinternal"))
1113     {
1114       return FLG_ANSIRESERVEDLOCAL;
1115     }
1116
1117   /*
1118   ** Obsolete Flags
1119   */
1120   
1121   if (cstring_equalLit (s, "accessunspec"))
1122     {
1123       if (!quiet) 
1124         {
1125           llerror_flagWarning 
1126             (cstring_makeLiteral
1127              ("accessunspec flag is no longer supported.  It has been replaced by accessmodule, accessfile and "
1128               "accessfunction to provide more precise control of accessibility "
1129               "of representations.  For more information, "
1130               "see splint -help accessmodule"));
1131         }
1132       
1133       return SKIP_FLAG;
1134     }
1135   else if (cstring_equalLit (s, "ansilimits"))
1136     {
1137           llerror_flagWarning 
1138             (cstring_makeLiteral
1139              ("ansilimits flag is no longer supported.  It has been replaced by ansi89limits and "
1140               "iso99limits to select either the lower translation limits imposed by the ANSI89 "
1141               "standard or the typically higher limits prescribed by ISO C99."));
1142
1143       return SKIP_FLAG;
1144     }
1145   else if (cstring_equalLit (s, "staticmods"))
1146     {
1147       if (!quiet) 
1148         {
1149           llerror_flagWarning 
1150             (cstring_makeLiteral
1151              ("staticmods flag is obsolete.  You probably "
1152               "want impcheckmodstatics.  For more information, "
1153               "see splint -help impcheckmodstatics"));
1154         }
1155
1156       return SKIP_FLAG;
1157     }
1158   else if (cstring_equalLit (s, "bool"))
1159     {
1160       if (!quiet) 
1161         {
1162           llerror_flagWarning
1163             (cstring_makeLiteral ("bool flag is obsolete.  It never really "
1164                                   "made sense in the first place."));
1165         }
1166       
1167       return SKIP_FLAG;
1168     }
1169   else if (cstring_equalLit (s, "shiftsigned"))
1170     {
1171       if (!quiet) 
1172         {
1173           llerror_flagWarning
1174             (cstring_makeLiteral ("shiftsigned flag is obsolete.  You probably "
1175                                   "want bitwisesigned, shiftnegative or shiftsize."));
1176         }
1177       
1178       return SKIP_FLAG;
1179     }
1180   else if (cstring_equalLit (s, "ansi"))
1181     {
1182       if (!quiet) 
1183         {
1184           llerror_flagWarning
1185             (cstring_makeLiteral ("ansi flag is obsolete.  You probably "
1186                                   "want noparams and/or oldstyle."));
1187         }
1188       
1189       return SKIP_FLAG;
1190     }
1191   else if (cstring_equalLit (s, "stdio"))
1192     {
1193       if (!quiet) 
1194         {
1195           llerror_flagWarning 
1196             (cstring_makeLiteral
1197              ("stdio flag is obsolete.  You may "
1198               "want strictlib or one of the gloabls "
1199               "checking flags.  For more information, "
1200               "see splint -help strictlib or splint -help flags globals"));
1201         }
1202       
1203       return SKIP_FLAG;
1204     }
1205   else
1206     {
1207       return INVALID_FLAG;
1208     }
1209 }
1210
1211 void setValueFlag (flagcode opt, cstring arg)
1212 {
1213   switch (opt)
1214     {
1215     case FLG_EXPECT:
1216     case FLG_LCLEXPECT:
1217     case FLG_LIMIT:  
1218     case FLG_LINELEN:
1219     case FLG_INDENTSPACES:
1220     case FLG_BUGSLIMIT:
1221     case FLG_EXTERNALNAMELEN:
1222     case FLG_INTERNALNAMELEN:
1223     case FLG_CONTROLNESTDEPTH:
1224     case FLG_STRINGLITERALLEN:
1225     case FLG_NUMSTRUCTFIELDS:
1226     case FLG_NUMENUMMEMBERS:
1227     case FLG_INCLUDENEST:
1228       {
1229         int val = cstring_toPosInt (arg);
1230
1231         if (val < 0)
1232           {
1233             llerror 
1234               (FLG_BADFLAG,
1235                message 
1236                ("Flag %s must be followed by a positive number number.  "
1237                 "Followed by %s",
1238                 flagcode_unparse (opt), arg));
1239           }
1240         else
1241           {
1242             context_setValueAndFlag (opt, val);
1243           }
1244       }
1245       break;
1246     case FLG_COMMENTCHAR:
1247       {
1248         if (cstring_length (arg) != 1)
1249           {
1250             llfatalerrorLoc
1251               (message
1252                ("Flag %s should be followed by a single character.  Followed by %s",
1253                 flagcode_unparse (opt), arg));
1254           }
1255         else
1256           {
1257             context_setCommentMarkerChar (cstring_firstChar (arg));
1258           }
1259       }
1260       break;
1261     BADDEFAULT;
1262     }
1263 }
1264
1265 void setStringFlag (flagcode opt, /*@only@*/ cstring arg)
1266 {
1267   switch (opt)
1268     {
1269     case FLG_TMPDIR:
1270       {
1271         if (cstring_lastChar (arg) == CONNECTCHAR)
1272           {
1273             context_setString (opt, arg);
1274           }
1275         else
1276           {
1277             context_setString (opt, cstring_appendChar (arg, CONNECTCHAR));
1278           }
1279         break;
1280       }
1281     default:
1282       {
1283         context_setString (opt, arg);
1284         break;
1285       }
1286     }
1287 }
1288
1289 cstring
1290 describeModes ()
1291 {
1292   cstring s = cstring_makeLiteral ("Flag                    ");
1293   cstringSList sflags = sortedFlags ();
1294
1295   allModes (modename)
1296     {
1297       s = message ("%q%9s", s, cstring_fromChars (modename));
1298     } end_allModes;
1299   
1300   s = message ("%q\n", s);
1301
1302   cstringSList_elements (sflags, flagname)
1303     {
1304       flagcode code = flags_identifyFlag (flagname);
1305       fflag currentflag = flags[code];
1306       
1307       if (mstring_isDefined (currentflag.desc) && flagcode_isModeFlag (code))
1308         {
1309           s = message ("%q\n%27s", s, 
1310                        cstring_fromChars (currentflag.flag));
1311           
1312           allModes (modename)
1313             {
1314               context_setMode (cstring_fromChars (modename));
1315               
1316               if (context_getFlag (code))
1317                 {
1318                   s = message ("%q%9s", s, cstring_makeLiteralTemp ("+"));
1319                 }
1320               else
1321                 {
1322                   s = message ("%q%9s", s, cstring_makeLiteralTemp (" "));
1323                 }
1324
1325               context_resetModeFlags ();
1326             } end_allModes;
1327         }
1328     } end_cstringSList_elements;
1329   
1330   cstringSList_free (sflags);
1331
1332   s = cstring_appendChar (s, '\n');
1333
1334   return (s);
1335 }
1336
1337 # if 0
1338 static /*@unused@*/ cstring
1339 listModes (void)
1340 {
1341   cstring s = cstring_makeLiteral ("\t");
1342   int i = 0;
1343
1344   allModes (modename)
1345     {
1346       if (i != 0 && (i % 4 == 0))
1347         {
1348           s = message ("%q\n\t%15s", s, cstring_fromChars (modename));
1349         }
1350       else
1351         {
1352           s = message ("%q%15s", s, cstring_fromChars (modename));
1353         }
1354       i++;
1355     } end_allModes;
1356
1357   return s;
1358 }
1359 # endif
1360
1361 bool
1362 isMode (cstring s)
1363 {
1364   allModes (modename)
1365     {
1366       if (mstring_isDefined (modename))
1367         {
1368           if (cstring_equalLit (s, modename))
1369             {
1370               return TRUE;
1371             }
1372         }
1373      } end_allModes;
1374
1375   return FALSE;
1376 }
1377
1378 extern bool flagcode_hasArgument (flagcode f)
1379 {
1380   return (flags[f].argtype != ARG_NONE);
1381 }
1382
1383 extern bool flagcode_hasNumber (flagcode f)
1384 {
1385   return (flags[f].argtype == ARG_NUMBER);
1386 }
1387
1388 extern bool flagcode_hasChar (flagcode f)
1389 {
1390   return (flags[f].argtype == ARG_CHAR);
1391 }
1392
1393 extern bool flagcode_hasString (flagcode f)
1394 {
1395   return (flags[f].argtype == ARG_STRING
1396           || flags[f].argtype == ARG_FILE
1397           || flags[f].argtype == ARG_DIRECTORY
1398           || flags[f].argtype == ARG_PATH);
1399 }
1400
1401 extern int flagcode_valueIndex (flagcode f)
1402 {
1403   /*@unchecked@*/ static bool initialized = FALSE;
1404   int i;
1405   /*@unchecked@*/ static flagcode valueFlags[NUMVALUEFLAGS];
1406   
1407   if (!initialized)
1408     {
1409       int nv = 0;
1410
1411       allFlagCodes (code)
1412         {
1413           if (flagcode_hasNumber (code) || flagcode_hasChar (code))
1414             {
1415               llassert (nv < NUMVALUEFLAGS);
1416               DPRINTF (("Value flag: %s [%d]", flagcode_unparse (code), (int) code));
1417               valueFlags[nv] = code;
1418               nv++;
1419             }
1420         } end_allFlagCodes;
1421
1422       llassertprint (nv == NUMVALUEFLAGS,
1423                      ("Number of value flags: %d (expected %d)",
1424                       nv, (int) NUMVALUEFLAGS));
1425       initialized = TRUE;
1426     }
1427
1428   for (i = 0; i < NUMVALUEFLAGS; i++)
1429     {
1430       /* static valueFlags must be defined */
1431       /*@-usedef@*/
1432       /*drl bee: sta*/
1433       if (f == valueFlags[i]) /*@=usedef@*/
1434         {
1435           return i;
1436         }
1437     }
1438
1439   fprintf (stderr, "Cannot find value flag: %d", (int) f);
1440   exit (EXIT_FAILURE);
1441   /* Cannot do this...might call recursively...
1442   llfatalbug (message ("Cannot fine value flag: %d", (int) f));
1443   BADEXIT;
1444   */
1445 }
1446
1447 extern int flagcode_stringIndex (flagcode f)
1448 {
1449   /*@unchecked@*/ static bool initialized = FALSE;
1450   /*@unchecked@*/ static flagcode stringFlags[NUMSTRINGFLAGS];
1451   int i;
1452
1453
1454   if (!initialized)
1455     {
1456       int nv = 0;
1457
1458       allFlagCodes (code)
1459         {
1460           if (flagcode_hasString (code))
1461             {
1462               llassertprint (nv < NUMSTRINGFLAGS, ("Incorrect number of string flags: %d (need at least %d)", NUMSTRINGFLAGS, nv));
1463               stringFlags[nv] = code;
1464               nv++;
1465             }
1466         } end_allFlagCodes;
1467
1468       llassertprint (nv == NUMSTRINGFLAGS,
1469                      ("number of string flags: %d (expected %d)",
1470                       nv, NUMSTRINGFLAGS));
1471       initialized = TRUE;
1472     }
1473
1474   for (i = 0; i < NUMSTRINGFLAGS; i++)
1475     {
1476               /*drl bee: sta*/
1477       /*@-usedef@*/ if (f == stringFlags[i]) /*@=usedef@*/
1478         {
1479           return i;
1480         }
1481     }
1482
1483   llbug (message ("Bad string flag: %s", flagcode_unparse (f)));
1484   BADEXIT;
1485 }
1486
1487 bool flagcode_isNamePrefixFlag (flagcode f)
1488 {
1489   switch (f)
1490     {
1491     case FLG_MACROVARPREFIX:
1492     case FLG_TAGPREFIX:
1493     case FLG_ENUMPREFIX:
1494     case FLG_FILESTATICPREFIX:
1495     case FLG_GLOBPREFIX:
1496     case FLG_TYPEPREFIX:
1497     case FLG_EXTERNALPREFIX:
1498     case FLG_LOCALPREFIX:
1499     case FLG_UNCHECKEDMACROPREFIX:
1500     case FLG_CONSTPREFIX:
1501     case FLG_ITERPREFIX:
1502     case FLG_DECLPARAMPREFIX:
1503       return TRUE;
1504     default:
1505       return FALSE;
1506     }
1507 }
1508         
This page took 0.83966 seconds and 5 git commands to generate.