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