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