]> andersk Git - splint.git/blob - src/flags.c
bc1597faf1950d66b478f9fa2fd7837ba96636d0
[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 describeFlagCode (flagcode flag)
710 {
711   cstring ret = cstring_undefined;
712   fflag f;
713   
714   if (flagcode_isInvalid (flag))
715     {
716       return (cstring_makeLiteral ("<invalid>"));
717     }
718
719   context_resetAllFlags ();
720   
721   f = flags[flag];
722   ret = cstring_copy (cstring_fromChars (f.desc));
723   
724   if (f.sub != FK_NONE)
725     {
726       ret = message ("%q\nCategories: %s, %s",
727                      ret, 
728                      categoryName (f.main),
729                      categoryName (f.sub));
730     }
731   else 
732     {
733       if (f.main != FK_NONE)
734         {
735           cstring cname = categoryName (f.main);
736           
737           if (cstring_isDefined (cname))
738             {
739               ret = message ("%q\nCategory: %s",
740                              ret, cname);
741             }
742         }
743     }
744   
745   if (f.isModeFlag)
746     {
747       ret = message ("%q\nMode Settings: %q",
748                      ret, getFlagModeSettings (flag));
749     }
750   else
751     {
752       ret = message ("%q\nDefault Setting: %s",
753                      ret, 
754                      cstring_makeLiteralTemp (context_getFlag (flag) ? "+" : "-"));
755     }
756   
757   if (f.isGlobal)
758     {
759       ret = message("%q\nSet globally only", ret);
760     }
761   else
762     {
763       ret = message("%q\nSet locally", ret);
764     }
765   
766   switch (f.argtype)
767     {
768     case ARG_NONE:
769     case ARG_SPECIAL:
770       break;
771     case ARG_NUMBER:
772       ret = message("%q\nNumeric Argument.  Default: %d",
773                     ret,
774                     context_getValue (flag));
775       break;
776     case ARG_CHAR:
777       ret = message("%q\nCharacter Argument.  Default: %h",
778                     ret, (char) context_getValue (flag));
779       break;
780     case ARG_STRING:
781     case ARG_FILE:
782     case ARG_PATH:
783     case ARG_DIRECTORY:
784       {
785       if (cstring_isDefined (context_getString (flag)))
786         {
787           ret = message("%q\n%q argument.  Default: %s",
788                         ret,
789                         cstring_capitalize (argcode_unparse (f.argtype)),
790                         context_getString (flag));
791         }
792       else
793         {
794           ret = message("%q\n%s argument.  No default.", 
795                         ret,
796                         cstring_capitalize (argcode_unparse (f.argtype)));
797         }
798       break;
799       }
800     }
801   
802   if (mstring_isDefined (f.hint))
803     {
804       ret = message("%q\n\3%s", ret, cstring_fromChars (f.hint));
805     }
806   
807   return ret;
808 }
809   
810 static cstring getFlagModeSettings (flagcode flag)
811 {
812   cstring res = cstring_undefined;
813   
814   allModes (mname)
815     {
816       context_setModeNoWarn (cstring_fromChars (mname));
817       
818       res = message ("%q%s", res, cstring_makeLiteralTemp (context_getFlag (flag) ? "+" : "-"));
819     } end_allModes;
820
821   return res;
822 }
823
824 cstring
825 describeFlag (cstring flagname)
826 {
827   cstring oflagname = cstring_copy (flagname);
828   flagcode f = flags_identifyFlag (flagname);
829
830   if (flagcode_isSkip (f))
831     {
832       cstring_free (oflagname);
833       return cstring_undefined;
834     }
835   else if (flagcode_isValid (f))
836     {
837       if (cstring_equal (flagname, oflagname))
838         {
839           cstring_free (oflagname);
840           return (message ("%s\n\3%q", flagname, describeFlagCode (f)));
841         }
842       else
843         {
844           return (message ("%q (standardized name: %s)\n\3%q",
845                            oflagname, flagname, describeFlagCode (f)));
846         }
847     }
848   else
849     {
850       if (flags_isModeName (flagname))
851         {
852           cstring_free (oflagname);
853
854           return
855             (message ("%s: predefined mode (see Manual for information)",
856                       flagname));
857         }
858       else
859         {
860           return (message ("%q: <invalid flag>", oflagname));
861         }
862     }
863 }
864
865 static cstringSList
866 sortedFlags (void)
867 {
868   cstringSList s = cstringSList_new ();
869
870   allFlags (f)
871     {
872       if (f.desc != NULL)
873         {
874           s = cstringSList_add (s, cstring_fromChars (f.flag));
875         }
876     } end_allFlags;
877
878   cstringSList_alphabetize (s);
879
880   return s;
881 }
882
883 void printAlphaFlags ()
884 {
885   cstringSList fl = sortedFlags ();
886
887   cstringSList_printSpaced (fl, 3, 1, context_getLineLen () - 25); 
888   cstringSList_free (fl);
889 }
890
891 /*@observer@*/ cstring
892 flagcode_unparse (flagcode code)
893 {
894   if (code == INVALID_FLAG)
895     {
896       return cstring_makeLiteralTemp ("<invalid flag>");
897     }
898
899   return cstring_fromChars (flags[code].flag);
900 }
901
902 /*
903 ** Transforms a flag into its cannonical form.
904 **
905 ** The following transformations are made:
906 **
907 **    function      -> fcn
908 **    variable      -> var
909 **    constant      -> const
910 **    iterator      -> iter
911 **    parameter     -> param
912 **    unrecognized  -> unrecog
913 **    qualifier     -> qual         
914 **    declaration   -> decl
915 **    globalias     -> (no change)
916 **    global        -> glob
917 **    modifies      -> mods
918 **    modify        -> mod
919 **    pointer       -> ptr
920 **    implies       -> imp
921 **    implicit      -> imp
922 **    implied       -> imp
923 **    unconstrained -> unspec       
924 **    unconst       -> unspec
925 **    memory        -> mem
926 **    length        -> len
927 */
928
929 static /*@only@*/ cstring
930 canonicalizeFlag (cstring s)
931 {
932   int i = 0;
933   cstring res = cstring_copy (s);
934   static bn_mstring transform[] = 
935     { 
936       "function", "fcn",
937       "variable", "var",
938       "constant", "const",
939       "iterator", "iter",
940       "parameter", "param",
941       "unrecognized", "unrecog",
942       "qualifier", "qual",
943       "declaration", "decl",
944       "globals", "globs", 
945       "modifies", "mods", 
946       "modify", "mod",
947       "pointer", "ptr",
948       "implies", "imp",
949       "implicit", "imp",
950       "implied", "imp",
951       "unconstrained", "uncon",
952       "unconst", "uncon",
953       "memory", "mem",
954       "length", "len",
955       "return", "ret",
956       "system", "sys",
957       NULL
958       } ;
959   char *current;
960   
961   while ((current = transform[i]) != NULL)
962     {
963       if (cstring_containsLit (res, current))
964         {
965           cstring_replaceLit (res, current, transform[i+1]);
966         }
967       i += 2;
968     }
969
970   /* remove whitespace, -'s, and _'s */
971   cstring_stripChars (res, " -_");
972   return res;
973 }
974
975 flagcode
976 flags_identifyFlag (cstring s)
977 {
978   return flags_identifyFlagAux (s, FALSE);
979 }
980
981 flagcode
982 flags_identifyFlagQuiet (cstring s)
983 {
984   return flags_identifyFlagAux (s, TRUE);
985 }
986
987 static flagcode
988 flags_identifyFlagAux (cstring s, bool quiet)
989 {
990   cstring cflag;
991   flagcode res;
992
993   if (cstring_length (s) == 0) {
994     /* evs 2000-06-25: A malformed flag. */
995     return INVALID_FLAG;
996   }
997
998   if (cstring_firstChar (s) == 'I')
999     {
1000       return FLG_INCLUDEPATH; /* no space required after -I */
1001     }
1002
1003   if (cstring_firstChar (s) == 'S') 
1004     {
1005       return FLG_SPECPATH;    /* no space required after -S */
1006     }
1007
1008   if (cstring_firstChar (s) == 'D') 
1009     {
1010       return FLG_DEFINE;      /* no space required after -D */
1011     }
1012
1013   if (cstring_firstChar (s) == 'U') 
1014     {
1015       return FLG_UNDEFINE;    /* no space required after -D */
1016     }
1017
1018   cflag = canonicalizeFlag (s);
1019   res = INVALID_FLAG;
1020
1021   allFlags (f)
1022     {
1023       if (cstring_equal (cstring_fromChars (f.flag), cflag))
1024         {
1025           res = f.code;
1026           break;
1027         }
1028     } end_allFlags;
1029   
1030   if (res == INVALID_FLAG)
1031     {
1032       /*
1033       ** Synonyms
1034       */
1035       
1036       if (cstring_equalLit (cflag, "pred"))
1037         {
1038           res = FLG_PREDBOOL;
1039         }
1040       else if (cstring_equalLit (cflag, "modobserverstrict"))
1041         {
1042           res = FLG_MODOBSERVERUNCON;
1043         }
1044       else if (cstring_equalLit (cflag, "czechnames"))
1045         {
1046           res = FLG_CZECH;
1047         }
1048       else if (cstring_equalLit (cflag, "slovaknames"))
1049         {
1050           res = FLG_SLOVAK;
1051         }
1052       else if (cstring_equalLit (cflag, "czechoslovaknames"))
1053         {
1054           res = FLG_CZECHOSLOVAK;
1055         }
1056       else if (cstring_equalLit (cflag, "globunspec")
1057                || cstring_equalLit (cflag, "globuncon"))
1058         {
1059           res = FLG_GLOBUNSPEC;
1060         }
1061       else if (cstring_equalLit (cflag, "modglobsunspec")
1062                || cstring_equalLit (cflag, "modglobsuncon")
1063                || cstring_equalLit (cflag, "modglobsnomods"))
1064         {
1065           res = FLG_MODGLOBSUNSPEC;
1066         }
1067       else if (cstring_equalLit (cflag, "export"))
1068         {
1069           res = FLG_EXPORTANY;
1070         }
1071       else if (cstring_equalLit (cflag, "macrospec"))
1072         {
1073           res = FLG_MACRODECL;
1074         }
1075       else if (cstring_equalLit (cflag, "ansireservedlocal"))
1076         {
1077           res = FLG_ISORESERVEDLOCAL;
1078         }
1079       else if (cstring_equalLit (cflag, "warnposix"))
1080         {
1081           res = FLG_WARNPOSIX;
1082         }
1083       else if (cstring_equalLit (cflag, "defuse"))
1084         {
1085           res = FLG_USEDEF;
1086         }
1087       else if (cstring_equalLit (cflag, "macroundef"))
1088         {
1089           res = FLG_MACROUNDEF;
1090         }
1091       else if (cstring_equalLit (cflag, "showcol"))
1092         {
1093           res = FLG_SHOWCOL;
1094         }
1095       else if (cstring_equalLit (cflag, "intbool"))
1096         {
1097           res = FLG_BOOLINT;
1098         }
1099       else if (cstring_equalLit (cflag, "intchar"))
1100         {
1101           res = FLG_CHARINT;
1102         }
1103       else if (cstring_equalLit (cflag, "intenum"))
1104         {
1105           res = FLG_ENUMINT;
1106         }
1107       else if (cstring_equalLit (cflag, "intlong"))
1108         {
1109           res = FLG_LONGINT;
1110         }
1111       else if (cstring_equalLit (cflag, "intshort"))
1112         {
1113           res = FLG_SHORTINT;
1114         }
1115       /*
1116       ** Backwards compatibility for our American friends...
1117       */
1118       
1119       else if (cstring_equalLit (cflag, "ansilib"))
1120         {
1121           res = FLG_ANSILIB;
1122         }
1123       else if (cstring_equalLit (cflag, "ansistrictlib"))
1124         {
1125           res = FLG_STRICTLIB;
1126         }
1127       else if (cstring_equalLit (cflag, "skipansiheaders"))
1128         {
1129           res = FLG_SKIPISOHEADERS;
1130         }
1131       else if (cstring_equalLit (cflag, "ansireserved"))
1132         {
1133           res = FLG_ISORESERVED;
1134         }
1135       else if (cstring_equalLit (cflag, "ansireservedinternal"))
1136         {
1137           res = FLG_ISORESERVEDLOCAL;
1138         }
1139       
1140       /*
1141       ** Obsolete Flags
1142       */
1143       
1144       else if (cstring_equalLit (cflag, "accessunspec"))
1145         {
1146           if (!quiet) 
1147             {
1148               llerror_flagWarning 
1149                 (cstring_makeLiteral
1150                  ("accessunspec flag is no longer supported.  It has been replaced by accessmodule, accessfile and "
1151                   "accessfunction to provide more precise control of accessibility "
1152                   "of representations.  For more information, "
1153                   "see splint -help accessmodule"));
1154             }
1155           
1156           res = SKIP_FLAG;
1157         }
1158       else if (cstring_equalLit (cflag, "ansilimits"))
1159         {
1160           llerror_flagWarning 
1161             (cstring_makeLiteral
1162              ("ansilimits flag is no longer supported.  It has been replaced by ansi89limits and "
1163               "iso99limits to select either the lower translation limits imposed by the ANSI89 "
1164               "standard or the typically higher limits prescribed by ISO C99."));
1165           
1166           res = SKIP_FLAG;
1167         }
1168       else if (cstring_equalLit (cflag, "staticmods"))
1169         {
1170           if (!quiet) 
1171             {
1172               llerror_flagWarning 
1173                 (cstring_makeLiteral
1174                  ("staticmods flag is obsolete.  You probably "
1175                   "want impcheckmodstatics.  For more information, "
1176                   "see splint -help impcheckmodstatics"));
1177             }
1178           
1179           res = SKIP_FLAG;
1180         }
1181       else if (cstring_equalLit (cflag, "bool"))
1182         {
1183           if (!quiet) 
1184             {
1185               llerror_flagWarning
1186                 (cstring_makeLiteral ("bool flag is obsolete.  It never really "
1187                                       "made sense in the first place."));
1188             }
1189           
1190           res = SKIP_FLAG;
1191         }
1192       else if (cstring_equalLit (cflag, "shiftsigned"))
1193         {
1194           if (!quiet) 
1195             {
1196               llerror_flagWarning
1197                 (cstring_makeLiteral ("shiftsigned flag is obsolete.  You probably "
1198                                       "want bitwisesigned, shiftnegative or shiftimplementation."));
1199             }
1200           
1201           res = SKIP_FLAG;
1202         }
1203       else if (cstring_equalLit (cflag, "ansi"))
1204         {
1205           if (!quiet) 
1206             {
1207               llerror_flagWarning
1208                 (cstring_makeLiteral ("ansi flag is obsolete.  You probably "
1209                                       "want noparams and/or oldstyle."));
1210             }
1211           
1212           res = SKIP_FLAG;
1213         }
1214       else if (cstring_equalLit (cflag, "usestderr"))
1215         {
1216           if (!quiet)
1217             {
1218               llerror_flagWarning 
1219                 (cstring_makeLiteral
1220                  ("usestderr flag is obsolete. This has been replaced "
1221                   "by more precise flags for controlling the warning, "
1222                   "status message and fatal error streams independently: message-stream-stdout, "
1223                   "message-stream-stderr, message-stream <file>, "
1224                   "warning-stream-stdout, warning-stream-stderr, warning-stream <file>, "
1225                   "error-stream-stdout, error-stream-stderr, error-stream <file>."));
1226             }
1227           
1228           res = SKIP_FLAG;
1229         }
1230
1231       else if (cstring_equalLit (cflag, "stdio"))
1232         {
1233           if (!quiet) 
1234             {
1235               llerror_flagWarning 
1236                 (cstring_makeLiteral
1237                  ("stdio flag is obsolete.  You may "
1238                   "want strictlib or one of the gloabls "
1239                   "checking flags.  For more information, "
1240                   "see splint -help strictlib or splint -help flags globals"));
1241             }
1242           
1243           res = SKIP_FLAG;
1244         }
1245       else if (flags_isModeName (cflag))
1246         {
1247           res = MODENAME_FLAG;
1248         }
1249       else
1250         {
1251           res = INVALID_FLAG;
1252         }
1253     }
1254
1255   cstring_free (cflag);
1256   return res;
1257 }
1258
1259 void flags_setValueFlag (flagcode opt, cstring arg)
1260 {
1261   switch (opt)
1262     {
1263     case FLG_EXPECT:
1264     case FLG_LCLEXPECT:
1265     case FLG_LIMIT:  
1266     case FLG_LINELEN:
1267     case FLG_INDENTSPACES:
1268     case FLG_LOCINDENTSPACES:
1269     case FLG_BUGSLIMIT:
1270     case FLG_EXTERNALNAMELEN:
1271     case FLG_INTERNALNAMELEN:
1272     case FLG_CONTROLNESTDEPTH:
1273     case FLG_STRINGLITERALLEN:
1274     case FLG_NUMSTRUCTFIELDS:
1275     case FLG_NUMENUMMEMBERS:
1276     case FLG_INCLUDENEST:
1277       {
1278         int val = cstring_toPosInt (arg);
1279
1280         if (val < 0)
1281           {
1282             llerror 
1283               (FLG_BADFLAG,
1284                message 
1285                ("Flag %s must be followed by a positive number number.  "
1286                 "Followed by %s",
1287                 flagcode_unparse (opt), arg));
1288           }
1289         else
1290           {
1291             context_setValueAndFlag (opt, val);
1292           }
1293       }
1294       break;
1295     case FLG_COMMENTCHAR:
1296       {
1297         if (cstring_length (arg) != 1)
1298           {
1299             llfatalerrorLoc
1300               (message
1301                ("Flag %s should be followed by a single character.  Followed by %s",
1302                 flagcode_unparse (opt), arg));
1303           }
1304         else
1305           {
1306             context_setCommentMarkerChar (cstring_firstChar (arg));
1307           }
1308       }
1309       break;
1310       BADDEFAULT;
1311     }
1312 }
1313
1314 void flags_setStringFlag (flagcode opt, /*@only@*/ cstring arg)
1315 {
1316   switch (opt)
1317     {
1318     case FLG_TMPDIR:
1319       {
1320         if (cstring_lastChar (arg) == CONNECTCHAR)
1321           {
1322             context_setString (opt, arg);
1323           }
1324         else
1325           {
1326             context_setString (opt, cstring_appendChar (arg, CONNECTCHAR));
1327           }
1328         break;
1329       }
1330     default:
1331       {
1332         context_setString (opt, arg);
1333         break;
1334       }
1335     }
1336 }
1337
1338 cstring
1339 describeModes ()
1340 {
1341   cstring s = cstring_makeLiteral ("Flag                    ");
1342   cstringSList sflags = sortedFlags ();
1343
1344   allModes (modename)
1345     {
1346       s = message ("%q%9s", s, cstring_fromChars (modename));
1347     } end_allModes;
1348   
1349   s = message ("%q\n", s);
1350
1351   cstringSList_elements (sflags, flagname)
1352     {
1353       flagcode code = flags_identifyFlag (flagname);
1354       fflag currentflag = flags[code];
1355       
1356       if (mstring_isDefined (currentflag.desc) && flagcode_isModeFlag (code))
1357         {
1358           s = message ("%q\n%27s", s, 
1359                        cstring_fromChars (currentflag.flag));
1360           
1361           allModes (modename)
1362             {
1363               context_setMode (cstring_fromChars (modename));
1364               
1365               if (context_getFlag (code))
1366                 {
1367                   s = message ("%q%9s", s, cstring_makeLiteralTemp ("+"));
1368                 }
1369               else
1370                 {
1371                   s = message ("%q%9s", s, cstring_makeLiteralTemp (" "));
1372                 }
1373
1374               context_resetModeFlags ();
1375             } end_allModes;
1376         }
1377     } end_cstringSList_elements;
1378   
1379   cstringSList_free (sflags);
1380
1381   s = cstring_appendChar (s, '\n');
1382
1383   return (s);
1384 }
1385
1386 # if 0
1387 static /*@unused@*/ cstring
1388 listModes (void)
1389 {
1390   cstring s = cstring_makeLiteral ("\t");
1391   int i = 0;
1392
1393   allModes (modename)
1394     {
1395       if (i != 0 && (i % 4 == 0))
1396         {
1397           s = message ("%q\n\t%15s", s, cstring_fromChars (modename));
1398         }
1399       else
1400         {
1401           s = message ("%q%15s", s, cstring_fromChars (modename));
1402         }
1403       i++;
1404     } end_allModes;
1405
1406   return s;
1407 }
1408 # endif
1409
1410 bool
1411 flags_isModeName (cstring s)
1412 {
1413   allModes (modename)
1414     {
1415       if (mstring_isDefined (modename))
1416         {
1417           if (cstring_equalLit (s, modename))
1418             {
1419               return TRUE;
1420             }
1421         }
1422      } end_allModes;
1423
1424   return FALSE;
1425 }
1426
1427 extern bool flagcode_hasArgument (flagcode f)
1428 {
1429   return (flags[f].argtype != ARG_NONE);
1430 }
1431
1432 extern bool flagcode_hasNumber (flagcode f)
1433 {
1434   return (flags[f].argtype == ARG_NUMBER);
1435 }
1436
1437 extern bool flagcode_hasChar (flagcode f)
1438 {
1439   return (flags[f].argtype == ARG_CHAR);
1440 }
1441
1442 extern bool flagcode_hasString (flagcode f)
1443 {
1444   return (flags[f].argtype == ARG_STRING
1445           || flags[f].argtype == ARG_FILE
1446           || flags[f].argtype == ARG_DIRECTORY
1447           || flags[f].argtype == ARG_PATH);
1448 }
1449
1450 extern int flagcode_valueIndex (flagcode f)
1451 {
1452   /*@unchecked@*/ static bool initialized = FALSE;
1453   int i;
1454   /*@unchecked@*/ static flagcode valueFlags[NUMVALUEFLAGS];
1455   
1456   if (!initialized)
1457     {
1458       int nv = 0;
1459
1460       allFlagCodes (code)
1461         {
1462           if (flagcode_hasNumber (code) || flagcode_hasChar (code))
1463             {
1464               llassert (nv < NUMVALUEFLAGS);
1465               DPRINTF (("Value flag: %s [%d]", flagcode_unparse (code), (int) code));
1466               valueFlags[nv] = code;
1467               nv++;
1468             }
1469         } end_allFlagCodes;
1470
1471       llassertprint (nv == NUMVALUEFLAGS,
1472                      ("Number of value flags: %d (expected %d)",
1473                       nv, (int) NUMVALUEFLAGS));
1474       initialized = TRUE;
1475     }
1476
1477   for (i = 0; i < NUMVALUEFLAGS; i++)
1478     {
1479       /* static valueFlags must be defined */
1480       /*@-usedef@*/
1481       if (f == valueFlags[i]) /*@=usedef@*/
1482         {
1483           return i;
1484         }
1485     }
1486
1487   fprintf (stderr, "Cannot find value flag: %d", (int) f);
1488   exit (EXIT_FAILURE);
1489   /* Cannot do this...might call recursively...
1490   llfatalbug (message ("Cannot fine value flag: %d", (int) f));
1491   BADEXIT;
1492   */
1493 }
1494
1495 extern int flagcode_stringIndex (flagcode f)
1496 {
1497   /*@unchecked@*/ static bool initialized = FALSE;
1498   /*@unchecked@*/ static flagcode stringFlags[NUMSTRINGFLAGS];
1499   int i;
1500
1501
1502   if (!initialized)
1503     {
1504       int nv = 0;
1505
1506       allFlagCodes (code)
1507         {
1508           if (flagcode_hasString (code))
1509             {
1510               llassertprint (nv < NUMSTRINGFLAGS, ("Incorrect number of string flags: %d (need at least %d)", NUMSTRINGFLAGS, nv));
1511               stringFlags[nv] = code;
1512               nv++;
1513             }
1514         } end_allFlagCodes;
1515
1516       llassertprint (nv == NUMSTRINGFLAGS,
1517                      ("number of string flags: %d (expected %d)",
1518                       nv, NUMSTRINGFLAGS));
1519       initialized = TRUE;
1520     }
1521
1522   for (i = 0; i < NUMSTRINGFLAGS; i++)
1523     {
1524       /*@-usedef@*/ if (f == stringFlags[i]) /*@=usedef@*/
1525         {
1526           return i;
1527         }
1528     }
1529
1530   llbug (message ("Bad string flag: %s", flagcode_unparse (f)));
1531   BADEXIT;
1532 }
1533
1534 bool flagcode_isNamePrefixFlag (flagcode f)
1535 {
1536   switch (f)
1537     {
1538     case FLG_MACROVARPREFIX:
1539     case FLG_TAGPREFIX:
1540     case FLG_ENUMPREFIX:
1541     case FLG_FILESTATICPREFIX:
1542     case FLG_GLOBPREFIX:
1543     case FLG_TYPEPREFIX:
1544     case FLG_EXTERNALPREFIX:
1545     case FLG_LOCALPREFIX:
1546     case FLG_UNCHECKEDMACROPREFIX:
1547     case FLG_CONSTPREFIX:
1548     case FLG_ITERPREFIX:
1549     case FLG_DECLPARAMPREFIX:
1550       return TRUE;
1551     default:
1552       return FALSE;
1553     }
1554 }
1555
1556 static cstring findLarchPathFile (/*@temp@*/ cstring s)
1557 {
1558   cstring pathName;
1559   filestatus status;
1560   
1561   status = osd_getPath (context_getLarchPath (), s, &pathName);
1562   
1563   if (status == OSD_FILEFOUND)
1564     {
1565       return pathName;
1566     }
1567   else if (status == OSD_FILENOTFOUND)
1568     {
1569       showHerald ();
1570       lldiagmsg (message ("Cannot find file on LARCH_PATH: %s", s));
1571     }
1572   else if (status == OSD_PATHTOOLONG)
1573     {
1574       /* Directory and filename are too long.  Report error. */
1575       llbuglit ("soure_getPath: Filename plus directory from search path too long");
1576     }
1577   else
1578     {
1579       BADBRANCH;
1580     }
1581
1582   return cstring_undefined;
1583 }
1584
1585 static void addLarchPathFile (fileIdList files, /*@temp@*/ cstring s)
1586 {
1587   cstring pathName = findLarchPathFile (s);
1588
1589   if (cstring_isDefined (pathName))
1590     {
1591       if (fileTable_exists (context_fileTable (), pathName))
1592         {
1593           showHerald ();
1594           lldiagmsg (message ("File listed multiple times: %s", pathName));
1595           cstring_free (pathName);
1596         }
1597       else
1598         {
1599           fileIdList_add (files, fileTable_addFileOnly (context_fileTable (), pathName));
1600         }
1601     }
1602 }
1603
1604
1605 static void addFile (fileIdList files, /*@only@*/ cstring s)
1606 {
1607   if (fileTable_exists (context_fileTable (), s))
1608     {
1609       showHerald ();
1610       lldiagmsg (message ("File listed multiple times: %s", s));
1611       cstring_free (s);
1612     }
1613   else
1614     {
1615       fileIdList_add (files, fileTable_addFileOnly (context_fileTable (), s));
1616     }
1617 }
1618
1619 static void addXHFile (fileIdList files, /*@temp@*/ cstring s)
1620 {
1621   cstring pathName = findLarchPathFile (s);
1622
1623   if (cstring_isDefined (pathName))
1624     {
1625       if (fileTable_exists (context_fileTable (), pathName))
1626         {
1627           showHerald ();
1628           lldiagmsg (message ("File listed multiple times: %s", s));
1629         }
1630       else
1631         {
1632           fileIdList_add (files, fileTable_addXHFile (context_fileTable (), pathName));
1633         }
1634     }
1635
1636   cstring_free (pathName);
1637 }
1638
1639 void
1640 flags_processFlags (bool inCommandLine, 
1641                     fileIdList xfiles,
1642                     fileIdList cfiles,
1643                     fileIdList lclfiles,
1644                     fileIdList mtfiles,
1645                     cstringList *passThroughArgs,
1646                     int argc, char **argv)
1647 {
1648   int i;
1649   cstringSList fl = cstringSList_undefined;
1650     
1651   for (i = 0; i < argc; i++)
1652     {
1653       char *thisarg;
1654
1655       llassert (argv != NULL);
1656       thisarg = argv[i];
1657       
1658       DPRINTF (("process thisarg [%d]: %s", i, thisarg));
1659
1660       if (*thisarg == '-' || *thisarg == '+')
1661         {
1662           bool set = (*thisarg == '+');
1663           cstring flagname;
1664           flagcode opt;
1665
1666           if (*(thisarg + 1) == '-') { /* allow -- before flags */
1667             flagname = cstring_fromChars (thisarg + 2);
1668           } else {
1669             flagname = cstring_fromChars (thisarg + 1);
1670           }
1671
1672           opt = flags_identifyFlag (flagname);
1673           DPRINTF (("Flag [%s]: %s", flagname, flagcode_unparse (opt)));
1674           
1675           if (flagcode_isInvalid (opt))
1676             {
1677               DPRINTF (("Error!"));
1678               voptgenerror (FLG_BADFLAG,
1679                             message ("Unrecognized option: %s", 
1680                                      cstring_fromChars (thisarg)),
1681                             g_currentloc);
1682             }
1683           else if (flagcode_isHelpFlag (opt))
1684             {
1685               if (inCommandLine)
1686                 {
1687                   voptgenerror (FLG_BADFLAG,
1688                                 message ("Help flag must be first on the command line: %s", 
1689                                          cstring_fromChars (thisarg)),
1690                                 g_currentloc);
1691                 }
1692               else
1693                 {
1694                   voptgenerror (FLG_BADFLAG,
1695                                 message ("Help flags can only be used on the command line: %s", 
1696                                          cstring_fromChars (thisarg)),
1697                                 g_currentloc);
1698                 }
1699             }
1700           else if (flagcode_isPassThrough (opt)) /* preprocessor flag: -D or -U */
1701             { 
1702               /*
1703               ** Following space is optional, don't include the -
1704               */
1705               
1706               *passThroughArgs = cstringList_add (*passThroughArgs, 
1707                                                   cstring_fromCharsNew (thisarg + 1));
1708             }
1709           else if (opt == FLG_INCLUDEPATH || opt == FLG_SPECPATH)
1710             {
1711               if (mstring_length (thisarg) < 2) {
1712                 BADBRANCH;
1713               } else {
1714                 if (mstring_equal (thisarg, "-I-")) {
1715                   cppAddIncludeDir (cstring_fromChars (thisarg)); /* Need to handle this specially. */
1716                 } else {
1717                   cstring dir = cstring_suffix (cstring_fromChars (thisarg), 2); /* skip over -I */
1718                   
1719                   DPRINTF (("Length of thisarg [%s] %d", thisarg, cstring_length (thisarg)));
1720                   
1721                   if (cstring_length (dir) == 0) {
1722                     DPRINTF (("space after directory: "));
1723                     if (++i < argc) {
1724                       dir = cstring_fromChars (argv[i]);
1725                     } else {
1726                       voptgenerror
1727                         (FLG_BADFLAG,
1728                          message
1729                          ("Flag %s must be followed by a directory name",
1730                           flagcode_unparse (opt)),
1731                          g_currentloc);
1732                     }
1733                   } 
1734                   
1735                   DPRINTF (("Got directory: [%s]", dir));
1736                   
1737                   switch (opt)
1738                     {
1739                     case FLG_INCLUDEPATH:
1740                       cppAddIncludeDir (dir);
1741                       /*@switchbreak@*/ break;
1742                     case FLG_SPECPATH:
1743                       /*@-mustfree@*/
1744                       g_localSpecPath = cstring_toCharsSafe
1745                         (message ("%s%h%s", 
1746                                   cstring_fromChars (g_localSpecPath), 
1747                                   PATH_SEPARATOR,
1748                                   dir));
1749                       /*@=mustfree@*/
1750                       /*@switchbreak@*/ break;
1751                       BADDEFAULT;
1752                     }
1753                 }
1754               }
1755             }
1756           else if (flagcode_isModeName (opt))
1757             {
1758               context_setMode (flagname);
1759             }
1760           else if (inCommandLine && flagcode_isMessageControlFlag (opt))
1761             {
1762               /*
1763               ** Processed on first pass
1764               */
1765               
1766               if (flagcode_hasArgument (opt))
1767                 {
1768                   ++i;
1769                 }
1770             }
1771           else
1772             {
1773               /*
1774               ** A normal control flag
1775               */
1776
1777               context_userSetFlag (opt, set);
1778               
1779               if (flagcode_hasArgument (opt))
1780                 {
1781                   if (flagcode_hasNumber (opt))
1782                     {
1783                       if (++i < argc)
1784                         {
1785                           flags_setValueFlag (opt, cstring_fromCharsNew (argv[i]));
1786                         }
1787                       else
1788                         {
1789                           voptgenerror
1790                             (FLG_BADFLAG,
1791                              message
1792                              ("Flag %s must be followed by a number",
1793                               flagcode_unparse (opt)),
1794                              g_currentloc);
1795                         }
1796                     } 
1797                   else if (flagcode_hasChar (opt))
1798                     {
1799                       if (++i < argc)
1800                         {
1801                           flags_setValueFlag (opt, cstring_fromCharsNew (argv[i]));
1802                         }
1803                       else
1804                         {
1805                           voptgenerror
1806                             (FLG_BADFLAG,
1807                              message
1808                              ("Flag %s must be followed by a character",
1809                               flagcode_unparse (opt)),
1810                              g_currentloc);
1811                         }
1812                     } 
1813                   else if (flagcode_hasString (opt)
1814                            || opt == FLG_INIT || opt == FLG_OPTF)
1815                     {
1816                       if (++i < argc)
1817                         {
1818                           /*drl 10/21/2002
1819                             Changed this because arg can be freed when it's passed to
1820                             lslinit_setInitFile and freeing argv[i] causes a seg fault
1821                           */
1822                           cstring arg =  cstring_fromCharsNew (argv[i]);
1823                           
1824                           if (opt == FLG_OPTF)
1825                             {
1826                               if (inCommandLine)
1827                                 {
1828                                   ; /* -f already processed */
1829                                 }
1830                               else
1831                                 {
1832                                   (void) rcfiles_read (arg, passThroughArgs, TRUE);
1833                                 }
1834                             }
1835                           else if (opt == FLG_INIT)
1836                             {
1837                               lslinit_setInitFile (inputStream_create 
1838                                                    (arg, 
1839                                                     cstring_makeLiteralTemp (LCLINIT_SUFFIX),
1840                                                     FALSE));
1841                               break;
1842                             }
1843                           else
1844                             {
1845                               DPRINTF (("String flag: %s / %s",
1846                                         flagcode_unparse (opt), arg));
1847                               if (opt == FLG_MTSFILE)
1848                                 {
1849                                   /*
1850                                   ** arg identifies mts files
1851                                   */
1852                                   cstring tmp =  message ("%s%s", arg, MTS_EXTENSION);
1853                                   addLarchPathFile (mtfiles, tmp);
1854                                   cstring_free (tmp);
1855                                   tmp = message ("%s%s", arg, XH_EXTENSION);
1856                                   addXHFile (xfiles, tmp);
1857                                   cstring_free (tmp);
1858                                 }
1859                               else
1860                                 {
1861                                   flags_setStringFlag (opt, cstring_copy (arg));
1862                                 }
1863                             }
1864                         }
1865                       else
1866                         {
1867                           voptgenerror
1868                             (FLG_BADFLAG,
1869                              message
1870                              ("Flag %s must be followed by a string",
1871                               flagcode_unparse (opt)),
1872                              g_currentloc);
1873                         }
1874                     }
1875                   else
1876                     {
1877                       /* no argument */
1878                     }
1879                 }
1880             }
1881         }
1882       else /* its a filename */
1883         {
1884           DPRINTF (("Adding filename: %s", thisarg));
1885           fl = cstringSList_add (fl, cstring_fromChars (thisarg));
1886         }
1887     }
1888   
1889   /*
1890   ** create lists of C and LCL files
1891   */
1892   
1893   if (inCommandLine)
1894     {
1895       cstringSList_elements (fl, current)
1896         {
1897           cstring ext = fileLib_getExtension (current);
1898           
1899           if (cstring_isUndefined (ext))
1900             {
1901               /* no extension --- both C and LCL with default extensions */
1902               
1903               addFile (cfiles, message ("%s%s", current, C_EXTENSION));
1904               addFile (lclfiles, message ("%s%s", current, LCL_EXTENSION));
1905             }
1906           else if (cstring_equal (ext, XH_EXTENSION))
1907             {
1908               addXHFile (xfiles, current);
1909             }
1910           else if (cstring_equal (ext, PP_EXTENSION))
1911             {
1912               if (!context_getFlag (FLG_NOPP))
1913                 {
1914                   voptgenerror 
1915                     (FLG_FILEEXTENSIONS,
1916                      message ("File extension %s used without +nopp flag (will be processed as C source code): %s", 
1917                               ext, current),
1918                      g_currentloc);
1919                 }
1920               
1921               addFile (cfiles, cstring_copy (current));
1922             }
1923           else if (cstring_equal (ext, LCL_EXTENSION)) 
1924             {
1925               addFile (lclfiles, cstring_copy (current));
1926             }
1927           else if (fileLib_isCExtension (ext))
1928             {
1929               addFile (cfiles, cstring_copy (current));
1930             }
1931           else if (cstring_equal (ext, MTS_EXTENSION))
1932             {
1933               addLarchPathFile (mtfiles, current);
1934             }
1935           else 
1936             {
1937               voptgenerror 
1938                 (FLG_FILEEXTENSIONS,
1939                  message ("Unrecognized file extension: %s (assuming %s is C source code)", 
1940                           current, ext),
1941                  g_currentloc);
1942               
1943               addFile (cfiles, cstring_copy (current));
1944             }
1945         } end_cstringSList_elements;
1946     }
1947   else
1948     {
1949       if (cstringSList_size (fl) != 0)
1950         {
1951           /* Cannot list files in .splintrc files */
1952           voptgenerror (FLG_BADFLAG, 
1953                         message ("Cannot list files in .splintrc files: %s (probable missing + or -)",
1954                                  cstringSList_unparse (fl)),
1955                         g_currentloc);
1956         }
1957     }
1958
1959   cstringSList_free (fl); /* evans 2002-07-12: why wasn't this reported!?? */
1960 }
1961
1962 int flagcode_priority (/*@unused@*/ flagcode code)
1963 {
1964   /*
1965   ** For now, we do a really simple prioritization: all are 1
1966   */
1967
1968   return 1;
1969 }
This page took 0.195437 seconds and 3 git commands to generate.