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