]> andersk Git - splint.git/blob - src/flags.c
Fixed -help <mode> bug.
[splint.git] / src / flags.c
1 /*
2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2003 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 "osd.h"
31 # include "rcfiles.h"
32 # include "lslinit.h"
33 # include "llmain.h"
34
35 /*
36 ** from the CC man page:
37 **
38 **  -Idir          Search for #include files whose names do not begin with a
39 **                    slash (/) in the following order: (1) in the directory of
40 **                    the dir argument, (2) in the directories specified by -I
41 **                    options, (3) in the standard directory (/usr/include).
42 */
43
44 /* needed for string literals literals */
45
46 typedef struct { 
47   flagkind kind;
48   /*@null@*/ /*@observer@*/ char *name;
49   /*@null@*/ /*@observer@*/ char *describe;
50 } flagcatinfo;
51
52 static flagcatinfo categories[] =
53 {
54   { FK_ABSTRACT, "abstract", "abstraction violations, representation access" } ,
55   { FK_ALIAS, "aliasing", "unexpected or dangerous aliasing" } ,
56   { FK_USE, "alluse", "all declarations are used" } ,
57   { FK_ANSI, "ansi", "violations of constraints imposed by ANSI/ISO standard" } ,
58   { FK_ARRAY, "arrays", "special checking involving arrays" } ,
59   { FK_BOOL, "booleans", "checking and naming of boolean types" } ,
60   { FK_COMMENTS, "comments", "warnings about (normal) comments" } ,
61   { FK_SYNCOMMENTS, "syncomments", "interpretation of annotation comments" } ,
62   { FK_COMPLETE, "complete", "completely defined, used, or specified system" } ,
63   { FK_CONTROL, "controlflow", "suspicious control structures" } ,
64   { FK_DEBUG, "debug", "flags for debugging splint" } ,
65   { FK_DECL, "declarations", "consistency of declarations" } ,
66   { FK_DEF, "definition", "undefined storage errors" } ,
67   { FK_DIRECT, "directories", "set directores" } ,
68   { FK_DISPLAY, "display", "control what is displayed" } ,
69   { FK_EFFECT, "effect", "statements with no effects" } ,
70   { FK_ERRORS, "errors", "control expected errors, summary reporting" } ,
71   { FK_EXPORT, "export", "control what may be exported" } ,
72   { FK_EXPOSURE, "exposure", "representation exposure" } ,
73   { FK_EXTENSIBLE, "extensible", "user-defined checks and annotations" },
74   { FK_FILES, "files", "control system files" } ,
75   { FK_FORMAT, "format", "control format of warning messages" } ,
76   { FK_GLOBALS, "globals", "use of global and file static variables" },
77   { FK_HEADERS, "headers", "control inclusion and generation of header files" },
78   { FK_HELP, "help", "on-line help" },
79   { FK_BOUNDS, "memorybounds", "out-of-bounds memory accesses" },
80   { FK_HINTS, "hints", "control display of warning hints" },
81   { FK_SYSTEMFUNCTIONS, "systemfunctions", "special properties of exit and main" },
82   { FK_IMPLICIT, "implicit", "control implicit annotations and interpretations" } ,
83   { FK_INIT, "initializations", "initialization files" } ,
84   { FK_ITER, "iterators", "checking iterator definitions and uses" } ,
85   { FK_LEAK, "leaks", "memory leaks" } ,
86   { FK_LIBS, "libraries", "loading and dumping of user and standard libraries" } ,
87   { FK_LIMITS, "limits", "violations of set limits" } ,
88   { FK_MACROS, "macros", "expansion, definition and use of macros" },
89   { FK_MEMORY, "memory", "memory management" } ,
90   { FK_MODIFIES, "modification", "modification errors" } ,
91   { FK_NAMES, "names", "naming conventions and limits" } ,
92   { FK_NULL, "null", "misuses of null pointers" } ,
93   { FK_NUMBERS, "numbers", "control type-checking of numeric types" } ,
94   { FK_OPS, "operations", "checking of primitive operations" } ,
95   { FK_PARAMS, "parameters", "function and macro parameters" } ,
96   { FK_SPEED, "performance", "speeding up checking" } ,
97   { FK_POINTER, "pointers", "pointers" } ,
98   { FK_PRED, "predicates", "condition test expressions" } ,
99   { FK_PREFIX, "prefixes", "set naming prefixes and control checking" } ,
100   { FK_PREPROC, "preproc", "defines and undefines for the preprocessor" } ,
101   { FK_PROTOS, "prototypes", "function prototypes" } ,
102   { FK_DEAD, "released", "using storage that has been deallocated" } ,
103   { FK_IGNORERET, "returnvals", "ignored return values" },
104   { FK_SECURITY, "security", "possible security vulnerability" },
105   { FK_SPEC, "specifications", "checks involving .lcl specifications" } ,
106   { FK_SUPPRESS, "suppress", "local and global suppression of messages" } ,
107   { FK_TYPEEQ, "typeequivalence", "control what types are equivalent" } ,
108   { FK_BEHAVIOR, "undefined", "code with undefined or implementation-defined behavior" } ,
109   { FK_UNRECOG, "unrecognized", "unrecognized identifiers" } ,
110   { FK_UNSPEC, "unconstrained", "checking in the presence of unconstrained functions" } ,
111   { FK_WARNUSE, "warnuse", "use of possibly problematic function" } ,
112   { FK_ITS4, "its4", "its4 compatibility flags (report warnings for uses of possibly insecure functions)" } ,
113   { FK_SYNTAX, NULL, NULL } ,
114   { FK_TYPE, NULL, NULL } ,
115   { FK_SECRET, NULL, NULL } ,
116   { FK_OBSOLETE, NULL, NULL } ,
117   { FK_NONE, NULL, NULL }  /* must be last */
118 } ; 
119
120 typedef enum {
121   ARG_NONE,
122   ARG_NUMBER,    /* number */
123   ARG_CHAR,      /* char */
124   ARG_STRING,    /* string */
125   ARG_FILE,      /* filename (also a string) */
126   ARG_DIRECTORY, /* directory (also a string) */
127   ARG_PATH,      /* path */
128   ARG_SPECIAL   /* ? */
129 } argcode;
130
131 # ifdef WIN32
132 /* Make Microsoft VC++ happy */
133 # pragma warning (disable:4715)
134 # endif
135
136 static /*@observer@*/ cstring argcode_unparse (argcode arg)
137 {
138   switch (arg) 
139     {
140     case ARG_STRING: return cstring_makeLiteralTemp ("string"); 
141     case ARG_FILE: return cstring_makeLiteralTemp ("filename"); 
142     case ARG_DIRECTORY: return cstring_makeLiteralTemp ("directory");
143     case ARG_PATH: return cstring_makeLiteralTemp ("path"); 
144     case ARG_NUMBER: return cstring_makeLiteralTemp ("number");
145     case ARG_CHAR: return cstring_makeLiteralTemp ("character");
146     case ARG_NONE: 
147       BADBRANCH;
148     case ARG_SPECIAL:
149       BADBRANCH;
150     }
151 }      
152
153 # ifdef WIN32
154 # pragma warning (default : 4715)
155 # endif
156
157 typedef struct { 
158   flagkind main;
159   flagkind sub;
160   bool isSpecial;  /* setting this flag may set other flags (or values) */
161   bool isIdem;     /* idempotent - always sets to TRUE */
162   bool isGlobal;   /* cannot be set locally (using control comments) */
163   bool isModeFlag; /* set by modes */
164   argcode argtype;
165   /*@observer@*/ char *flag;
166   flagcode code; 
167   /*@observer@*/ /*@null@*/ char *desc;
168   bn_mstring hint; 
169   int nreported; 
170   int nsuppressed; 
171 } fflag;
172
173 typedef fflag flaglist[];
174
175 # include "flags.def"
176
177 /*@iter allFlags (yield observer fflag f); @*/
178 # define allFlags(m_f) \
179   { /*@+enumint@*/ flagcode m_i; for (m_i = 0; m_i < NUMFLAGS; m_i++) { fflag m_f = flags[m_i]; /*@=enumint@*/
180 # define end_allFlags }}
181
182 static bn_mstring mode_names[] =
183
184   "weak", "standard", "checks", "strict", NULL, 
185 };
186
187 /*@iter allModes (yield bn_mstring modename)@*/
188 # define allModes(m_m) \
189   { int m_ii = 0; while (mstring_isDefined (mode_names[m_ii])) \
190       { bn_mstring m_m = mode_names[m_ii]; m_ii++; 
191
192 # define end_allModes }}
193
194 /*@+enumint@*/
195
196 static cstring getFlagModeSettings (flagcode p_flag) /*@modifies internalState@*/ ;
197 static cstring describeFlagCode (flagcode p_flag) /*@*/ ;
198 static cstringSList sortedFlags (void) /*@*/ ;
199 static /*@observer@*/ cstring categoryName (flagkind p_kind) /*@*/ ;
200
201 static flagcode flags_identifyFlagAux (cstring p_s, bool p_quiet) /*@modifies g_warningstream@*/ ;
202
203 # if 0
204 static /*@unused@*/ cstring listModes (void) /*@*/ ;
205 # endif
206
207 bool flagcode_isSpecialFlag (flagcode f)
208 {
209   return (flags[f].isSpecial);
210 }
211
212 bool flagcode_isGlobalFlag (flagcode f)
213 {
214   return (flags[f].isGlobal);
215 }
216
217 bool flagcode_isIdemFlag (flagcode f)
218 {
219   return (flags[f].isIdem);
220 }
221
222 bool flagcode_isModeFlag (flagcode f)
223 {
224   return (flags[f].isModeFlag);
225 }
226
227 bool flagcode_isNameChecksFlag (flagcode f)
228 {
229   return (flags[f].main == FK_NAMES);
230 }
231
232 bool flagcode_isHelpFlag (flagcode f)
233 {
234   return f == FLG_HELP;
235 }
236
237 bool flagcode_isMessageControlFlag (flagcode f)
238 {
239   /*
240   ** True if opt controls the display of messages.
241   ** These flags must be processed first.
242   */
243
244   return (f == FLG_SHOWSCAN 
245           || f == FLG_WARNRC 
246           || f == FLG_PARENFILEFORMAT
247           || f == FLG_MESSAGESTREAMSTDERR
248           || f == FLG_MESSAGESTREAMSTDOUT
249           || f == FLG_WARNINGSTREAMSTDERR
250           || f == FLG_WARNINGSTREAMSTDOUT
251           || f == FLG_ERRORSTREAMSTDERR
252           || f == FLG_ERRORSTREAMSTDOUT
253           || f == FLG_MESSAGESTREAM
254           || f == FLG_WARNINGSTREAM
255           || f == FLG_ERRORSTREAM
256           || f == FLG_STREAMOVERWRITE);
257 }
258
259 /*
260 ** Internal consistency check on the flags.
261 */
262
263 void flags_initMod ()
264 {
265   allFlagCodes (code)
266     {
267       /*@+enumint@*/
268       if (flags[code].code != code)
269         {
270           fprintf (stderr, 
271                    "*** ERROR: inconsistent flag %s / %d / %d", 
272                    flags[code].flag,
273                    flags[code].code, code);
274           
275           llbug (message ("*** ERROR: inconsistent flag %s / %d / %d", 
276                           cstring_fromChars (flags[code].flag),
277                           flags[code].code, code));
278         }
279       /*@=enumint@*/
280     } end_allFlagCodes;
281 }
282
283 void
284 summarizeErrors ()
285 {
286   bool hadOne = FALSE;
287   int sumrep = 0;
288   int sumsup = 0;
289
290   char *buf = mstring_create (128);
291
292   allFlags (f)
293     {
294       if (f.nreported > 0 || f.nsuppressed > 0)
295         {
296           int nrep = f.nreported;
297           int nsup = f.nsuppressed;
298           cstring fs = cstring_fill (cstring_fromChars (f.flag), 23);
299
300           if (!hadOne)
301             {
302               llmsgplain (cstring_makeLiteral
303                           ("\nError Type                Reported  Suppressed\n"
304                            "===================       ========  ========="));
305               hadOne = TRUE;
306             }
307
308           (void) snprintf (buf, 128, "%s%7d   %9d", cstring_toCharsSafe (fs), nrep, nsup);
309
310           sumrep += nrep;
311           sumsup += nsup;
312           
313           cstring_free (fs);
314           llmsg (cstring_copy (cstring_fromChars (buf)));
315         }
316     } end_allFlags;
317
318   if (hadOne)
319     {
320       cstring ts = cstring_fill (cstring_makeLiteralTemp ("Total"), 23);
321
322       llmsglit ("                          ========  =========");
323
324       (void) snprintf (buf, 128, "%s%7d   %9d", cstring_toCharsSafe (ts), sumrep, sumsup);
325       cstring_free (ts);
326       llmsgplain (cstring_copy (cstring_fromChars (buf)));
327     }
328
329   sfree (buf);
330 }
331
332 /*@+enumindex@*/
333
334 void
335 flagcode_recordError (flagcode f)
336 {
337   if (f != INVALID_FLAG)
338     {
339       if (f == FLG_WARNFLAGS)
340         {
341           ; /* don't count these */
342         }
343       else
344         {
345           flags[f].nreported = flags[f].nreported + 1;
346         }
347     }
348   else
349     {
350       llcontbug (message ("flagcode_recordError: invalid flag: %d", (int) f));
351     }
352 }
353
354 void
355 flagcode_recordSuppressed (flagcode f)
356 {
357   llassertprint (f != INVALID_FLAG, ("flagcode: %s", flagcode_unparse (f)));
358
359   flags[f].nsuppressed = flags[f].nsuppressed + 1;
360 }
361
362 int
363 flagcode_numReported (flagcode f)
364 {
365   llassert (f != INVALID_FLAG);
366
367   return (flags[f].nreported);
368 }
369
370 /*@observer@*/ cstring
371 flagcodeHint (flagcode f)
372 {
373   llassert (f != INVALID_FLAG);
374
375   if (mstring_isDefined (flags[f].hint))
376     {
377       return (cstring_fromChars (flags[f].hint));
378     }
379   else
380     {
381       return (cstring_fromChars (flags[f].desc));
382     }
383 }
384
385 static int categorySize (flagkind kind) /*@*/ 
386 {
387   int n = 0;
388
389   
390   allFlags (f)
391     {
392       if (f.main == kind || f.sub == kind)
393         {
394                   n++;
395         }
396     } end_allFlags;
397
398   return n;
399 }
400
401 flagkind identifyCategory (cstring s)
402 {
403   int i;
404
405   for (i = 0; categories[i].kind != FK_NONE; i++)
406     {
407       if (mstring_isDefined (categories[i].name))
408         {
409           if (cstring_equalLit (s, categories[i].name))
410             {
411               return categories[i].kind;
412             }
413         }
414     }
415
416   return FK_NONE;
417 }
418
419 static /*@observer@*/ cstring categoryName (flagkind kind)
420 {
421   int i;
422
423   for (i = 0; categories[i].kind != FK_NONE; i++)
424     {
425       if (categories[i].kind == kind)
426         {
427           return (cstring_fromChars (categories[i].name));
428         }
429     }
430   
431   return (cstring_makeLiteralTemp ("<No Category>"));
432 }
433
434 static int categoryIndex (flagkind kind)
435 {
436   int i;
437
438   for (i = 0; categories[i].kind != FK_NONE; i++)
439     {
440       if (categories[i].kind == kind)
441         {
442           return i;
443         }
444     }
445
446   return -1;
447 }
448
449 void printCategory (flagkind kind)
450 {
451   int index = categoryIndex (kind);
452
453   llassert (index >= 0);
454   llmsg (message ("%s (%d flags)\n\3%s\n\n", 
455                   cstring_fromChars (categories[index].name), 
456                   categorySize (kind),
457                   cstring_fromChars (categories[index].describe)));
458
459   allFlags (f)
460     {
461       if (f.main == kind || f.sub == kind)
462         {
463           llmsg (message ("   %s\n\6%q", cstring_fromChars (f.flag), 
464                           describeFlagCode (f.code)));
465         }
466     } end_allFlags;
467 }
468
469 void 
470 listAllCategories (void)
471 {
472   int i;
473
474   for (i = 0; categories[i].kind != FK_NONE; i++)
475     {
476       flagkind kind = categories[i].kind ;
477
478       if (categories[i].describe != NULL)
479         {
480           llmsg (message ("%s (%d flags)\n\3%s", 
481                           categoryName (kind), 
482                           categorySize (kind),
483                           cstring_fromChars (categories[i].describe)));
484         }
485     }
486 }
487
488 void
489 printAllFlags (bool desc, bool full)
490 {
491   if (full)
492     {
493       cstringSList fl = sortedFlags ();
494
495       cstringSList_elements (fl, el)
496         {
497           cstring tmp;
498           tmp = cstring_copy(el);
499           llmsg (message ("%q\n\n", describeFlag (tmp)));
500           cstring_free(tmp);
501         } end_cstringSList_elements ;
502
503       cstringSList_free (fl);
504     }
505   else
506     {
507       allFlags (f)
508         {
509           if (f.code != INVALID_FLAG && f.main != FK_OBSOLETE)
510             {
511               if (mstring_isDefined (f.desc))
512                 {
513                   if (desc)
514                     {
515                       llmsg (message ("%s --- %s", cstring_fromChars (f.flag),
516                                       cstring_fromChars (f.desc)));
517                     }
518                 }
519             }
520         } end_allFlags;
521     }
522 }
523
524 void
525 printFlagManual (bool html)
526 {
527   /*
528   ** Prints all flags by category, in order they appear in flags.def
529   */
530
531   flagkind lastCategory = FK_NONE;
532
533   allFlags (f) {
534     cstring flagname;
535     cstring flagtype = cstring_undefined;
536
537     if (f.main != lastCategory)
538       {
539         if (html)
540           {
541             llmsg (message ("\n<h4>%s</h4>\n", categoryName (f.main)));
542           }
543         else
544           {
545             llmsg (message ("\n%s\n%s\n",
546                             categoryName (f.main),
547                             cstring_makeLiteralTemp ("===================================")));
548           }
549
550         lastCategory = f.main;
551       }
552
553     if (f.argtype == ARG_NONE || f.argtype == ARG_SPECIAL)
554       {
555         if (html) 
556           {
557             flagname = message ("<tt>%s</tt>", cstring_fromChars (f.flag));
558           }
559         else
560           {
561             flagname = cstring_fromCharsNew (f.flag);
562           }
563       }
564     else
565       {
566         if (flagcode_hasString (f.code)) 
567           {
568             if (html)
569               {
570                 flagname = message ("<tt>%s <em>&lt;%s&gt;</em></tt>",
571                                     cstring_fromChars (f.flag), argcode_unparse (f.argtype));
572               }
573             else
574               {
575                 flagname = message ("%s <%s>", cstring_fromChars (f.flag), argcode_unparse (f.argtype));
576               }
577             
578             if (cstring_isDefined (context_getString (f.code)))
579               {
580                 if (html)
581                   {
582                     flagname = message ("%q <font color=\"blue\">[%s]</font>", flagname,
583                                         context_getString (f.code));
584                   }
585                 else
586                   {
587                     flagname = message ("%q [%s]", flagname,
588                                         context_getString (f.code));
589                   }
590               }
591           }
592         else if (f.argtype == ARG_CHAR)
593           {
594             if (html)
595               {
596                 flagname = message ("<tt>%s <em>&lt;%s&gt;</em></tt> <font color=\"blue\">[%c]</font>",
597                                     cstring_fromChars (f.flag), argcode_unparse (f.argtype),
598                                     (char) context_getValue (f.code));
599               }
600             else
601               {
602                 flagname = message ("%s <%s> [%c]", cstring_fromChars (f.flag), argcode_unparse (f.argtype),
603                                     (char) context_getValue (f.code));
604               }
605           }
606         else 
607           {
608             llassert (f.argtype == ARG_NUMBER);
609
610             if (html)
611               {
612                 flagname = message ("<tt>%s <em>&lt;%s&gt;</em> <font color=\"blue\">[%d]</font>",
613                                     cstring_fromChars (f.flag), argcode_unparse (f.argtype),
614                                     context_getValue (f.code));
615               }
616             else
617               {
618                 flagname = message ("%s <%s> [%d]", cstring_fromChars (f.flag), argcode_unparse (f.argtype),
619                                     context_getValue (f.code));
620               }
621           }
622       }
623
624     if (f.isIdem)
625       {
626         if (html)
627           {
628             flagtype = message("%q<font color=\"green\">-</font>", flagtype);
629           }
630         else
631           {
632             flagtype = message("%q<->", flagtype);
633           }
634       }
635     
636     if (f.isGlobal)
637       {
638         if (html)
639           {
640             flagtype = message ("%q<font color=\"green\"><em>global</em></font>", flagtype);
641           }
642         else
643           {
644             flagtype = message ("%q<G>", flagtype);
645           }
646       }
647
648     if (f.isSpecial)
649       {
650         if (html)
651           {
652             flagtype = message ("%q<font color=\"orange\"><em>shortcut</em></font>", flagtype);
653           }
654         else
655           {
656             flagtype = message("%q<S>", flagtype);
657           }
658       }
659     
660     if (f.isModeFlag)
661       {
662         if (html)
663           {
664             flagtype = message ("%q mode:<tt>%q</tt>>", flagtype, getFlagModeSettings (f.code));
665           }
666         else
667           {
668             flagtype = message ("%q<M:%q>", flagtype, getFlagModeSettings (f.code));
669           }
670       }
671     else /* its a plain flag */
672       {
673         if (html)
674           {
675             flagtype = message ("%q plain:<tt>%s</tt>", flagtype,
676                                 cstring_makeLiteralTemp (context_getFlag (f.code) ? "+" : "-"));
677           }
678         else
679           {
680             flagtype = message ("%q<P:%s>", flagtype,
681                                 cstring_makeLiteralTemp (context_getFlag (f.code) ? "+" : "-"));
682           }
683       }
684     
685     llmsg (message ("%s: %s", flagname, flagtype));
686
687     if (html)
688       {
689         llgenindentmsgnoloc (cstring_makeLiteral ("<blockquote>"));
690       }
691
692     if (mstring_isDefined (f.hint))
693       {
694         llgenindentmsgnoloc (cstring_fromCharsNew (f.hint));
695       }
696     else
697       {
698         llgenindentmsgnoloc (message ("%q.", cstring_capitalize (cstring_fromChars (f.desc))));
699       }
700
701     if (html)
702       {
703         llgenindentmsgnoloc (cstring_makeLiteral ("</blockquote>"));
704       }
705   } end_allFlags ;
706 }
707
708 cstring 
709 describeMode (cstring mode)
710 {
711   cstringSList sflags = sortedFlags ();
712   cstring res = message ("Predefined mode %s sets: ", mode);
713
714   llassert (flags_isModeName (mode));
715
716   context_setMode (mode);
717
718   cstringSList_elements (sflags, flagname)
719     {
720       flagcode code = flags_identifyFlag (flagname);
721       fflag currentflag = flags[code];
722       
723       if (mstring_isDefined (currentflag.desc) && flagcode_isModeFlag (code))
724         {
725           if (context_getFlag (code))
726             {
727               res = message ("%q\n   +%s", res, cstring_fromChars (currentflag.flag));
728             }
729           else
730             {
731               res = message ("%q\n   -%s", res, cstring_fromChars (currentflag.flag)); 
732             }
733         }
734     } end_cstringSList_elements;
735   
736   cstringSList_free (sflags);
737
738   res = cstring_appendChar (res, '\n');
739   return (res);
740 }
741
742 cstring
743 describeFlagCode (flagcode flag)
744 {
745   cstring ret = cstring_undefined;
746   fflag f;
747   
748   if (flagcode_isInvalid (flag))
749     {
750       return (cstring_makeLiteral ("<invalid>"));
751     }
752
753   if (flagcode_isModeName (flag)) 
754     {
755       return (cstring_makeLiteral ("<mode flag>"));
756     }
757
758   context_resetAllFlags ();
759   
760   f = flags[flag];
761   ret = cstring_copy (cstring_fromChars (f.desc));
762   
763   if (f.sub != FK_NONE)
764     {
765       ret = message ("%q\nCategories: %s, %s",
766                      ret, 
767                      categoryName (f.main),
768                      categoryName (f.sub));
769     }
770   else 
771     {
772       if (f.main != FK_NONE)
773         {
774           cstring cname = categoryName (f.main);
775           
776           if (cstring_isDefined (cname))
777             {
778               ret = message ("%q\nCategory: %s",
779                              ret, cname);
780             }
781         }
782     }
783   
784   if (f.isModeFlag)
785     {
786       ret = message ("%q\nMode Settings: %q",
787                      ret, getFlagModeSettings (flag));
788     }
789   else
790     {
791       ret = message ("%q\nDefault Setting: %s",
792                      ret, 
793                      cstring_makeLiteralTemp (context_getFlag (flag) ? "+" : "-"));
794     }
795   
796   if (f.isGlobal)
797     {
798       ret = message("%q\nSet globally only", ret);
799     }
800   else
801     {
802       ret = message("%q\nSet locally", ret);
803     }
804   
805   switch (f.argtype)
806     {
807     case ARG_NONE:
808     case ARG_SPECIAL:
809       break;
810     case ARG_NUMBER:
811       ret = message("%q\nNumeric Argument.  Default: %d",
812                     ret,
813                     context_getValue (flag));
814       break;
815     case ARG_CHAR:
816       ret = message("%q\nCharacter Argument.  Default: %h",
817                     ret, (char) context_getValue (flag));
818       break;
819     case ARG_STRING:
820     case ARG_FILE:
821     case ARG_PATH:
822     case ARG_DIRECTORY:
823       {
824       if (cstring_isDefined (context_getString (flag)))
825         {
826           ret = message("%q\n%q argument.  Default: %s",
827                         ret,
828                         cstring_capitalize (argcode_unparse (f.argtype)),
829                         context_getString (flag));
830         }
831       else
832         {
833           ret = message("%q\n%s argument.  No default.", 
834                         ret,
835                         cstring_capitalize (argcode_unparse (f.argtype)));
836         }
837       break;
838       }
839     }
840   
841   if (mstring_isDefined (f.hint))
842     {
843       ret = message("%q\n\3%s", ret, cstring_fromChars (f.hint));
844     }
845   
846   return ret;
847 }
848   
849 static cstring getFlagModeSettings (flagcode flag)
850 {
851   cstring res = cstring_undefined;
852   
853   allModes (mname)
854     {
855       context_setModeNoWarn (cstring_fromChars (mname));
856       
857       res = message ("%q%s", res, cstring_makeLiteralTemp (context_getFlag (flag) ? "+" : "-"));
858     } end_allModes;
859
860   return res;
861 }
862
863 cstring
864 describeFlag (cstring flagname)
865 {
866   cstring oflagname = cstring_copy (flagname);
867   flagcode f = flags_identifyFlag (flagname);
868
869   if (flagcode_isSkip (f))
870     {
871       cstring_free (oflagname);
872       return cstring_undefined;
873     }
874   else if (flagcode_isValid (f))
875     {
876       if (cstring_equal (flagname, oflagname))
877         {
878           cstring_free (oflagname);
879           return (message ("%s\n\3%q", flagname, describeFlagCode (f)));
880         }
881       else
882         {
883           return (message ("%q (standardized name: %s)\n\3%q",
884                            oflagname, flagname, describeFlagCode (f)));
885         }
886     }
887   else
888     {
889       if (flags_isModeName (flagname))
890         {
891           cstring_free (oflagname);
892           return describeMode (flagname);
893         }
894       else
895         {
896           return (message ("%q: <invalid flag>", oflagname));
897         }
898     }
899 }
900
901 static cstringSList
902 sortedFlags (void)
903 {
904   cstringSList s = cstringSList_new ();
905
906   allFlags (f)
907     {
908       if (f.desc != NULL)
909         {
910           s = cstringSList_add (s, cstring_fromChars (f.flag));
911         }
912     } end_allFlags;
913
914   cstringSList_alphabetize (s);
915
916   return s;
917 }
918
919 void printAlphaFlags ()
920 {
921   cstringSList fl = sortedFlags ();
922
923   cstringSList_printSpaced (fl, 3, 1, context_getLineLen () - 25); 
924   cstringSList_free (fl);
925 }
926
927 /*@observer@*/ cstring
928 flagcode_unparse (flagcode code)
929 {
930   if (code == INVALID_FLAG)
931     {
932       return cstring_makeLiteralTemp ("<invalid flag>");
933     }
934
935   return cstring_fromChars (flags[code].flag);
936 }
937
938 /*
939 ** Transforms a flag into its cannonical form.
940 **
941 ** The following transformations are made:
942 **
943 **    function      -> fcn
944 **    variable      -> var
945 **    constant      -> const
946 **    iterator      -> iter
947 **    parameter     -> param
948 **    unrecognized  -> unrecog
949 **    qualifier     -> qual         
950 **    declaration   -> decl
951 **    globalias     -> (no change)
952 **    global        -> glob
953 **    modifies      -> mods
954 **    modify        -> mod
955 **    pointer       -> ptr
956 **    implies       -> imp
957 **    implicit      -> imp
958 **    implied       -> imp
959 **    unconstrained -> unspec       
960 **    unconst       -> unspec
961 **    memory        -> mem
962 **    length        -> len
963 */
964
965 static /*@only@*/ cstring
966 canonicalizeFlag (cstring s)
967 {
968   int i = 0;
969   cstring res = cstring_copy (s);
970   static bn_mstring transform[] = 
971     { 
972       "function", "fcn",
973       "variable", "var",
974       "constant", "const",
975       "iterator", "iter",
976       "parameter", "param",
977       "unrecognized", "unrecog",
978       "qualifier", "qual",
979       "declaration", "decl",
980       "globals", "globs", 
981       "modifies", "mods", 
982       "modify", "mod",
983       "pointer", "ptr",
984       "implies", "imp",
985       "implicit", "imp",
986       "implied", "imp",
987       "unconstrained", "uncon",
988       "unconst", "uncon",
989       "memory", "mem",
990       "length", "len",
991       "return", "ret",
992       "system", "sys",
993       NULL
994       } ;
995   char *current;
996   
997   while ((current = transform[i]) != NULL)
998     {
999       if (cstring_containsLit (res, current))
1000         {
1001           cstring_replaceLit (res, current, transform[i+1]);
1002         }
1003       i += 2;
1004     }
1005
1006   /* remove whitespace, -'s, and _'s */
1007   cstring_stripChars (res, " -_");
1008   return res;
1009 }
1010
1011 flagcode
1012 flags_identifyFlag (cstring s)
1013 {
1014   return flags_identifyFlagAux (s, FALSE);
1015 }
1016
1017 flagcode
1018 flags_identifyFlagQuiet (cstring s)
1019 {
1020   return flags_identifyFlagAux (s, TRUE);
1021 }
1022
1023 static flagcode
1024 flags_identifyFlagAux (cstring s, bool quiet)
1025 {
1026   cstring cflag;
1027   flagcode res;
1028
1029   if (cstring_length (s) == 0) {
1030     /* evs 2000-06-25: A malformed flag. */
1031     return INVALID_FLAG;
1032   }
1033
1034   if (cstring_firstChar (s) == 'I')
1035     {
1036       return FLG_INCLUDEPATH; /* no space required after -I */
1037     }
1038
1039   if (cstring_firstChar (s) == 'S') 
1040     {
1041       return FLG_SPECPATH;    /* no space required after -S */
1042     }
1043
1044   if (cstring_firstChar (s) == 'D') 
1045     {
1046       return FLG_DEFINE;      /* no space required after -D */
1047     }
1048
1049   if (cstring_firstChar (s) == 'U') 
1050     {
1051       return FLG_UNDEFINE;    /* no space required after -D */
1052     }
1053
1054   cflag = canonicalizeFlag (s);
1055   res = INVALID_FLAG;
1056
1057   allFlags (f)
1058     {
1059       if (cstring_equal (cstring_fromChars (f.flag), cflag))
1060         {
1061           res = f.code;
1062           break;
1063         }
1064     } end_allFlags;
1065   
1066   if (res == INVALID_FLAG)
1067     {
1068       /*
1069       ** Synonyms
1070       */
1071       
1072       if (cstring_equalLit (cflag, "pred"))
1073         {
1074           res = FLG_PREDBOOL;
1075         }
1076       else if (cstring_equalLit (cflag, "modobserverstrict"))
1077         {
1078           res = FLG_MODOBSERVERUNCON;
1079         }
1080       else if (cstring_equalLit (cflag, "czechnames"))
1081         {
1082           res = FLG_CZECH;
1083         }
1084       else if (cstring_equalLit (cflag, "slovaknames"))
1085         {
1086           res = FLG_SLOVAK;
1087         }
1088       else if (cstring_equalLit (cflag, "czechoslovaknames"))
1089         {
1090           res = FLG_CZECHOSLOVAK;
1091         }
1092       else if (cstring_equalLit (cflag, "globunspec")
1093                || cstring_equalLit (cflag, "globuncon"))
1094         {
1095           res = FLG_GLOBUNSPEC;
1096         }
1097       else if (cstring_equalLit (cflag, "modglobsunspec")
1098                || cstring_equalLit (cflag, "modglobsuncon")
1099                || cstring_equalLit (cflag, "modglobsnomods"))
1100         {
1101           res = FLG_MODGLOBSUNSPEC;
1102         }
1103       else if (cstring_equalLit (cflag, "export"))
1104         {
1105           res = FLG_EXPORTANY;
1106         }
1107       else if (cstring_equalLit (cflag, "macrospec"))
1108         {
1109           res = FLG_MACRODECL;
1110         }
1111       else if (cstring_equalLit (cflag, "ansireservedlocal"))
1112         {
1113           res = FLG_ISORESERVEDLOCAL;
1114         }
1115       else if (cstring_equalLit (cflag, "warnposix"))
1116         {
1117           res = FLG_WARNPOSIX;
1118         }
1119       else if (cstring_equalLit (cflag, "defuse"))
1120         {
1121           res = FLG_USEDEF;
1122         }
1123       else if (cstring_equalLit (cflag, "macroundef"))
1124         {
1125           res = FLG_MACROUNDEF;
1126         }
1127       else if (cstring_equalLit (cflag, "showcol"))
1128         {
1129           res = FLG_SHOWCOL;
1130         }
1131       else if (cstring_equalLit (cflag, "intbool"))
1132         {
1133           res = FLG_BOOLINT;
1134         }
1135       else if (cstring_equalLit (cflag, "intchar"))
1136         {
1137           res = FLG_CHARINT;
1138         }
1139       else if (cstring_equalLit (cflag, "intenum"))
1140         {
1141           res = FLG_ENUMINT;
1142         }
1143       else if (cstring_equalLit (cflag, "intlong"))
1144         {
1145           res = FLG_LONGINT;
1146         }
1147       else if (cstring_equalLit (cflag, "intshort"))
1148         {
1149           res = FLG_SHORTINT;
1150         }
1151       /*
1152       ** Backwards compatibility for our American friends...
1153       */
1154       
1155       else if (cstring_equalLit (cflag, "ansilib"))
1156         {
1157           res = FLG_ANSILIB;
1158         }
1159       else if (cstring_equalLit (cflag, "ansistrictlib"))
1160         {
1161           res = FLG_STRICTLIB;
1162         }
1163       else if (cstring_equalLit (cflag, "skipansiheaders"))
1164         {
1165           res = FLG_SKIPISOHEADERS;
1166         }
1167       else if (cstring_equalLit (cflag, "ansireserved"))
1168         {
1169           res = FLG_ISORESERVED;
1170         }
1171       else if (cstring_equalLit (cflag, "ansireservedinternal"))
1172         {
1173           res = FLG_ISORESERVEDLOCAL;
1174         }
1175       
1176       /*
1177       ** Obsolete Flags
1178       */
1179       
1180       else if (cstring_equalLit (cflag, "accessunspec"))
1181         {
1182           if (!quiet) 
1183             {
1184               llerror_flagWarning 
1185                 (cstring_makeLiteral
1186                  ("accessunspec flag is no longer supported.  It has been replaced by accessmodule, accessfile and "
1187                   "accessfunction to provide more precise control of accessibility "
1188                   "of representations.  For more information, "
1189                   "see splint -help accessmodule"));
1190             }
1191           
1192           res = SKIP_FLAG;
1193         }
1194       else if (cstring_equalLit (cflag, "ansilimits"))
1195         {
1196           llerror_flagWarning 
1197             (cstring_makeLiteral
1198              ("ansilimits flag is no longer supported.  It has been replaced by ansi89limits and "
1199               "iso99limits to select either the lower translation limits imposed by the ANSI89 "
1200               "standard or the typically higher limits prescribed by ISO C99."));
1201           
1202           res = SKIP_FLAG;
1203         }
1204       else if (cstring_equalLit (cflag, "staticmods"))
1205         {
1206           if (!quiet) 
1207             {
1208               llerror_flagWarning 
1209                 (cstring_makeLiteral
1210                  ("staticmods flag is obsolete.  You probably "
1211                   "want impcheckmodstatics.  For more information, "
1212                   "see splint -help impcheckmodstatics"));
1213             }
1214           
1215           res = SKIP_FLAG;
1216         }
1217       else if (cstring_equalLit (cflag, "bool"))
1218         {
1219           if (!quiet) 
1220             {
1221               llerror_flagWarning
1222                 (cstring_makeLiteral ("bool flag is obsolete.  It never really "
1223                                       "made sense in the first place."));
1224             }
1225           
1226           res = SKIP_FLAG;
1227         }
1228       else if (cstring_equalLit (cflag, "shiftsigned"))
1229         {
1230           if (!quiet) 
1231             {
1232               llerror_flagWarning
1233                 (cstring_makeLiteral ("shiftsigned flag is obsolete.  You probably "
1234                                       "want bitwisesigned, shiftnegative or shiftimplementation."));
1235             }
1236           
1237           res = SKIP_FLAG;
1238         }
1239       else if (cstring_equalLit (cflag, "ansi"))
1240         {
1241           if (!quiet) 
1242             {
1243               llerror_flagWarning
1244                 (cstring_makeLiteral ("ansi flag is obsolete.  You probably "
1245                                       "want noparams and/or oldstyle."));
1246             }
1247           
1248           res = SKIP_FLAG;
1249         }
1250       else if (cstring_equalLit (cflag, "usestderr"))
1251         {
1252           if (!quiet)
1253             {
1254               llerror_flagWarning 
1255                 (cstring_makeLiteral
1256                  ("usestderr flag is obsolete. This has been replaced "
1257                   "by more precise flags for controlling the warning, "
1258                   "status message and fatal error streams independently: message-stream-stdout, "
1259                   "message-stream-stderr, message-stream <file>, "
1260                   "warning-stream-stdout, warning-stream-stderr, warning-stream <file>, "
1261                   "error-stream-stdout, error-stream-stderr, error-stream <file>."));
1262             }
1263           
1264           res = SKIP_FLAG;
1265         }
1266
1267       else if (cstring_equalLit (cflag, "stdio"))
1268         {
1269           if (!quiet) 
1270             {
1271               llerror_flagWarning 
1272                 (cstring_makeLiteral
1273                  ("stdio flag is obsolete.  You may "
1274                   "want strictlib or one of the gloabls "
1275                   "checking flags.  For more information, "
1276                   "see splint -help strictlib or splint -help flags globals"));
1277             }
1278           
1279           res = SKIP_FLAG;
1280         }
1281       else if (flags_isModeName (cflag))
1282         {
1283           res = MODENAME_FLAG;
1284         }
1285       else
1286         {
1287           res = INVALID_FLAG;
1288         }
1289     }
1290
1291   cstring_free (cflag);
1292   return res;
1293 }
1294
1295 void flags_setValueFlag (flagcode opt, cstring arg)
1296 {
1297   switch (opt)
1298     {
1299     case FLG_EXPECT:
1300     case FLG_LCLEXPECT:
1301     case FLG_LIMIT:  
1302     case FLG_LINELEN:
1303     case FLG_INDENTSPACES:
1304     case FLG_LOCINDENTSPACES:
1305     case FLG_BUGSLIMIT:
1306     case FLG_EXTERNALNAMELEN:
1307     case FLG_INTERNALNAMELEN:
1308     case FLG_CONTROLNESTDEPTH:
1309     case FLG_STRINGLITERALLEN:
1310     case FLG_NUMSTRUCTFIELDS:
1311     case FLG_NUMENUMMEMBERS:
1312     case FLG_INCLUDENEST:
1313       {
1314         int val = cstring_toPosInt (arg);
1315
1316         if (val < 0)
1317           {
1318             llerror 
1319               (FLG_BADFLAG,
1320                message 
1321                ("Flag %s must be followed by a positive number number.  "
1322                 "Followed by %s",
1323                 flagcode_unparse (opt), arg));
1324           }
1325         else
1326           {
1327             context_setValueAndFlag (opt, val);
1328           }
1329       }
1330       break;
1331     case FLG_COMMENTCHAR:
1332       {
1333         if (cstring_length (arg) != 1)
1334           {
1335             llfatalerrorLoc
1336               (message
1337                ("Flag %s should be followed by a single character.  Followed by %s",
1338                 flagcode_unparse (opt), arg));
1339           }
1340         else
1341           {
1342             context_setCommentMarkerChar (cstring_firstChar (arg));
1343           }
1344       }
1345       break;
1346       BADDEFAULT;
1347     }
1348 }
1349
1350 void flags_setStringFlag (flagcode opt, /*@only@*/ cstring arg)
1351 {
1352   switch (opt)
1353     {
1354     case FLG_TMPDIR:
1355       {
1356         if (cstring_lastChar (arg) == CONNECTCHAR)
1357           {
1358             context_setString (opt, arg);
1359           }
1360         else
1361           {
1362             context_setString (opt, cstring_appendChar (arg, CONNECTCHAR));
1363           }
1364         break;
1365       }
1366     default:
1367       {
1368         context_setString (opt, arg);
1369         break;
1370       }
1371     }
1372 }
1373
1374 cstring
1375 describeModes ()
1376 {
1377   cstring s = cstring_makeLiteral ("Flag                    ");
1378   cstringSList sflags = sortedFlags ();
1379
1380   allModes (modename)
1381     {
1382       s = message ("%q%9s", s, cstring_fromChars (modename));
1383     } end_allModes;
1384   
1385   s = message ("%q\n", s);
1386
1387   cstringSList_elements (sflags, flagname)
1388     {
1389       flagcode code = flags_identifyFlag (flagname);
1390       fflag currentflag = flags[code];
1391       
1392       if (mstring_isDefined (currentflag.desc) && flagcode_isModeFlag (code))
1393         {
1394           s = message ("%q\n%27s", s, 
1395                        cstring_fromChars (currentflag.flag));
1396           
1397           allModes (modename)
1398             {
1399               context_setMode (cstring_fromChars (modename));
1400               
1401               if (context_getFlag (code))
1402                 {
1403                   s = message ("%q%9s", s, cstring_makeLiteralTemp ("+"));
1404                 }
1405               else
1406                 {
1407                   s = message ("%q%9s", s, cstring_makeLiteralTemp (" "));
1408                 }
1409
1410               context_resetModeFlags ();
1411             } end_allModes;
1412         }
1413     } end_cstringSList_elements;
1414   
1415   cstringSList_free (sflags);
1416
1417   s = cstring_appendChar (s, '\n');
1418
1419   return (s);
1420 }
1421
1422 # if 0
1423 static /*@unused@*/ cstring
1424 listModes (void)
1425 {
1426   cstring s = cstring_makeLiteral ("\t");
1427   int i = 0;
1428
1429   allModes (modename)
1430     {
1431       if (i != 0 && (i % 4 == 0))
1432         {
1433           s = message ("%q\n\t%15s", s, cstring_fromChars (modename));
1434         }
1435       else
1436         {
1437           s = message ("%q%15s", s, cstring_fromChars (modename));
1438         }
1439       i++;
1440     } end_allModes;
1441
1442   return s;
1443 }
1444 # endif
1445
1446 bool
1447 flags_isModeName (cstring s)
1448 {
1449   allModes (modename)
1450     {
1451       if (mstring_isDefined (modename))
1452         {
1453           if (cstring_equalLit (s, modename))
1454             {
1455               return TRUE;
1456             }
1457         }
1458      } end_allModes;
1459
1460   return FALSE;
1461 }
1462
1463 extern bool flagcode_hasArgument (flagcode f)
1464 {
1465   return (flags[f].argtype != ARG_NONE);
1466 }
1467
1468 extern bool flagcode_hasNumber (flagcode f)
1469 {
1470   return (flags[f].argtype == ARG_NUMBER);
1471 }
1472
1473 extern bool flagcode_hasChar (flagcode f)
1474 {
1475   return (flags[f].argtype == ARG_CHAR);
1476 }
1477
1478 extern bool flagcode_hasString (flagcode f)
1479 {
1480   return (flags[f].argtype == ARG_STRING
1481           || flags[f].argtype == ARG_FILE
1482           || flags[f].argtype == ARG_DIRECTORY
1483           || flags[f].argtype == ARG_PATH);
1484 }
1485
1486 extern int flagcode_valueIndex (flagcode f)
1487 {
1488   /*@unchecked@*/ static bool initialized = FALSE;
1489   int i;
1490   /*@unchecked@*/ static flagcode valueFlags[NUMVALUEFLAGS];
1491   
1492   if (!initialized)
1493     {
1494       int nv = 0;
1495
1496       allFlagCodes (code)
1497         {
1498           if (flagcode_hasNumber (code) || flagcode_hasChar (code))
1499             {
1500               llassert (nv < NUMVALUEFLAGS);
1501               DPRINTF (("Value flag: %s [%d]", flagcode_unparse (code), (int) code));
1502               valueFlags[nv] = code;
1503               nv++;
1504             }
1505         } end_allFlagCodes;
1506
1507       llassertprint (nv == NUMVALUEFLAGS,
1508                      ("Number of value flags: %d (expected %d)",
1509                       nv, (int) NUMVALUEFLAGS));
1510       initialized = TRUE;
1511     }
1512
1513   for (i = 0; i < NUMVALUEFLAGS; i++)
1514     {
1515       /* static valueFlags must be defined */
1516       /*@-usedef@*/
1517       if (f == valueFlags[i]) /*@=usedef@*/
1518         {
1519           return i;
1520         }
1521     }
1522
1523   fprintf (stderr, "Cannot find value flag: %d", (int) f);
1524   exit (EXIT_FAILURE);
1525   /* Cannot do this...might call recursively...
1526   llfatalbug (message ("Cannot fine value flag: %d", (int) f));
1527   BADEXIT;
1528   */
1529 }
1530
1531 extern int flagcode_stringIndex (flagcode f)
1532 {
1533   /*@unchecked@*/ static bool initialized = FALSE;
1534   /*@unchecked@*/ static flagcode stringFlags[NUMSTRINGFLAGS];
1535   int i;
1536
1537
1538   if (!initialized)
1539     {
1540       int nv = 0;
1541
1542       allFlagCodes (code)
1543         {
1544           if (flagcode_hasString (code))
1545             {
1546               llassertprint (nv < NUMSTRINGFLAGS, ("Incorrect number of string flags: %d (need at least %d)", NUMSTRINGFLAGS, nv));
1547               stringFlags[nv] = code;
1548               nv++;
1549             }
1550         } end_allFlagCodes;
1551
1552       llassertprint (nv == NUMSTRINGFLAGS,
1553                      ("number of string flags: %d (expected %d)",
1554                       nv, NUMSTRINGFLAGS));
1555       initialized = TRUE;
1556     }
1557
1558   for (i = 0; i < NUMSTRINGFLAGS; i++)
1559     {
1560       /*@-usedef@*/ if (f == stringFlags[i]) /*@=usedef@*/
1561         {
1562           return i;
1563         }
1564     }
1565
1566   llbug (message ("Bad string flag: %s", flagcode_unparse (f)));
1567   BADEXIT;
1568 }
1569
1570 bool flagcode_isNamePrefixFlag (flagcode f)
1571 {
1572   switch (f)
1573     {
1574     case FLG_MACROVARPREFIX:
1575     case FLG_TAGPREFIX:
1576     case FLG_ENUMPREFIX:
1577     case FLG_FILESTATICPREFIX:
1578     case FLG_GLOBPREFIX:
1579     case FLG_TYPEPREFIX:
1580     case FLG_EXTERNALPREFIX:
1581     case FLG_LOCALPREFIX:
1582     case FLG_UNCHECKEDMACROPREFIX:
1583     case FLG_CONSTPREFIX:
1584     case FLG_ITERPREFIX:
1585     case FLG_DECLPARAMPREFIX:
1586       return TRUE;
1587     default:
1588       return FALSE;
1589     }
1590 }
1591
1592 static cstring findLarchPathFile (/*@temp@*/ cstring s)
1593 {
1594   cstring pathName;
1595   filestatus status;
1596   
1597   status = osd_getPath (context_getLarchPath (), s, &pathName);
1598   
1599   if (status == OSD_FILEFOUND)
1600     {
1601       return pathName;
1602     }
1603   else if (status == OSD_FILENOTFOUND)
1604     {
1605       showHerald ();
1606       lldiagmsg (message ("Cannot find file on LARCH_PATH: %s", s));
1607     }
1608   else if (status == OSD_PATHTOOLONG)
1609     {
1610       /* Directory and filename are too long.  Report error. */
1611       llbuglit ("soure_getPath: Filename plus directory from search path too long");
1612     }
1613   else
1614     {
1615       BADBRANCH;
1616     }
1617
1618   return cstring_undefined;
1619 }
1620
1621 static void addLarchPathFile (fileIdList files, /*@temp@*/ cstring s)
1622 {
1623   cstring pathName = findLarchPathFile (s);
1624
1625   if (cstring_isDefined (pathName))
1626     {
1627       if (fileTable_exists (context_fileTable (), pathName))
1628         {
1629           showHerald ();
1630           lldiagmsg (message ("File listed multiple times: %s", pathName));
1631           cstring_free (pathName);
1632         }
1633       else
1634         {
1635           fileIdList_add (files, fileTable_addFileOnly (context_fileTable (), pathName));
1636         }
1637     }
1638 }
1639
1640
1641 static void addFile (fileIdList files, /*@only@*/ cstring s)
1642 {
1643   if (fileTable_exists (context_fileTable (), s))
1644     {
1645       showHerald ();
1646       lldiagmsg (message ("File listed multiple times: %s", s));
1647       cstring_free (s);
1648     }
1649   else
1650     {
1651       fileIdList_add (files, fileTable_addFileOnly (context_fileTable (), s));
1652     }
1653 }
1654
1655 static void addXHFile (fileIdList files, /*@temp@*/ cstring s)
1656 {
1657   cstring pathName = findLarchPathFile (s);
1658
1659   if (cstring_isDefined (pathName))
1660     {
1661       if (fileTable_exists (context_fileTable (), pathName))
1662         {
1663           showHerald ();
1664           lldiagmsg (message ("File listed multiple times: %s", s));
1665         }
1666       else
1667         {
1668           fileIdList_add (files, fileTable_addXHFile (context_fileTable (), pathName));
1669         }
1670     }
1671
1672   cstring_free (pathName);
1673 }
1674
1675 void
1676 flags_processFlags (bool inCommandLine, 
1677                     fileIdList xfiles,
1678                     fileIdList cfiles,
1679                     fileIdList lclfiles,
1680                     fileIdList mtfiles,
1681                     cstringList *passThroughArgs,
1682                     int argc, char **argv)
1683 {
1684   int i;
1685   cstringSList fl = cstringSList_undefined;
1686     
1687   for (i = 0; i < argc; i++)
1688     {
1689       char *thisarg;
1690
1691       llassert (argv != NULL);
1692       thisarg = argv[i];
1693       
1694       DPRINTF (("process thisarg [%d]: %s", i, thisarg));
1695
1696       if (*thisarg == '-' || *thisarg == '+')
1697         {
1698           bool set = (*thisarg == '+');
1699           cstring flagname;
1700           flagcode opt;
1701
1702           if (*(thisarg + 1) == '-') { /* allow -- before flags */
1703             flagname = cstring_fromChars (thisarg + 2);
1704           } else {
1705             flagname = cstring_fromChars (thisarg + 1);
1706           }
1707
1708           opt = flags_identifyFlag (flagname);
1709           DPRINTF (("Flag [%s]: %s", flagname, flagcode_unparse (opt)));
1710           
1711           if (flagcode_isInvalid (opt))
1712             {
1713               DPRINTF (("Error!"));
1714               voptgenerror (FLG_BADFLAG,
1715                             message ("Unrecognized option: %s", 
1716                                      cstring_fromChars (thisarg)),
1717                             g_currentloc);
1718             }
1719           else if (flagcode_isHelpFlag (opt))
1720             {
1721               if (inCommandLine)
1722                 {
1723                   voptgenerror (FLG_BADFLAG,
1724                                 message ("Help flag must be first on the command line: %s", 
1725                                          cstring_fromChars (thisarg)),
1726                                 g_currentloc);
1727                 }
1728               else
1729                 {
1730                   voptgenerror (FLG_BADFLAG,
1731                                 message ("Help flags can only be used on the command line: %s", 
1732                                          cstring_fromChars (thisarg)),
1733                                 g_currentloc);
1734                 }
1735             }
1736           else if (flagcode_isPassThrough (opt)) /* preprocessor flag: -D or -U */
1737             { 
1738               /*
1739               ** Following space is optional, don't include the -
1740               */
1741               
1742               *passThroughArgs = cstringList_add (*passThroughArgs, 
1743                                                   cstring_fromCharsNew (thisarg + 1));
1744             }
1745           else if (opt == FLG_INCLUDEPATH || opt == FLG_SPECPATH)
1746             {
1747               if (mstring_length (thisarg) < 2) {
1748                 BADBRANCH;
1749               } else {
1750                 if (mstring_equal (thisarg, "-I-")) {
1751                   cppAddIncludeDir (cstring_fromChars (thisarg)); /* Need to handle this specially. */
1752                 } else {
1753                   cstring dir = cstring_suffix (cstring_fromChars (thisarg), 2); /* skip over -I */
1754                   
1755                   DPRINTF (("Length of thisarg [%s] %d", thisarg, cstring_length (thisarg)));
1756                   
1757                   if (cstring_length (dir) == 0) {
1758                     DPRINTF (("space after directory: "));
1759                     if (++i < argc) {
1760                       dir = cstring_fromChars (argv[i]);
1761                     } else {
1762                       voptgenerror
1763                         (FLG_BADFLAG,
1764                          message
1765                          ("Flag %s must be followed by a directory name",
1766                           flagcode_unparse (opt)),
1767                          g_currentloc);
1768                     }
1769                   } 
1770                   
1771                   DPRINTF (("Got directory: [%s]", dir));
1772                   
1773                   switch (opt)
1774                     {
1775                     case FLG_INCLUDEPATH:
1776                       cppAddIncludeDir (dir);
1777                       /*@switchbreak@*/ break;
1778                     case FLG_SPECPATH:
1779                       /*@-mustfree@*/
1780                       g_localSpecPath = cstring_toCharsSafe
1781                         (message ("%s%h%s", 
1782                                   cstring_fromChars (g_localSpecPath), 
1783                                   PATH_SEPARATOR,
1784                                   dir));
1785                       /*@=mustfree@*/
1786                       /*@switchbreak@*/ break;
1787                       BADDEFAULT;
1788                     }
1789                 }
1790               }
1791             }
1792           else if (flagcode_isModeName (opt))
1793             {
1794               context_setMode (flagname);
1795             }
1796           else if (inCommandLine && flagcode_isMessageControlFlag (opt))
1797             {
1798               /*
1799               ** Processed on first pass
1800               */
1801               
1802               if (flagcode_hasArgument (opt))
1803                 {
1804                   ++i;
1805                 }
1806             }
1807           else
1808             {
1809               /*
1810               ** A normal control flag
1811               */
1812
1813               context_userSetFlag (opt, set);
1814               
1815               if (flagcode_hasArgument (opt))
1816                 {
1817                   if (flagcode_hasNumber (opt))
1818                     {
1819                       if (++i < argc)
1820                         {
1821                           flags_setValueFlag (opt, cstring_fromCharsNew (argv[i]));
1822                         }
1823                       else
1824                         {
1825                           voptgenerror
1826                             (FLG_BADFLAG,
1827                              message
1828                              ("Flag %s must be followed by a number",
1829                               flagcode_unparse (opt)),
1830                              g_currentloc);
1831                         }
1832                     } 
1833                   else if (flagcode_hasChar (opt))
1834                     {
1835                       if (++i < argc)
1836                         {
1837                           flags_setValueFlag (opt, cstring_fromCharsNew (argv[i]));
1838                         }
1839                       else
1840                         {
1841                           voptgenerror
1842                             (FLG_BADFLAG,
1843                              message
1844                              ("Flag %s must be followed by a character",
1845                               flagcode_unparse (opt)),
1846                              g_currentloc);
1847                         }
1848                     } 
1849                   else if (flagcode_hasString (opt)
1850                            || opt == FLG_INIT || opt == FLG_OPTF)
1851                     {
1852                       if (++i < argc)
1853                         {
1854                           /*drl 10/21/2002
1855                             Changed this because arg can be freed when it's passed to
1856                             lslinit_setInitFile and freeing argv[i] causes a seg fault
1857                           */
1858                           cstring arg =  cstring_fromCharsNew (argv[i]);
1859                           
1860                           if (opt == FLG_OPTF)
1861                             {
1862                               if (inCommandLine)
1863                                 {
1864                                   ; /* -f already processed */
1865                                 }
1866                               else
1867                                 {
1868                                   (void) rcfiles_read (arg, passThroughArgs, TRUE);
1869                                 }
1870                             }
1871                           else if (opt == FLG_INIT)
1872                             {
1873                               lslinit_setInitFile (inputStream_create 
1874                                                    (arg, 
1875                                                     cstring_makeLiteralTemp (LCLINIT_SUFFIX),
1876                                                     FALSE));
1877                               break;
1878                             }
1879                           else
1880                             {
1881                               DPRINTF (("String flag: %s / %s",
1882                                         flagcode_unparse (opt), arg));
1883                               if (opt == FLG_MTSFILE)
1884                                 {
1885                                   /*
1886                                   ** arg identifies mts files
1887                                   */
1888                                   cstring tmp =  message ("%s%s", arg, MTS_EXTENSION);
1889                                   addLarchPathFile (mtfiles, tmp);
1890                                   cstring_free (tmp);
1891                                   tmp = message ("%s%s", arg, XH_EXTENSION);
1892                                   addXHFile (xfiles, tmp);
1893                                   cstring_free (tmp);
1894                                 }
1895                               else
1896                                 {
1897                                   flags_setStringFlag (opt, cstring_copy (arg));
1898                                 }
1899                             }
1900                         }
1901                       else
1902                         {
1903                           voptgenerror
1904                             (FLG_BADFLAG,
1905                              message
1906                              ("Flag %s must be followed by a string",
1907                               flagcode_unparse (opt)),
1908                              g_currentloc);
1909                         }
1910                     }
1911                   else
1912                     {
1913                       /* no argument */
1914                     }
1915                 }
1916             }
1917         }
1918       else /* its a filename */
1919         {
1920           DPRINTF (("Adding filename: %s", thisarg));
1921           fl = cstringSList_add (fl, cstring_fromChars (thisarg));
1922         }
1923     }
1924   
1925   /*
1926   ** create lists of C and LCL files
1927   */
1928   
1929   if (inCommandLine)
1930     {
1931       cstringSList_elements (fl, current)
1932         {
1933           cstring ext = fileLib_getExtension (current);
1934           
1935           if (cstring_isUndefined (ext))
1936             {
1937               /* no extension --- both C and LCL with default extensions */
1938               
1939               addFile (cfiles, message ("%s%s", current, C_EXTENSION));
1940               addFile (lclfiles, message ("%s%s", current, LCL_EXTENSION));
1941             }
1942           else if (cstring_equal (ext, XH_EXTENSION))
1943             {
1944               addXHFile (xfiles, current);
1945             }
1946           else if (cstring_equal (ext, PP_EXTENSION))
1947             {
1948               if (!context_getFlag (FLG_NOPP))
1949                 {
1950                   voptgenerror 
1951                     (FLG_FILEEXTENSIONS,
1952                      message ("File extension %s used without +nopp flag (will be processed as C source code): %s", 
1953                               ext, current),
1954                      g_currentloc);
1955                 }
1956               
1957               addFile (cfiles, cstring_copy (current));
1958             }
1959           else if (cstring_equal (ext, LCL_EXTENSION)) 
1960             {
1961               addFile (lclfiles, cstring_copy (current));
1962             }
1963           else if (fileLib_isCExtension (ext))
1964             {
1965               addFile (cfiles, cstring_copy (current));
1966             }
1967           else if (cstring_equal (ext, MTS_EXTENSION))
1968             {
1969               addLarchPathFile (mtfiles, current);
1970             }
1971           else 
1972             {
1973               voptgenerror 
1974                 (FLG_FILEEXTENSIONS,
1975                  message ("Unrecognized file extension: %s (assuming %s is C source code)", 
1976                           current, ext),
1977                  g_currentloc);
1978               
1979               addFile (cfiles, cstring_copy (current));
1980             }
1981         } end_cstringSList_elements;
1982     }
1983   else
1984     {
1985       if (cstringSList_size (fl) != 0)
1986         {
1987           /* Cannot list files in .splintrc files */
1988           voptgenerror (FLG_BADFLAG, 
1989                         message ("Cannot list files in .splintrc files: %s (probable missing + or -)",
1990                                  cstringSList_unparse (fl)),
1991                         g_currentloc);
1992         }
1993     }
1994
1995   cstringSList_free (fl); /* evans 2002-07-12: why wasn't this reported!?? */
1996 }
1997
1998 int flagcode_priority (/*@unused@*/ flagcode code)
1999 {
2000   /*
2001   ** For now, we do a really simple prioritization: all are 1
2002   */
2003
2004   return 1;
2005 }
This page took 0.205235 seconds and 5 git commands to generate.