2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2003 University of Virginia,
4 ** Massachusetts Institute of Technology
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.
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.
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.
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
28 # include "splintMacros.nf"
36 ** from the CC man page:
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).
44 /* needed for string literals literals */
48 /*@null@*/ /*@observer@*/ char *name;
49 /*@null@*/ /*@observer@*/ char *describe;
52 static flagcatinfo categories[] =
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 */
122 ARG_NUMBER, /* number */
124 ARG_STRING, /* string */
125 ARG_FILE, /* filename (also a string) */
126 ARG_DIRECTORY, /* directory (also a string) */
132 /* Make Microsoft VC++ happy */
133 # pragma warning (disable:4715)
136 static /*@observer@*/ cstring argcode_unparse (argcode arg)
140 case ARG_STRING: return cstring_makeLiteralTemp ("string");
141 case ARG_FILE: return cstring_makeLiteralTemp ("filename");
142 case ARG_DIRECTORY: return cstring_makeLiteralTemp ("directory");
143 case ARG_PATH: return cstring_makeLiteralTemp ("path");
144 case ARG_NUMBER: return cstring_makeLiteralTemp ("number");
145 case ARG_CHAR: return cstring_makeLiteralTemp ("character");
154 # pragma warning (default : 4715)
160 bool isSpecial; /* setting this flag may set other flags (or values) */
161 bool isIdem; /* idempotent - always sets to TRUE */
162 bool isGlobal; /* cannot be set locally (using control comments) */
163 bool isModeFlag; /* set by modes */
165 /*@observer@*/ char *flag;
167 /*@observer@*/ /*@null@*/ char *desc;
173 typedef fflag flaglist[];
175 # include "flags.def"
177 /*@iter allFlags (yield observer fflag f); @*/
178 # define allFlags(m_f) \
179 { /*@+enumint@*/ flagcode m_i; for (m_i = 0; m_i < NUMFLAGS; m_i++) { fflag m_f = flags[m_i]; /*@=enumint@*/
180 # define end_allFlags }}
182 static bn_mstring mode_names[] =
184 "weak", "standard", "checks", "strict", NULL,
187 /*@iter allModes (yield bn_mstring modename)@*/
188 # define allModes(m_m) \
189 { int m_ii = 0; while (mstring_isDefined (mode_names[m_ii])) \
190 { bn_mstring m_m = mode_names[m_ii]; m_ii++;
192 # define end_allModes }}
196 static cstring getFlagModeSettings (flagcode p_flag) /*@modifies internalState@*/ ;
197 static cstring describeFlagCode (flagcode p_flag) /*@*/ ;
198 static cstringSList sortedFlags (void) /*@*/ ;
199 static /*@observer@*/ cstring categoryName (flagkind p_kind) /*@*/ ;
201 static flagcode flags_identifyFlagAux (cstring p_s, bool p_quiet) /*@modifies g_warningstream@*/ ;
204 static /*@unused@*/ cstring listModes (void) /*@*/ ;
207 bool flagcode_isSpecialFlag (flagcode f)
209 return (flags[f].isSpecial);
212 bool flagcode_isGlobalFlag (flagcode f)
214 return (flags[f].isGlobal);
217 bool flagcode_isIdemFlag (flagcode f)
219 return (flags[f].isIdem);
222 bool flagcode_isModeFlag (flagcode f)
224 return (flags[f].isModeFlag);
227 bool flagcode_isNameChecksFlag (flagcode f)
229 return (flags[f].main == FK_NAMES);
232 bool flagcode_isHelpFlag (flagcode f)
234 return f == FLG_HELP;
237 bool flagcode_isMessageControlFlag (flagcode f)
240 ** True if opt controls the display of messages.
241 ** These flags must be processed first.
244 return (f == FLG_SHOWSCAN
246 || f == FLG_PARENFILEFORMAT
247 || f == FLG_MESSAGESTREAMSTDERR
248 || f == FLG_MESSAGESTREAMSTDOUT
249 || f == FLG_WARNINGSTREAMSTDERR
250 || f == FLG_WARNINGSTREAMSTDOUT
251 || f == FLG_ERRORSTREAMSTDERR
252 || f == FLG_ERRORSTREAMSTDOUT
253 || f == FLG_MESSAGESTREAM
254 || f == FLG_WARNINGSTREAM
255 || f == FLG_ERRORSTREAM
256 || f == FLG_STREAMOVERWRITE);
260 ** Internal consistency check on the flags.
263 void flags_initMod ()
268 if (flags[code].code != code)
271 "*** ERROR: inconsistent flag %s / %d / %d",
273 flags[code].code, code);
275 llbug (message ("*** ERROR: inconsistent flag %s / %d / %d",
276 cstring_fromChars (flags[code].flag),
277 flags[code].code, code));
290 char *buf = mstring_create (128);
294 if (f.nreported > 0 || f.nsuppressed > 0)
296 int nrep = f.nreported;
297 int nsup = f.nsuppressed;
298 cstring fs = cstring_fill (cstring_fromChars (f.flag), 23);
302 llmsgplain (cstring_makeLiteral
303 ("\nError Type Reported Suppressed\n"
304 "=================== ======== ========="));
308 (void) snprintf (buf, 128, "%s%7d %9d", cstring_toCharsSafe (fs), nrep, nsup);
314 llmsg (cstring_copy (cstring_fromChars (buf)));
320 cstring ts = cstring_fill (cstring_makeLiteralTemp ("Total"), 23);
322 llmsglit (" ======== =========");
324 (void) snprintf (buf, 128, "%s%7d %9d", cstring_toCharsSafe (ts), sumrep, sumsup);
326 llmsgplain (cstring_copy (cstring_fromChars (buf)));
335 flagcode_recordError (flagcode f)
337 if (f != INVALID_FLAG)
339 if (f == FLG_WARNFLAGS)
341 ; /* don't count these */
345 flags[f].nreported = flags[f].nreported + 1;
350 llcontbug (message ("flagcode_recordError: invalid flag: %d", (int) f));
355 flagcode_recordSuppressed (flagcode f)
357 llassertprint (f != INVALID_FLAG, ("flagcode: %s", flagcode_unparse (f)));
359 flags[f].nsuppressed = flags[f].nsuppressed + 1;
363 flagcode_numReported (flagcode f)
365 llassert (f != INVALID_FLAG);
367 return (flags[f].nreported);
370 /*@observer@*/ cstring
371 flagcodeHint (flagcode f)
373 llassert (f != INVALID_FLAG);
375 if (mstring_isDefined (flags[f].hint))
377 return (cstring_fromChars (flags[f].hint));
381 return (cstring_fromChars (flags[f].desc));
385 static int categorySize (flagkind kind) /*@*/
392 if (f.main == kind || f.sub == kind)
401 flagkind identifyCategory (cstring s)
405 for (i = 0; categories[i].kind != FK_NONE; i++)
407 if (mstring_isDefined (categories[i].name))
409 if (cstring_equalLit (s, categories[i].name))
411 return categories[i].kind;
419 static /*@observer@*/ cstring categoryName (flagkind kind)
423 for (i = 0; categories[i].kind != FK_NONE; i++)
425 if (categories[i].kind == kind)
427 return (cstring_fromChars (categories[i].name));
431 return (cstring_makeLiteralTemp ("<No Category>"));
434 static int categoryIndex (flagkind kind)
438 for (i = 0; categories[i].kind != FK_NONE; i++)
440 if (categories[i].kind == kind)
449 void printCategory (flagkind kind)
451 int index = categoryIndex (kind);
453 llassert (index >= 0);
454 llmsg (message ("%s (%d flags)\n\3%s\n\n",
455 cstring_fromChars (categories[index].name),
457 cstring_fromChars (categories[index].describe)));
461 if (f.main == kind || f.sub == kind)
463 llmsg (message (" %s\n\6%q", cstring_fromChars (f.flag),
464 describeFlagCode (f.code)));
470 listAllCategories (void)
474 for (i = 0; categories[i].kind != FK_NONE; i++)
476 flagkind kind = categories[i].kind ;
478 if (categories[i].describe != NULL)
480 llmsg (message ("%s (%d flags)\n\3%s",
483 cstring_fromChars (categories[i].describe)));
489 printAllFlags (bool desc, bool full)
493 cstringSList fl = sortedFlags ();
495 cstringSList_elements (fl, el)
498 tmp = cstring_copy(el);
499 llmsg (message ("%q\n\n", describeFlag (tmp)));
501 } end_cstringSList_elements ;
503 cstringSList_free (fl);
509 if (f.code != INVALID_FLAG && f.main != FK_OBSOLETE)
511 if (mstring_isDefined (f.desc))
515 llmsg (message ("%s --- %s", cstring_fromChars (f.flag),
516 cstring_fromChars (f.desc)));
525 printFlagManual (bool html)
528 ** Prints all flags by category, in order they appear in flags.def
531 flagkind lastCategory = FK_NONE;
535 cstring flagtype = cstring_undefined;
537 if (f.main != lastCategory)
541 llmsg (message ("\n<h4>%s</h4>\n", categoryName (f.main)));
545 llmsg (message ("\n%s\n%s\n",
546 categoryName (f.main),
547 cstring_makeLiteralTemp ("===================================")));
550 lastCategory = f.main;
553 if (f.argtype == ARG_NONE || f.argtype == ARG_SPECIAL)
557 flagname = message ("<tt>%s</tt>", cstring_fromChars (f.flag));
561 flagname = cstring_fromCharsNew (f.flag);
566 if (flagcode_hasString (f.code))
570 flagname = message ("<tt>%s <em><%s></em></tt>",
571 cstring_fromChars (f.flag), argcode_unparse (f.argtype));
575 flagname = message ("%s <%s>", cstring_fromChars (f.flag), argcode_unparse (f.argtype));
578 if (cstring_isDefined (context_getString (f.code)))
582 flagname = message ("%q <font color=\"blue\">[%s]</font>", flagname,
583 context_getString (f.code));
587 flagname = message ("%q [%s]", flagname,
588 context_getString (f.code));
592 else if (f.argtype == ARG_CHAR)
596 flagname = message ("<tt>%s <em><%s></em></tt> <font color=\"blue\">[%c]</font>",
597 cstring_fromChars (f.flag), argcode_unparse (f.argtype),
598 (char) context_getValue (f.code));
602 flagname = message ("%s <%s> [%c]", cstring_fromChars (f.flag), argcode_unparse (f.argtype),
603 (char) context_getValue (f.code));
608 llassert (f.argtype == ARG_NUMBER);
612 flagname = message ("<tt>%s <em><%s></em> <font color=\"blue\">[%d]</font>",
613 cstring_fromChars (f.flag), argcode_unparse (f.argtype),
614 context_getValue (f.code));
618 flagname = message ("%s <%s> [%d]", cstring_fromChars (f.flag), argcode_unparse (f.argtype),
619 context_getValue (f.code));
628 flagtype = message("%q<font color=\"green\">-</font>", flagtype);
632 flagtype = message("%q<->", flagtype);
640 flagtype = message ("%q<font color=\"green\"><em>global</em></font>", flagtype);
644 flagtype = message ("%q<G>", flagtype);
652 flagtype = message ("%q<font color=\"orange\"><em>shortcut</em></font>", flagtype);
656 flagtype = message("%q<S>", flagtype);
664 flagtype = message ("%q mode:<tt>%q</tt>>", flagtype, getFlagModeSettings (f.code));
668 flagtype = message ("%q<M:%q>", flagtype, getFlagModeSettings (f.code));
671 else /* its a plain flag */
675 flagtype = message ("%q plain:<tt>%s</tt>", flagtype,
676 cstring_makeLiteralTemp (context_getFlag (f.code) ? "+" : "-"));
680 flagtype = message ("%q<P:%s>", flagtype,
681 cstring_makeLiteralTemp (context_getFlag (f.code) ? "+" : "-"));
685 llmsg (message ("%s: %s", flagname, flagtype));
689 llgenindentmsgnoloc (cstring_makeLiteral ("<blockquote>"));
692 if (mstring_isDefined (f.hint))
694 llgenindentmsgnoloc (cstring_fromCharsNew (f.hint));
698 llgenindentmsgnoloc (message ("%q.", cstring_capitalize (cstring_fromChars (f.desc))));
703 llgenindentmsgnoloc (cstring_makeLiteral ("</blockquote>"));
709 describeMode (cstring mode)
711 cstringSList sflags = sortedFlags ();
712 cstring res = message ("Predefined mode %s sets: ", mode);
714 llassert (flags_isModeName (mode));
716 context_setMode (mode);
718 cstringSList_elements (sflags, flagname)
720 flagcode code = flags_identifyFlag (flagname);
721 fflag currentflag = flags[code];
723 if (mstring_isDefined (currentflag.desc) && flagcode_isModeFlag (code))
725 if (context_getFlag (code))
727 res = message ("%q\n +%s", res, cstring_fromChars (currentflag.flag));
731 res = message ("%q\n -%s", res, cstring_fromChars (currentflag.flag));
734 } end_cstringSList_elements;
736 cstringSList_free (sflags);
738 res = cstring_appendChar (res, '\n');
743 describeFlagCode (flagcode flag)
745 cstring ret = cstring_undefined;
748 if (flagcode_isInvalid (flag))
750 return (cstring_makeLiteral ("<invalid>"));
753 if (flagcode_isModeName (flag))
755 return (cstring_makeLiteral ("<mode flag>"));
758 context_resetAllFlags ();
761 ret = cstring_copy (cstring_fromChars (f.desc));
763 if (f.sub != FK_NONE)
765 ret = message ("%q\nCategories: %s, %s",
767 categoryName (f.main),
768 categoryName (f.sub));
772 if (f.main != FK_NONE)
774 cstring cname = categoryName (f.main);
776 if (cstring_isDefined (cname))
778 ret = message ("%q\nCategory: %s",
786 ret = message ("%q\nMode Settings: %q",
787 ret, getFlagModeSettings (flag));
791 ret = message ("%q\nDefault Setting: %s",
793 cstring_makeLiteralTemp (context_getFlag (flag) ? "+" : "-"));
798 ret = message("%q\nSet globally only", ret);
802 ret = message("%q\nSet locally", ret);
811 ret = message("%q\nNumeric Argument. Default: %d",
813 context_getValue (flag));
816 ret = message("%q\nCharacter Argument. Default: %h",
817 ret, (char) context_getValue (flag));
824 if (cstring_isDefined (context_getString (flag)))
826 ret = message("%q\n%q argument. Default: %s",
828 cstring_capitalize (argcode_unparse (f.argtype)),
829 context_getString (flag));
833 ret = message("%q\n%s argument. No default.",
835 cstring_capitalize (argcode_unparse (f.argtype)));
841 if (mstring_isDefined (f.hint))
843 ret = message("%q\n\3%s", ret, cstring_fromChars (f.hint));
849 static cstring getFlagModeSettings (flagcode flag)
851 cstring res = cstring_undefined;
855 context_setModeNoWarn (cstring_fromChars (mname));
857 res = message ("%q%s", res, cstring_makeLiteralTemp (context_getFlag (flag) ? "+" : "-"));
864 describeFlag (cstring flagname)
866 cstring oflagname = cstring_copy (flagname);
867 flagcode f = flags_identifyFlag (flagname);
869 if (flagcode_isSkip (f))
871 cstring_free (oflagname);
872 return cstring_undefined;
874 else if (flagcode_isValid (f))
876 if (cstring_equal (flagname, oflagname))
878 cstring_free (oflagname);
879 return (message ("%s\n\3%q", flagname, describeFlagCode (f)));
883 return (message ("%q (standardized name: %s)\n\3%q",
884 oflagname, flagname, describeFlagCode (f)));
889 if (flags_isModeName (flagname))
891 cstring_free (oflagname);
892 return describeMode (flagname);
896 return (message ("%q: <invalid flag>", oflagname));
904 cstringSList s = cstringSList_new ();
910 s = cstringSList_add (s, cstring_fromChars (f.flag));
914 cstringSList_alphabetize (s);
919 void printAlphaFlags ()
921 cstringSList fl = sortedFlags ();
923 cstringSList_printSpaced (fl, 3, 1, context_getLineLen () - 25);
924 cstringSList_free (fl);
927 /*@observer@*/ cstring
928 flagcode_unparse (flagcode code)
930 if (code == INVALID_FLAG)
932 return cstring_makeLiteralTemp ("<invalid flag>");
935 return cstring_fromChars (flags[code].flag);
939 ** Transforms a flag into its cannonical form.
941 ** The following transformations are made:
947 ** parameter -> param
948 ** unrecognized -> unrecog
950 ** declaration -> decl
951 ** globalias -> (no change)
959 ** unconstrained -> unspec
965 static /*@only@*/ cstring
966 canonicalizeFlag (cstring s)
969 cstring res = cstring_copy (s);
970 static bn_mstring transform[] =
976 "parameter", "param",
977 "unrecognized", "unrecog",
979 "declaration", "decl",
987 "unconstrained", "uncon",
997 while ((current = transform[i]) != NULL)
999 if (cstring_containsLit (res, current))
1001 cstring_replaceLit (res, current, transform[i+1]);
1006 /* remove whitespace, -'s, and _'s */
1007 cstring_stripChars (res, " -_");
1012 flags_identifyFlag (cstring s)
1014 return flags_identifyFlagAux (s, FALSE);
1018 flags_identifyFlagQuiet (cstring s)
1020 return flags_identifyFlagAux (s, TRUE);
1024 flags_identifyFlagAux (cstring s, bool quiet)
1029 if (cstring_length (s) == 0) {
1030 /* evs 2000-06-25: A malformed flag. */
1031 return INVALID_FLAG;
1034 if (cstring_firstChar (s) == 'I')
1036 return FLG_INCLUDEPATH; /* no space required after -I */
1039 if (cstring_firstChar (s) == 'S')
1041 return FLG_SPECPATH; /* no space required after -S */
1044 if (cstring_firstChar (s) == 'D')
1046 return FLG_DEFINE; /* no space required after -D */
1049 if (cstring_firstChar (s) == 'U')
1051 return FLG_UNDEFINE; /* no space required after -D */
1054 cflag = canonicalizeFlag (s);
1059 if (cstring_equal (cstring_fromChars (f.flag), cflag))
1066 if (res == INVALID_FLAG)
1072 if (cstring_equalLit (cflag, "pred"))
1076 else if (cstring_equalLit (cflag, "modobserverstrict"))
1078 res = FLG_MODOBSERVERUNCON;
1080 else if (cstring_equalLit (cflag, "czechnames"))
1084 else if (cstring_equalLit (cflag, "slovaknames"))
1088 else if (cstring_equalLit (cflag, "czechoslovaknames"))
1090 res = FLG_CZECHOSLOVAK;
1092 else if (cstring_equalLit (cflag, "globunspec")
1093 || cstring_equalLit (cflag, "globuncon"))
1095 res = FLG_GLOBUNSPEC;
1097 else if (cstring_equalLit (cflag, "modglobsunspec")
1098 || cstring_equalLit (cflag, "modglobsuncon")
1099 || cstring_equalLit (cflag, "modglobsnomods"))
1101 res = FLG_MODGLOBSUNSPEC;
1103 else if (cstring_equalLit (cflag, "export"))
1105 res = FLG_EXPORTANY;
1107 else if (cstring_equalLit (cflag, "macrospec"))
1109 res = FLG_MACRODECL;
1111 else if (cstring_equalLit (cflag, "ansireservedlocal"))
1113 res = FLG_ISORESERVEDLOCAL;
1115 else if (cstring_equalLit (cflag, "warnposix"))
1117 res = FLG_WARNPOSIX;
1119 else if (cstring_equalLit (cflag, "defuse"))
1123 else if (cstring_equalLit (cflag, "macroundef"))
1125 res = FLG_MACROUNDEF;
1127 else if (cstring_equalLit (cflag, "showcol"))
1131 else if (cstring_equalLit (cflag, "intbool"))
1135 else if (cstring_equalLit (cflag, "intchar"))
1139 else if (cstring_equalLit (cflag, "intenum"))
1143 else if (cstring_equalLit (cflag, "intlong"))
1147 else if (cstring_equalLit (cflag, "intshort"))
1152 ** Backwards compatibility for our American friends...
1155 else if (cstring_equalLit (cflag, "ansilib"))
1159 else if (cstring_equalLit (cflag, "ansistrictlib"))
1161 res = FLG_STRICTLIB;
1163 else if (cstring_equalLit (cflag, "skipansiheaders"))
1165 res = FLG_SKIPISOHEADERS;
1167 else if (cstring_equalLit (cflag, "ansireserved"))
1169 res = FLG_ISORESERVED;
1171 else if (cstring_equalLit (cflag, "ansireservedinternal"))
1173 res = FLG_ISORESERVEDLOCAL;
1180 else if (cstring_equalLit (cflag, "accessunspec"))
1185 (cstring_makeLiteral
1186 ("accessunspec flag is no longer supported. It has been replaced by accessmodule, accessfile and "
1187 "accessfunction to provide more precise control of accessibility "
1188 "of representations. For more information, "
1189 "see splint -help accessmodule"));
1194 else if (cstring_equalLit (cflag, "ansilimits"))
1197 (cstring_makeLiteral
1198 ("ansilimits flag is no longer supported. It has been replaced by ansi89limits and "
1199 "iso99limits to select either the lower translation limits imposed by the ANSI89 "
1200 "standard or the typically higher limits prescribed by ISO C99."));
1204 else if (cstring_equalLit (cflag, "staticmods"))
1209 (cstring_makeLiteral
1210 ("staticmods flag is obsolete. You probably "
1211 "want impcheckmodstatics. For more information, "
1212 "see splint -help impcheckmodstatics"));
1217 else if (cstring_equalLit (cflag, "bool"))
1222 (cstring_makeLiteral ("bool flag is obsolete. It never really "
1223 "made sense in the first place."));
1228 else if (cstring_equalLit (cflag, "shiftsigned"))
1233 (cstring_makeLiteral ("shiftsigned flag is obsolete. You probably "
1234 "want bitwisesigned, shiftnegative or shiftimplementation."));
1239 else if (cstring_equalLit (cflag, "ansi"))
1244 (cstring_makeLiteral ("ansi flag is obsolete. You probably "
1245 "want noparams and/or oldstyle."));
1250 else if (cstring_equalLit (cflag, "usestderr"))
1255 (cstring_makeLiteral
1256 ("usestderr flag is obsolete. This has been replaced "
1257 "by more precise flags for controlling the warning, "
1258 "status message and fatal error streams independently: message-stream-stdout, "
1259 "message-stream-stderr, message-stream <file>, "
1260 "warning-stream-stdout, warning-stream-stderr, warning-stream <file>, "
1261 "error-stream-stdout, error-stream-stderr, error-stream <file>."));
1267 else if (cstring_equalLit (cflag, "stdio"))
1272 (cstring_makeLiteral
1273 ("stdio flag is obsolete. You may "
1274 "want strictlib or one of the gloabls "
1275 "checking flags. For more information, "
1276 "see splint -help strictlib or splint -help flags globals"));
1281 else if (flags_isModeName (cflag))
1283 res = MODENAME_FLAG;
1291 cstring_free (cflag);
1295 void flags_setValueFlag (flagcode opt, cstring arg)
1303 case FLG_INDENTSPACES:
1304 case FLG_LOCINDENTSPACES:
1306 case FLG_EXTERNALNAMELEN:
1307 case FLG_INTERNALNAMELEN:
1308 case FLG_CONTROLNESTDEPTH:
1309 case FLG_STRINGLITERALLEN:
1310 case FLG_NUMSTRUCTFIELDS:
1311 case FLG_NUMENUMMEMBERS:
1312 case FLG_INCLUDENEST:
1314 int val = cstring_toPosInt (arg);
1321 ("Flag %s must be followed by a positive number number. "
1323 flagcode_unparse (opt), arg));
1327 context_setValueAndFlag (opt, val);
1331 case FLG_COMMENTCHAR:
1333 if (cstring_length (arg) != 1)
1337 ("Flag %s should be followed by a single character. Followed by %s",
1338 flagcode_unparse (opt), arg));
1342 context_setCommentMarkerChar (cstring_firstChar (arg));
1350 void flags_setStringFlag (flagcode opt, /*@only@*/ cstring arg)
1356 if (cstring_lastChar (arg) == CONNECTCHAR)
1358 context_setString (opt, arg);
1362 context_setString (opt, cstring_appendChar (arg, CONNECTCHAR));
1368 context_setString (opt, arg);
1377 cstring s = cstring_makeLiteral ("Flag ");
1378 cstringSList sflags = sortedFlags ();
1382 s = message ("%q%9s", s, cstring_fromChars (modename));
1385 s = message ("%q\n", s);
1387 cstringSList_elements (sflags, flagname)
1389 flagcode code = flags_identifyFlag (flagname);
1390 fflag currentflag = flags[code];
1392 if (mstring_isDefined (currentflag.desc) && flagcode_isModeFlag (code))
1394 s = message ("%q\n%27s", s,
1395 cstring_fromChars (currentflag.flag));
1399 context_setMode (cstring_fromChars (modename));
1401 if (context_getFlag (code))
1403 s = message ("%q%9s", s, cstring_makeLiteralTemp ("+"));
1407 s = message ("%q%9s", s, cstring_makeLiteralTemp (" "));
1410 context_resetModeFlags ();
1413 } end_cstringSList_elements;
1415 cstringSList_free (sflags);
1417 s = cstring_appendChar (s, '\n');
1423 static /*@unused@*/ cstring
1426 cstring s = cstring_makeLiteral ("\t");
1431 if (i != 0 && (i % 4 == 0))
1433 s = message ("%q\n\t%15s", s, cstring_fromChars (modename));
1437 s = message ("%q%15s", s, cstring_fromChars (modename));
1447 flags_isModeName (cstring s)
1451 if (mstring_isDefined (modename))
1453 if (cstring_equalLit (s, modename))
1463 extern bool flagcode_hasArgument (flagcode f)
1465 return (flags[f].argtype != ARG_NONE);
1468 extern bool flagcode_hasNumber (flagcode f)
1470 return (flags[f].argtype == ARG_NUMBER);
1473 extern bool flagcode_hasChar (flagcode f)
1475 return (flags[f].argtype == ARG_CHAR);
1478 extern bool flagcode_hasString (flagcode f)
1480 return (flags[f].argtype == ARG_STRING
1481 || flags[f].argtype == ARG_FILE
1482 || flags[f].argtype == ARG_DIRECTORY
1483 || flags[f].argtype == ARG_PATH);
1486 extern int flagcode_valueIndex (flagcode f)
1488 /*@unchecked@*/ static bool initialized = FALSE;
1490 /*@unchecked@*/ static flagcode valueFlags[NUMVALUEFLAGS];
1498 if (flagcode_hasNumber (code) || flagcode_hasChar (code))
1500 llassert (nv < NUMVALUEFLAGS);
1501 DPRINTF (("Value flag: %s [%d]", flagcode_unparse (code), (int) code));
1502 valueFlags[nv] = code;
1507 llassertprint (nv == NUMVALUEFLAGS,
1508 ("Number of value flags: %d (expected %d)",
1509 nv, (int) NUMVALUEFLAGS));
1513 for (i = 0; i < NUMVALUEFLAGS; i++)
1515 /* static valueFlags must be defined */
1517 if (f == valueFlags[i]) /*@=usedef@*/
1523 fprintf (stderr, "Cannot find value flag: %d", (int) f);
1524 exit (EXIT_FAILURE);
1525 /* Cannot do this...might call recursively...
1526 llfatalbug (message ("Cannot fine value flag: %d", (int) f));
1531 extern int flagcode_stringIndex (flagcode f)
1533 /*@unchecked@*/ static bool initialized = FALSE;
1534 /*@unchecked@*/ static flagcode stringFlags[NUMSTRINGFLAGS];
1544 if (flagcode_hasString (code))
1546 llassertprint (nv < NUMSTRINGFLAGS, ("Incorrect number of string flags: %d (need at least %d)", NUMSTRINGFLAGS, nv));
1547 stringFlags[nv] = code;
1552 llassertprint (nv == NUMSTRINGFLAGS,
1553 ("number of string flags: %d (expected %d)",
1554 nv, NUMSTRINGFLAGS));
1558 for (i = 0; i < NUMSTRINGFLAGS; i++)
1560 /*@-usedef@*/ if (f == stringFlags[i]) /*@=usedef@*/
1566 llbug (message ("Bad string flag: %s", flagcode_unparse (f)));
1570 bool flagcode_isNamePrefixFlag (flagcode f)
1574 case FLG_MACROVARPREFIX:
1576 case FLG_ENUMPREFIX:
1577 case FLG_FILESTATICPREFIX:
1578 case FLG_GLOBPREFIX:
1579 case FLG_TYPEPREFIX:
1580 case FLG_EXTERNALPREFIX:
1581 case FLG_LOCALPREFIX:
1582 case FLG_UNCHECKEDMACROPREFIX:
1583 case FLG_CONSTPREFIX:
1584 case FLG_ITERPREFIX:
1585 case FLG_DECLPARAMPREFIX:
1592 static cstring findLarchPathFile (/*@temp@*/ cstring s)
1597 status = osd_getPath (context_getLarchPath (), s, &pathName);
1599 if (status == OSD_FILEFOUND)
1603 else if (status == OSD_FILENOTFOUND)
1606 lldiagmsg (message ("Cannot find file on LARCH_PATH: %s", s));
1608 else if (status == OSD_PATHTOOLONG)
1610 /* Directory and filename are too long. Report error. */
1611 llbuglit ("soure_getPath: Filename plus directory from search path too long");
1618 return cstring_undefined;
1621 static void addLarchPathFile (fileIdList files, /*@temp@*/ cstring s)
1623 cstring pathName = findLarchPathFile (s);
1625 if (cstring_isDefined (pathName))
1627 if (fileTable_exists (context_fileTable (), pathName))
1630 lldiagmsg (message ("File listed multiple times: %s", pathName));
1631 cstring_free (pathName);
1635 fileIdList_add (files, fileTable_addFileOnly (context_fileTable (), pathName));
1641 static void addFile (fileIdList files, /*@only@*/ cstring s)
1643 if (fileTable_exists (context_fileTable (), s))
1646 lldiagmsg (message ("File listed multiple times: %s", s));
1651 fileIdList_add (files, fileTable_addFileOnly (context_fileTable (), s));
1655 static void addXHFile (fileIdList files, /*@temp@*/ cstring s)
1657 cstring pathName = findLarchPathFile (s);
1659 if (cstring_isDefined (pathName))
1661 if (fileTable_exists (context_fileTable (), pathName))
1664 lldiagmsg (message ("File listed multiple times: %s", s));
1668 fileIdList_add (files, fileTable_addXHFile (context_fileTable (), pathName));
1672 cstring_free (pathName);
1676 flags_processFlags (bool inCommandLine,
1679 fileIdList lclfiles,
1681 cstringList *passThroughArgs,
1682 int argc, char **argv)
1685 cstringSList fl = cstringSList_undefined;
1687 for (i = 0; i < argc; i++)
1691 llassert (argv != NULL);
1694 DPRINTF (("process thisarg [%d]: %s", i, thisarg));
1696 if (*thisarg == '-' || *thisarg == '+')
1698 bool set = (*thisarg == '+');
1702 if (*(thisarg + 1) == '-') { /* allow -- before flags */
1703 flagname = cstring_fromChars (thisarg + 2);
1705 flagname = cstring_fromChars (thisarg + 1);
1708 opt = flags_identifyFlag (flagname);
1709 DPRINTF (("Flag [%s]: %s", flagname, flagcode_unparse (opt)));
1711 if (flagcode_isInvalid (opt))
1713 DPRINTF (("Error!"));
1714 voptgenerror (FLG_BADFLAG,
1715 message ("Unrecognized option: %s",
1716 cstring_fromChars (thisarg)),
1719 else if (flagcode_isHelpFlag (opt))
1723 voptgenerror (FLG_BADFLAG,
1724 message ("Help flag must be first on the command line: %s",
1725 cstring_fromChars (thisarg)),
1730 voptgenerror (FLG_BADFLAG,
1731 message ("Help flags can only be used on the command line: %s",
1732 cstring_fromChars (thisarg)),
1736 else if (flagcode_isPassThrough (opt)) /* preprocessor flag: -D or -U */
1739 ** Following space is optional, don't include the -
1742 *passThroughArgs = cstringList_add (*passThroughArgs,
1743 cstring_fromCharsNew (thisarg + 1));
1745 else if (opt == FLG_INCLUDEPATH || opt == FLG_SPECPATH)
1747 if (mstring_length (thisarg) < 2) {
1750 if (mstring_equal (thisarg, "-I-")) {
1751 cppAddIncludeDir (cstring_fromChars (thisarg)); /* Need to handle this specially. */
1753 cstring dir = cstring_suffix (cstring_fromChars (thisarg), 2); /* skip over -I */
1755 DPRINTF (("Length of thisarg [%s] %d", thisarg, cstring_length (thisarg)));
1757 if (cstring_length (dir) == 0) {
1758 DPRINTF (("space after directory: "));
1760 dir = cstring_fromChars (argv[i]);
1765 ("Flag %s must be followed by a directory name",
1766 flagcode_unparse (opt)),
1771 DPRINTF (("Got directory: [%s]", dir));
1775 case FLG_INCLUDEPATH:
1776 cppAddIncludeDir (dir);
1777 /*@switchbreak@*/ break;
1780 g_localSpecPath = cstring_toCharsSafe
1782 cstring_fromChars (g_localSpecPath),
1786 /*@switchbreak@*/ break;
1792 else if (flagcode_isModeName (opt))
1794 context_setMode (flagname);
1796 else if (inCommandLine && flagcode_isMessageControlFlag (opt))
1799 ** Processed on first pass
1802 if (flagcode_hasArgument (opt))
1810 ** A normal control flag
1813 context_userSetFlag (opt, set);
1815 if (flagcode_hasArgument (opt))
1817 if (flagcode_hasNumber (opt))
1821 flags_setValueFlag (opt, cstring_fromCharsNew (argv[i]));
1828 ("Flag %s must be followed by a number",
1829 flagcode_unparse (opt)),
1833 else if (flagcode_hasChar (opt))
1837 flags_setValueFlag (opt, cstring_fromCharsNew (argv[i]));
1844 ("Flag %s must be followed by a character",
1845 flagcode_unparse (opt)),
1849 else if (flagcode_hasString (opt)
1850 || opt == FLG_INIT || opt == FLG_OPTF)
1855 Changed this because arg can be freed when it's passed to
1856 lslinit_setInitFile and freeing argv[i] causes a seg fault
1858 cstring arg = cstring_fromCharsNew (argv[i]);
1860 if (opt == FLG_OPTF)
1864 ; /* -f already processed */
1868 (void) rcfiles_read (arg, passThroughArgs, TRUE);
1871 else if (opt == FLG_INIT)
1873 lslinit_setInitFile (inputStream_create
1875 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
1881 DPRINTF (("String flag: %s / %s",
1882 flagcode_unparse (opt), arg));
1883 if (opt == FLG_MTSFILE)
1886 ** arg identifies mts files
1888 cstring tmp = message ("%s%s", arg, MTS_EXTENSION);
1889 addLarchPathFile (mtfiles, tmp);
1891 tmp = message ("%s%s", arg, XH_EXTENSION);
1892 addXHFile (xfiles, tmp);
1897 flags_setStringFlag (opt, cstring_copy (arg));
1906 ("Flag %s must be followed by a string",
1907 flagcode_unparse (opt)),
1918 else /* its a filename */
1920 DPRINTF (("Adding filename: %s", thisarg));
1921 fl = cstringSList_add (fl, cstring_fromChars (thisarg));
1926 ** create lists of C and LCL files
1931 cstringSList_elements (fl, current)
1933 cstring ext = fileLib_getExtension (current);
1935 if (cstring_isUndefined (ext))
1937 /* no extension --- both C and LCL with default extensions */
1939 addFile (cfiles, message ("%s%s", current, C_EXTENSION));
1940 addFile (lclfiles, message ("%s%s", current, LCL_EXTENSION));
1942 else if (cstring_equal (ext, XH_EXTENSION))
1944 addXHFile (xfiles, current);
1946 else if (cstring_equal (ext, PP_EXTENSION))
1948 if (!context_getFlag (FLG_NOPP))
1951 (FLG_FILEEXTENSIONS,
1952 message ("File extension %s used without +nopp flag (will be processed as C source code): %s",
1957 addFile (cfiles, cstring_copy (current));
1959 else if (cstring_equal (ext, LCL_EXTENSION))
1961 addFile (lclfiles, cstring_copy (current));
1963 else if (fileLib_isCExtension (ext))
1965 addFile (cfiles, cstring_copy (current));
1967 else if (cstring_equal (ext, MTS_EXTENSION))
1969 addLarchPathFile (mtfiles, current);
1974 (FLG_FILEEXTENSIONS,
1975 message ("Unrecognized file extension: %s (assuming %s is C source code)",
1979 addFile (cfiles, cstring_copy (current));
1981 } end_cstringSList_elements;
1985 if (cstringSList_size (fl) != 0)
1987 /* Cannot list files in .splintrc files */
1988 voptgenerror (FLG_BADFLAG,
1989 message ("Cannot list files in .splintrc files: %s (probable missing + or -)",
1990 cstringSList_unparse (fl)),
1995 cstringSList_free (fl); /* evans 2002-07-12: why wasn't this reported!?? */
1998 int flagcode_priority (/*@unused@*/ flagcode code)
2001 ** For now, we do a really simple prioritization: all are 1