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@*/ const char *name
;
49 /*@null@*/ /*@observer@*/ const 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) */
131 static /*@observer@*/ cstring
argcode_unparse (argcode arg
)
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 default: BADBRANCH
; return cstring_undefined
;
148 bool isSpecial
; /* setting this flag may set other flags (or values) */
149 bool isIdem
; /* idempotent - always sets to TRUE */
150 bool isGlobal
; /* cannot be set locally (using control comments) */
151 bool isModeFlag
; /* set by modes */
153 /*@observer@*/ const char *flag
;
155 /*@observer@*/ /*@null@*/ const char *desc
;
156 /*@observer@*/ /*@null@*/ const char *hint
;
161 typedef fflag flaglist
[];
163 # include "flags.def"
165 /*@iter allFlags (yield observer fflag f); @*/
166 # define allFlags(m_f) \
167 { /*@+enumint@*/ flagcode m_i; for (m_i = 0; m_i < NUMFLAGS; m_i++) { fflag m_f = flags[m_i]; /*@=enumint@*/
168 # define end_allFlags }}
170 static /*@observer@*/ /*@null@*/ const char * mode_names
[] =
172 "weak", "standard", "checks", "strict", NULL
,
175 /*@iter allModes (yield const char* modename)@*/
176 # define allModes(m_m) \
177 { int m_ii = 0; while (mstring_isDefined (mode_names[m_ii])) \
178 { /*@observer@*/ /*@null@*/ const char* m_m = mode_names[m_ii]; m_ii++;
180 # define end_allModes }}
184 static cstring
getFlagModeSettings (flagcode p_flag
) /*@modifies internalState@*/ ;
185 static cstring
describeFlagCode (flagcode p_flag
) /*@*/ ;
186 static cstringSList
sortedFlags (void) /*@*/ ;
187 static /*@observer@*/ cstring
categoryName (flagkind p_kind
) /*@*/ ;
189 static flagcode
flags_identifyFlagAux (cstring p_s
, bool p_quiet
) /*@modifies g_warningstream@*/ ;
192 static /*@unused@*/ cstring
listModes (void) /*@*/ ;
195 bool flagcode_isSpecialFlag (flagcode f
)
197 return (flags
[f
].isSpecial
);
200 bool flagcode_isGlobalFlag (flagcode f
)
202 return (flags
[f
].isGlobal
);
205 bool flagcode_isIdemFlag (flagcode f
)
207 return (flags
[f
].isIdem
);
210 bool flagcode_isModeFlag (flagcode f
)
212 return (flags
[f
].isModeFlag
);
215 bool flagcode_isNameChecksFlag (flagcode f
)
217 return (flags
[f
].main
== FK_NAMES
);
220 bool flagcode_isHelpFlag (flagcode f
)
222 return f
== FLG_HELP
;
225 bool flagcode_isMessageControlFlag (flagcode f
)
228 ** True if opt controls the display of messages.
229 ** These flags must be processed first.
232 return (f
== FLG_SHOWSCAN
234 || f
== FLG_PARENFILEFORMAT
235 || f
== FLG_MESSAGESTREAMSTDERR
236 || f
== FLG_MESSAGESTREAMSTDOUT
237 || f
== FLG_WARNINGSTREAMSTDERR
238 || f
== FLG_WARNINGSTREAMSTDOUT
239 || f
== FLG_ERRORSTREAMSTDERR
240 || f
== FLG_ERRORSTREAMSTDOUT
241 || f
== FLG_MESSAGESTREAM
242 || f
== FLG_WARNINGSTREAM
243 || f
== FLG_ERRORSTREAM
244 || f
== FLG_STREAMOVERWRITE
);
248 ** Internal consistency check on the flags.
251 void flags_initMod (void)
256 if (flags
[code
].code
!= code
)
259 "*** ERROR: inconsistent flag %s / %d / %d",
261 flags
[code
].code
, code
);
263 llbug (message ("*** ERROR: inconsistent flag %s / %d / %d",
264 cstring_fromChars (flags
[code
].flag
),
265 flags
[code
].code
, code
));
272 summarizeErrors (void)
278 char *buf
= mstring_create (128);
282 if (f
.nreported
> 0 || f
.nsuppressed
> 0)
284 int nrep
= f
.nreported
;
285 int nsup
= f
.nsuppressed
;
286 cstring fs
= cstring_fill (cstring_fromChars (f
.flag
), 23);
290 llmsgplain (cstring_makeLiteral
291 ("\nError Type Reported Suppressed\n"
292 "=================== ======== ========="));
296 (void) snprintf (buf
, 128, "%s%7d %9d", cstring_toCharsSafe (fs
), nrep
, nsup
);
302 llmsg (cstring_copy (cstring_fromChars (buf
)));
308 cstring ts
= cstring_fill (cstring_makeLiteralTemp ("Total"), 23);
310 llmsglit (" ======== =========");
312 (void) snprintf (buf
, 128, "%s%7d %9d", cstring_toCharsSafe (ts
), sumrep
, sumsup
);
314 llmsgplain (cstring_copy (cstring_fromChars (buf
)));
323 flagcode_recordError (flagcode f
)
325 if (f
!= INVALID_FLAG
)
327 if (f
== FLG_WARNFLAGS
)
329 ; /* don't count these */
333 flags
[f
].nreported
= flags
[f
].nreported
+ 1;
338 llcontbug (message ("flagcode_recordError: invalid flag: %d", (int) f
));
343 flagcode_recordSuppressed (flagcode f
)
345 llassertprint (f
!= INVALID_FLAG
, ("flagcode: %s", flagcode_unparse (f
)));
347 flags
[f
].nsuppressed
= flags
[f
].nsuppressed
+ 1;
351 flagcode_numReported (flagcode f
)
353 llassert (f
!= INVALID_FLAG
);
355 return (flags
[f
].nreported
);
358 /*@observer@*/ cstring
359 flagcodeHint (flagcode f
)
361 llassert (f
!= INVALID_FLAG
);
363 if (mstring_isDefined (flags
[f
].hint
))
365 return (cstring_fromChars (flags
[f
].hint
));
369 return (cstring_fromChars (flags
[f
].desc
));
373 static int categorySize (flagkind kind
) /*@*/
380 if (f
.main
== kind
|| f
.sub
== kind
)
389 flagkind
identifyCategory (cstring s
)
393 for (i
= 0; categories
[i
].kind
!= FK_NONE
; i
++)
395 if (mstring_isDefined (categories
[i
].name
))
397 if (cstring_equalLit (s
, categories
[i
].name
))
399 return categories
[i
].kind
;
407 static /*@observer@*/ cstring
categoryName (flagkind kind
)
411 for (i
= 0; categories
[i
].kind
!= FK_NONE
; i
++)
413 if (categories
[i
].kind
== kind
)
415 return (cstring_fromChars (categories
[i
].name
));
419 return (cstring_makeLiteralTemp ("<No Category>"));
422 static int categoryIndex (flagkind kind
)
426 for (i
= 0; categories
[i
].kind
!= FK_NONE
; i
++)
428 if (categories
[i
].kind
== kind
)
437 void printCategory (flagkind kind
)
439 int index
= categoryIndex (kind
);
441 llassert (index
>= 0);
442 llmsg (message ("%s (%d flags)\n\3%s\n\n",
443 cstring_fromChars (categories
[index
].name
),
445 cstring_fromChars (categories
[index
].describe
)));
449 if (f
.main
== kind
|| f
.sub
== kind
)
451 llmsg (message (" %s\n\6%q", cstring_fromChars (f
.flag
),
452 describeFlagCode (f
.code
)));
458 listAllCategories (void)
462 for (i
= 0; categories
[i
].kind
!= FK_NONE
; i
++)
464 flagkind kind
= categories
[i
].kind
;
466 if (categories
[i
].describe
!= NULL
)
468 llmsg (message ("%s (%d flags)\n\3%s",
471 cstring_fromChars (categories
[i
].describe
)));
477 printAllFlags (bool desc
, bool full
)
481 cstringSList fl
= sortedFlags ();
483 cstringSList_elements (fl
, el
)
486 tmp
= cstring_copy(el
);
487 llmsg (message ("%q\n\n", describeFlag (tmp
)));
489 } end_cstringSList_elements
;
491 cstringSList_free (fl
);
497 if (f
.code
!= INVALID_FLAG
&& f
.main
!= FK_OBSOLETE
)
499 if (mstring_isDefined (f
.desc
))
503 llmsg (message ("%s --- %s", cstring_fromChars (f
.flag
),
504 cstring_fromChars (f
.desc
)));
513 printFlagManual (bool html
)
516 ** Prints all flags by category, in order they appear in flags.def
519 flagkind lastCategory
= FK_NONE
;
523 cstring flagtype
= cstring_undefined
;
525 if (f
.main
!= lastCategory
)
529 llmsg (message ("\n<h4>%s</h4>\n", categoryName (f
.main
)));
533 llmsg (message ("\n%s\n%s\n",
534 categoryName (f
.main
),
535 cstring_makeLiteralTemp ("===================================")));
538 lastCategory
= f
.main
;
541 if (f
.argtype
== ARG_NONE
|| f
.argtype
== ARG_SPECIAL
)
545 flagname
= message ("<tt>%s</tt>", cstring_fromChars (f
.flag
));
549 flagname
= cstring_fromCharsNew (f
.flag
);
554 if (flagcode_hasString (f
.code
))
558 flagname
= message ("<tt>%s <em><%s></em></tt>",
559 cstring_fromChars (f
.flag
), argcode_unparse (f
.argtype
));
563 flagname
= message ("%s <%s>", cstring_fromChars (f
.flag
), argcode_unparse (f
.argtype
));
566 if (cstring_isDefined (context_getString (f
.code
)))
570 flagname
= message ("%q <font color=\"blue\">[%s]</font>", flagname
,
571 context_getString (f
.code
));
575 flagname
= message ("%q [%s]", flagname
,
576 context_getString (f
.code
));
580 else if (f
.argtype
== ARG_CHAR
)
584 flagname
= message ("<tt>%s <em><%s></em></tt> <font color=\"blue\">[%c]</font>",
585 cstring_fromChars (f
.flag
), argcode_unparse (f
.argtype
),
586 (char) context_getValue (f
.code
));
590 flagname
= message ("%s <%s> [%c]", cstring_fromChars (f
.flag
), argcode_unparse (f
.argtype
),
591 (char) context_getValue (f
.code
));
596 llassert (f
.argtype
== ARG_NUMBER
);
600 flagname
= message ("<tt>%s <em><%s></em> <font color=\"blue\">[%d]</font>",
601 cstring_fromChars (f
.flag
), argcode_unparse (f
.argtype
),
602 context_getValue (f
.code
));
606 flagname
= message ("%s <%s> [%d]", cstring_fromChars (f
.flag
), argcode_unparse (f
.argtype
),
607 context_getValue (f
.code
));
616 flagtype
= message("%q<font color=\"green\">-</font>", flagtype
);
620 flagtype
= message("%q<->", flagtype
);
628 flagtype
= message ("%q<font color=\"green\"><em>global</em></font>", flagtype
);
632 flagtype
= message ("%q<G>", flagtype
);
640 flagtype
= message ("%q<font color=\"orange\"><em>shortcut</em></font>", flagtype
);
644 flagtype
= message("%q<S>", flagtype
);
652 flagtype
= message ("%q mode:<tt>%q</tt>>", flagtype
, getFlagModeSettings (f
.code
));
656 flagtype
= message ("%q<M:%q>", flagtype
, getFlagModeSettings (f
.code
));
659 else /* its a plain flag */
663 flagtype
= message ("%q plain:<tt>%s</tt>", flagtype
,
664 cstring_makeLiteralTemp (context_getFlag (f
.code
) ? "+" : "-"));
668 flagtype
= message ("%q<P:%s>", flagtype
,
669 cstring_makeLiteralTemp (context_getFlag (f
.code
) ? "+" : "-"));
673 llmsg (message ("%s: %s", flagname
, flagtype
));
677 llgenindentmsgnoloc (cstring_makeLiteral ("<blockquote>"));
680 if (mstring_isDefined (f
.hint
))
682 llgenindentmsgnoloc (cstring_fromCharsNew (f
.hint
));
686 llgenindentmsgnoloc (message ("%q.", cstring_capitalize (cstring_fromChars (f
.desc
))));
691 llgenindentmsgnoloc (cstring_makeLiteral ("</blockquote>"));
697 describeMode (cstring mode
)
699 cstringSList sflags
= sortedFlags ();
700 cstring res
= message ("Predefined mode %s sets: ", mode
);
702 llassert (flags_isModeName (mode
));
704 context_setMode (mode
);
706 cstringSList_elements (sflags
, flagname
)
708 flagcode code
= flags_identifyFlag (flagname
);
709 fflag currentflag
= flags
[code
];
711 if (mstring_isDefined (currentflag
.desc
) && flagcode_isModeFlag (code
))
713 if (context_getFlag (code
))
715 res
= message ("%q\n +%s", res
, cstring_fromChars (currentflag
.flag
));
719 res
= message ("%q\n -%s", res
, cstring_fromChars (currentflag
.flag
));
722 } end_cstringSList_elements
;
724 cstringSList_free (sflags
);
726 res
= cstring_appendChar (res
, '\n');
731 describeFlagCode (flagcode flag
)
733 cstring ret
= cstring_undefined
;
736 if (flagcode_isInvalid (flag
))
738 return (cstring_makeLiteral ("<invalid>"));
741 if (flagcode_isModeName (flag
))
743 return (cstring_makeLiteral ("<mode flag>"));
746 context_resetAllFlags ();
749 ret
= cstring_copy (cstring_fromChars (f
.desc
));
751 if (f
.sub
!= FK_NONE
)
753 ret
= message ("%q\nCategories: %s, %s",
755 categoryName (f
.main
),
756 categoryName (f
.sub
));
760 if (f
.main
!= FK_NONE
)
762 cstring cname
= categoryName (f
.main
);
764 if (cstring_isDefined (cname
))
766 ret
= message ("%q\nCategory: %s",
774 ret
= message ("%q\nMode Settings: %q",
775 ret
, getFlagModeSettings (flag
));
779 ret
= message ("%q\nDefault Setting: %s",
781 cstring_makeLiteralTemp (context_getFlag (flag
) ? "+" : "-"));
786 ret
= message("%q\nSet globally only", ret
);
790 ret
= message("%q\nSet locally", ret
);
799 ret
= message("%q\nNumeric Argument. Default: %d",
801 context_getValue (flag
));
804 ret
= message("%q\nCharacter Argument. Default: %h",
805 ret
, (char) context_getValue (flag
));
812 if (cstring_isDefined (context_getString (flag
)))
814 ret
= message("%q\n%q argument. Default: %s",
816 cstring_capitalize (argcode_unparse (f
.argtype
)),
817 context_getString (flag
));
821 ret
= message("%q\n%s argument. No default.",
823 cstring_capitalize (argcode_unparse (f
.argtype
)));
829 if (mstring_isDefined (f
.hint
))
831 ret
= message("%q\n\3%s", ret
, cstring_fromChars (f
.hint
));
837 static cstring
getFlagModeSettings (flagcode flag
)
839 cstring res
= cstring_undefined
;
843 context_setModeNoWarn (cstring_fromChars (mname
));
845 res
= message ("%q%s", res
, cstring_makeLiteralTemp (context_getFlag (flag
) ? "+" : "-"));
852 describeFlag (cstring flagname
)
854 cstring oflagname
= cstring_copy (flagname
);
855 flagcode f
= flags_identifyFlag (flagname
);
857 if (flagcode_isSkip (f
))
859 cstring_free (oflagname
);
860 return cstring_undefined
;
862 else if (flagcode_isValid (f
))
864 if (cstring_equal (flagname
, oflagname
))
866 cstring_free (oflagname
);
867 return (message ("%s\n\3%q", flagname
, describeFlagCode (f
)));
871 return (message ("%q (standardized name: %s)\n\3%q",
872 oflagname
, flagname
, describeFlagCode (f
)));
877 if (flags_isModeName (flagname
))
879 cstring_free (oflagname
);
880 return describeMode (flagname
);
884 return (message ("%q: <invalid flag>", oflagname
));
892 cstringSList s
= cstringSList_new ();
898 s
= cstringSList_add (s
, cstring_fromChars (f
.flag
));
902 cstringSList_alphabetize (s
);
907 void printAlphaFlags (void)
909 cstringSList fl
= sortedFlags ();
911 cstringSList_printSpaced (fl
, 3, 1, context_getLineLen () - 25);
912 cstringSList_free (fl
);
915 /*@observer@*/ cstring
916 flagcode_unparse (flagcode code
)
918 if (code
== INVALID_FLAG
)
920 return cstring_makeLiteralTemp ("<invalid flag>");
923 return cstring_fromChars (flags
[code
].flag
);
927 ** Transforms a flag into its cannonical form.
929 ** The following transformations are made:
935 ** parameter -> param
936 ** unrecognized -> unrecog
938 ** declaration -> decl
946 ** unconstrained -> uncon
954 static /*@only@*/ cstring
955 canonicalizeFlag (cstring s
)
958 cstring res
= cstring_copy (s
);
959 static /*@observer@*/ /*@null@*/ const char* transform
[] =
965 "parameter", "param",
966 "unrecognized", "unrecog",
968 "declaration", "decl",
976 "unconstrained", "uncon",
986 while ((current
= transform
[i
]) != NULL
)
988 if (cstring_containsLit (res
, current
))
990 cstring_replaceLit (res
, current
, transform
[i
+1]);
995 /* remove whitespace, -'s, and _'s */
996 cstring_stripChars (res
, " -_");
1001 flags_identifyFlag (cstring s
)
1003 return flags_identifyFlagAux (s
, FALSE
);
1007 flags_identifyFlagQuiet (cstring s
)
1009 return flags_identifyFlagAux (s
, TRUE
);
1013 flags_identifyFlagAux (cstring s
, bool quiet
)
1018 if (cstring_length (s
) == 0) {
1019 /* evs 2000-06-25: A malformed flag. */
1020 return INVALID_FLAG
;
1023 if (cstring_firstChar (s
) == 'I')
1025 return FLG_INCLUDEPATH
; /* no space required after -I */
1028 if (cstring_firstChar (s
) == 'S')
1030 return FLG_SPECPATH
; /* no space required after -S */
1033 if (cstring_firstChar (s
) == 'D')
1035 return FLG_DEFINE
; /* no space required after -D */
1038 if (cstring_firstChar (s
) == 'U')
1040 return FLG_UNDEFINE
; /* no space required after -D */
1043 cflag
= canonicalizeFlag (s
);
1048 if (cstring_equal (cstring_fromChars (f
.flag
), cflag
))
1055 if (res
== INVALID_FLAG
)
1061 if (cstring_equalLit (cflag
, "pred"))
1065 else if (cstring_equalLit (cflag
, "modobserverstrict"))
1067 res
= FLG_MODOBSERVERUNCON
;
1069 else if (cstring_equalLit (cflag
, "czechnames"))
1073 else if (cstring_equalLit (cflag
, "slovaknames"))
1077 else if (cstring_equalLit (cflag
, "czechoslovaknames"))
1079 res
= FLG_CZECHOSLOVAK
;
1081 else if (cstring_equalLit (cflag
, "globunspec")
1082 || cstring_equalLit (cflag
, "globuncon"))
1084 res
= FLG_GLOBUNSPEC
;
1086 else if (cstring_equalLit (cflag
, "modglobsunspec")
1087 || cstring_equalLit (cflag
, "modglobsuncon")
1088 || cstring_equalLit (cflag
, "modglobsnomods"))
1090 res
= FLG_MODGLOBSUNSPEC
;
1092 else if (cstring_equalLit (cflag
, "export"))
1094 res
= FLG_EXPORTANY
;
1096 else if (cstring_equalLit (cflag
, "macrospec"))
1098 res
= FLG_MACRODECL
;
1100 else if (cstring_equalLit (cflag
, "ansireservedlocal"))
1102 res
= FLG_ISORESERVEDLOCAL
;
1104 else if (cstring_equalLit (cflag
, "warnposix"))
1106 res
= FLG_WARNPOSIX
;
1108 else if (cstring_equalLit (cflag
, "defuse"))
1112 else if (cstring_equalLit (cflag
, "macroundef"))
1114 res
= FLG_MACROUNDEF
;
1116 else if (cstring_equalLit (cflag
, "showcol"))
1120 else if (cstring_equalLit (cflag
, "intbool"))
1124 else if (cstring_equalLit (cflag
, "intchar"))
1128 else if (cstring_equalLit (cflag
, "intenum"))
1132 else if (cstring_equalLit (cflag
, "intlong"))
1136 else if (cstring_equalLit (cflag
, "intshort"))
1141 ** Backwards compatibility for our American friends...
1144 else if (cstring_equalLit (cflag
, "ansilib"))
1148 else if (cstring_equalLit (cflag
, "ansistrictlib"))
1150 res
= FLG_STRICTLIB
;
1152 else if (cstring_equalLit (cflag
, "skipansiheaders"))
1154 res
= FLG_SKIPISOHEADERS
;
1156 else if (cstring_equalLit (cflag
, "ansireserved"))
1158 res
= FLG_ISORESERVED
;
1160 else if (cstring_equalLit (cflag
, "ansireservedinternal"))
1162 res
= FLG_ISORESERVEDLOCAL
;
1169 else if (cstring_equalLit (cflag
, "accessunspec"))
1174 (cstring_makeLiteral
1175 ("accessunspec flag is no longer supported. It has been replaced by accessmodule, accessfile and "
1176 "accessfunction to provide more precise control of accessibility "
1177 "of representations. For more information, "
1178 "see splint -help accessmodule"));
1183 else if (cstring_equalLit (cflag
, "ansilimits"))
1186 (cstring_makeLiteral
1187 ("ansilimits flag is no longer supported. It has been replaced by ansi89limits and "
1188 "iso99limits to select either the lower translation limits imposed by the ANSI89 "
1189 "standard or the typically higher limits prescribed by ISO C99."));
1193 else if (cstring_equalLit (cflag
, "staticmods"))
1198 (cstring_makeLiteral
1199 ("staticmods flag is obsolete. You probably "
1200 "want impcheckmodstatics. For more information, "
1201 "see splint -help impcheckmodstatics"));
1206 else if (cstring_equalLit (cflag
, "bool"))
1211 (cstring_makeLiteral ("bool flag is obsolete. It never really "
1212 "made sense in the first place."));
1217 else if (cstring_equalLit (cflag
, "shiftsigned"))
1222 (cstring_makeLiteral ("shiftsigned flag is obsolete. You probably "
1223 "want bitwisesigned, shiftnegative or shiftimplementation."));
1228 else if (cstring_equalLit (cflag
, "ansi"))
1233 (cstring_makeLiteral ("ansi flag is obsolete. You probably "
1234 "want noparams and/or oldstyle."));
1239 else if (cstring_equalLit (cflag
, "usestderr"))
1244 (cstring_makeLiteral
1245 ("usestderr flag is obsolete. This has been replaced "
1246 "by more precise flags for controlling the warning, "
1247 "status message and fatal error streams independently: message-stream-stdout, "
1248 "message-stream-stderr, message-stream <file>, "
1249 "warning-stream-stdout, warning-stream-stderr, warning-stream <file>, "
1250 "error-stream-stdout, error-stream-stderr, error-stream <file>."));
1256 else if (cstring_equalLit (cflag
, "stdio"))
1261 (cstring_makeLiteral
1262 ("stdio flag is obsolete. You may "
1263 "want strictlib or one of the gloabls "
1264 "checking flags. For more information, "
1265 "see splint -help strictlib or splint -help flags globals"));
1270 else if (flags_isModeName (cflag
))
1272 res
= MODENAME_FLAG
;
1280 cstring_free (cflag
);
1284 void flags_setValueFlag (flagcode opt
, cstring arg
)
1292 case FLG_INDENTSPACES
:
1293 case FLG_LOCINDENTSPACES
:
1295 case FLG_EXTERNALNAMELEN
:
1296 case FLG_INTERNALNAMELEN
:
1297 case FLG_CONTROLNESTDEPTH
:
1298 case FLG_STRINGLITERALLEN
:
1299 case FLG_NUMSTRUCTFIELDS
:
1300 case FLG_NUMENUMMEMBERS
:
1301 case FLG_INCLUDENEST
:
1303 int val
= cstring_toPosInt (arg
);
1310 ("Flag %s must be followed by a positive number number. "
1312 flagcode_unparse (opt
), arg
));
1316 context_setValueAndFlag (opt
, val
);
1320 case FLG_COMMENTCHAR
:
1322 if (cstring_length (arg
) != 1)
1326 ("Flag %s should be followed by a single character. Followed by %s",
1327 flagcode_unparse (opt
), arg
));
1331 context_setCommentMarkerChar (cstring_firstChar (arg
));
1339 void flags_setStringFlag (flagcode opt
, /*@only@*/ cstring arg
)
1345 if (cstring_lastChar (arg
) == CONNECTCHAR
)
1347 context_setString (opt
, arg
);
1351 context_setString (opt
, cstring_appendChar (arg
, CONNECTCHAR
));
1357 context_setString (opt
, arg
);
1364 describeModes (void)
1366 cstring s
= cstring_makeLiteral ("Flag ");
1367 cstringSList sflags
= sortedFlags ();
1371 s
= message ("%q%9s", s
, cstring_fromChars (modename
));
1374 s
= message ("%q\n", s
);
1376 cstringSList_elements (sflags
, flagname
)
1378 flagcode code
= flags_identifyFlag (flagname
);
1379 fflag currentflag
= flags
[code
];
1381 if (mstring_isDefined (currentflag
.desc
) && flagcode_isModeFlag (code
))
1383 s
= message ("%q\n%27s", s
,
1384 cstring_fromChars (currentflag
.flag
));
1388 context_setMode (cstring_fromChars (modename
));
1390 if (context_getFlag (code
))
1392 s
= message ("%q%9s", s
, cstring_makeLiteralTemp ("+"));
1396 s
= message ("%q%9s", s
, cstring_makeLiteralTemp (" "));
1399 context_resetModeFlags ();
1402 } end_cstringSList_elements
;
1404 cstringSList_free (sflags
);
1406 s
= cstring_appendChar (s
, '\n');
1412 static /*@unused@*/ cstring
1415 cstring s
= cstring_makeLiteral ("\t");
1420 if (i
!= 0 && (i
% 4 == 0))
1422 s
= message ("%q\n\t%15s", s
, cstring_fromChars (modename
));
1426 s
= message ("%q%15s", s
, cstring_fromChars (modename
));
1436 flags_isModeName (cstring s
)
1440 if (mstring_isDefined (modename
))
1442 if (cstring_equalLit (s
, modename
))
1452 extern bool flagcode_hasArgument (flagcode f
)
1454 return (flags
[f
].argtype
!= ARG_NONE
);
1457 extern bool flagcode_hasNumber (flagcode f
)
1459 return (flags
[f
].argtype
== ARG_NUMBER
);
1462 extern bool flagcode_hasChar (flagcode f
)
1464 return (flags
[f
].argtype
== ARG_CHAR
);
1467 extern bool flagcode_hasString (flagcode f
)
1469 return (flags
[f
].argtype
== ARG_STRING
1470 || flags
[f
].argtype
== ARG_FILE
1471 || flags
[f
].argtype
== ARG_DIRECTORY
1472 || flags
[f
].argtype
== ARG_PATH
);
1475 extern int flagcode_valueIndex (flagcode f
)
1477 /*@unchecked@*/ static bool initialized
= FALSE
;
1479 /*@unchecked@*/ static flagcode valueFlags
[NUMVALUEFLAGS
];
1487 if (flagcode_hasNumber (code
) || flagcode_hasChar (code
))
1489 llassert (nv
< NUMVALUEFLAGS
);
1490 DPRINTF (("Value flag: %s [%d]", flagcode_unparse (code
), (int) code
));
1491 valueFlags
[nv
] = code
;
1496 llassertprint (nv
== NUMVALUEFLAGS
,
1497 ("Number of value flags: %d (expected %d)",
1498 nv
, (int) NUMVALUEFLAGS
));
1502 for (i
= 0; i
< NUMVALUEFLAGS
; i
++)
1504 /* static valueFlags must be defined */
1506 if (f
== valueFlags
[i
]) /*@=usedef@*/
1512 fprintf (stderr
, "Cannot find value flag: %d", (int) f
);
1513 exit (EXIT_FAILURE
);
1514 /* Cannot do this...might call recursively...
1515 llfatalbug (message ("Cannot fine value flag: %d", (int) f));
1520 extern int flagcode_stringIndex (flagcode f
)
1522 /*@unchecked@*/ static bool initialized
= FALSE
;
1523 /*@unchecked@*/ static flagcode stringFlags
[NUMSTRINGFLAGS
];
1533 if (flagcode_hasString (code
))
1535 llassertprint (nv
< NUMSTRINGFLAGS
, ("Incorrect number of string flags: %d (need at least %d)", NUMSTRINGFLAGS
, nv
));
1536 stringFlags
[nv
] = code
;
1541 llassertprint (nv
== NUMSTRINGFLAGS
,
1542 ("number of string flags: %d (expected %d)",
1543 nv
, NUMSTRINGFLAGS
));
1547 for (i
= 0; i
< NUMSTRINGFLAGS
; i
++)
1549 /*@-usedef@*/ if (f
== stringFlags
[i
]) /*@=usedef@*/
1555 llbug (message ("Bad string flag: %s", flagcode_unparse (f
)));
1559 bool flagcode_isNamePrefixFlag (flagcode f
)
1563 case FLG_MACROVARPREFIX
:
1565 case FLG_ENUMPREFIX
:
1566 case FLG_FILESTATICPREFIX
:
1567 case FLG_GLOBPREFIX
:
1568 case FLG_TYPEPREFIX
:
1569 case FLG_EXTERNALPREFIX
:
1570 case FLG_LOCALPREFIX
:
1571 case FLG_UNCHECKEDMACROPREFIX
:
1572 case FLG_CONSTPREFIX
:
1573 case FLG_ITERPREFIX
:
1574 case FLG_DECLPARAMPREFIX
:
1581 static cstring
findLarchPathFile (/*@temp@*/ cstring s
)
1586 status
= osd_getPath (context_getLarchPath (), s
, &pathName
);
1588 if (status
== OSD_FILEFOUND
)
1592 else if (status
== OSD_FILENOTFOUND
)
1595 lldiagmsg (message ("Cannot find file on LARCH_PATH: %s", s
));
1597 else if (status
== OSD_PATHTOOLONG
)
1599 /* Directory and filename are too long. Report error. */
1600 llbuglit ("soure_getPath: Filename plus directory from search path too long");
1607 return cstring_undefined
;
1610 static void addFile (fileIdList files
, /*@temp@*/ cstring pathName
, fileType typ
)
1612 if (fileTable_exists (context_fileTable (), pathName
))
1615 lldiagmsg (message ("File listed multiple times: %s", pathName
));
1619 fileIdList_add (files
, fileTable_addFile (context_fileTable (), typ
, pathName
));
1624 strIsQuoteOpen (const char * arg
)
1626 register const char * s
;
1627 bool escape
, quoted
;
1629 llassert (arg
!= NULL
);
1642 else if (*s
== '\"')
1658 flags_processFlags (bool inCommandLine
,
1660 fileIdList lclfiles
,
1662 cstringList
*cppArgs
,
1663 int argc
, char **argv
)
1666 cstringSList fl
= cstringSList_undefined
;
1668 for (i
= 0; i
< argc
; i
++)
1672 llassert (argv
!= NULL
);
1675 DPRINTF (("process thisarg [%d]: %s", i
, thisarg
));
1677 if (*thisarg
== '-' || *thisarg
== '+')
1679 bool set
= (*thisarg
== '+');
1683 if (*thisarg
== '-' && *(thisarg
+ 1) == '-') { /* allow -- before flags */
1684 flagname
= cstring_fromChars (thisarg
+ 2);
1686 flagname
= cstring_fromChars (thisarg
+ 1);
1689 opt
= flags_identifyFlag (flagname
);
1690 DPRINTF (("Flag [%s]: %s", flagname
, flagcode_unparse (opt
)));
1692 if (flagcode_isInvalid (opt
))
1694 DPRINTF (("Error!"));
1695 voptgenerror (FLG_BADFLAG
,
1696 message ("Unrecognized option: %s",
1697 cstring_fromChars (thisarg
)),
1700 else if (flagcode_isHelpFlag (opt
))
1704 voptgenerror (FLG_BADFLAG
,
1705 message ("Help flag must be first on the command line: %s",
1706 cstring_fromChars (thisarg
)),
1711 voptgenerror (FLG_BADFLAG
,
1712 message ("Help flags can only be used on the command line: %s",
1713 cstring_fromChars (thisarg
)),
1717 else if (flagcode_isCpp (opt
)) /* preprocessor flag: -D, -U or -I */
1719 if (*thisarg
== '+') /* reject +D, +U or +I */
1724 ("Unrecognized option +%c (did you meant -%c?)", *flagname
, *flagname
),
1727 else if (*(thisarg
+1) == '-') /* reject --D, --U or --I */
1732 ("Unrecognized option --%c (did you meant -%c?)", *flagname
, *flagname
),
1735 else if (*(thisarg
+ 2) == '\0' && flagcode_isCppMacro (opt
))
1740 ("Flag -%c requires a preprocessor macro merged with it (no separate arguments)", *flagname
),
1743 else if (*(thisarg
+ 2) == '\0' && i
+1 >= argc
) /* -I allows spaces between itself and argument */
1745 llassert (opt
== FLG_INCLUDEPATH
);
1748 message ("Flag -I must be followed by a directory name"),
1753 const char *quotcheck
;
1754 if (*(thisarg
+ 2) != '\0') /* argument is merged with flag */
1756 quotcheck
= thisarg
;
1761 llassert (opt
== FLG_INCLUDEPATH
&& *(thisarg
+ 2) == '\0' && i
< argc
);
1762 quotcheck
= argv
[i
];
1765 if (strIsQuoteOpen (quotcheck
))
1767 voptgenerror (FLG_BADFLAG
,
1768 message ("Unclosed quote in flag: %s", quotcheck
),
1773 cstring newCppArg
= cstring_undefined
;
1775 if (*(thisarg
+ 2) != '\0') /* argument is merged with flag */
1777 newCppArg
= cstring_fromCharsNew (thisarg
+ 1);
1779 else /* use next argument */
1781 newCppArg
= cstring_prependChar ('I', cstring_fromChars (argv
[i
]));
1784 *cppArgs
= cstringList_add (*cppArgs
, newCppArg
);
1788 else if (opt
== FLG_SPECPATH
)
1790 char* dir
= thisarg
+ 2; /* skip over -S */
1793 DPRINTF (("space after directory: "));
1795 DPRINTF (("use next argument, argv[%d] : %s", i
, argv
[i
]));
1801 ("Flag %s must be followed by a directory name",
1802 flagcode_unparse (opt
)),
1804 /* TODO: do we really want to add an empty path? */
1807 DPRINTF (("Got directory: [%s]", dir
));
1810 /* TODO: why aren't we freeing the intermediary g_localSpecPath? */
1811 g_localSpecPath
= cstring_toCharsSafe
1812 (osd_pathListConcat (g_localSpecPath
, dir
));
1815 else if (flagcode_isModeName (opt
))
1817 context_setMode (flagname
);
1819 else if (inCommandLine
&& flagcode_isMessageControlFlag (opt
))
1822 ** Processed on first pass
1825 if (flagcode_hasArgument (opt
))
1833 ** A normal control flag
1836 context_userSetFlag (opt
, set
);
1838 if (flagcode_hasArgument (opt
))
1840 if (flagcode_hasNumber (opt
))
1844 flags_setValueFlag (opt
, cstring_fromCharsNew (argv
[i
]));
1851 ("Flag %s must be followed by a number",
1852 flagcode_unparse (opt
)),
1856 else if (flagcode_hasChar (opt
))
1860 flags_setValueFlag (opt
, cstring_fromCharsNew (argv
[i
]));
1867 ("Flag %s must be followed by a character",
1868 flagcode_unparse (opt
)),
1872 else if (flagcode_hasString (opt
)
1873 || opt
== FLG_INIT
|| opt
== FLG_OPTF
)
1878 Changed this because arg can be freed when it's passed to
1879 lslinit_setInitFile and freeing argv[i] causes a seg fault
1881 cstring arg
= cstring_fromCharsNew (argv
[i
]);
1883 /* FIXME: memory leak; for opt == FLG_INIT,
1884 * inputStream_create() will take ownership of arg;
1885 * for the rest, the code above just introduced a leak. */
1887 if (opt
== FLG_OPTF
)
1891 ; /* -f already processed */
1895 (void) rcfiles_read (arg
, cppArgs
, TRUE
);
1898 else if (opt
== FLG_INIT
)
1900 lslinit_setInitFile (inputStream_create
1902 cstring_makeLiteralTemp (LCLINIT_SUFFIX
),
1908 DPRINTF (("String flag: %s / %s",
1909 flagcode_unparse (opt
), arg
));
1910 if (opt
== FLG_MTSFILE
)
1913 ** arg identifies mts files
1918 tmp
= cstring_concat (arg
, MTS_EXTENSION
);
1919 pathName
= findLarchPathFile (tmp
);
1921 if (cstring_isDefined (pathName
))
1922 addFile (mtfiles
, pathName
, FILE_METASTATE
);
1923 cstring_free (pathName
);
1925 tmp
= cstring_concat (arg
, XH_EXTENSION
);
1926 pathName
= findLarchPathFile (tmp
);
1928 if (cstring_isDefined (pathName
))
1929 addFile (cfiles
, pathName
, FILE_XH
);
1930 cstring_free (pathName
);
1934 flags_setStringFlag (opt
, cstring_copy (arg
));
1943 ("Flag %s must be followed by a string",
1944 flagcode_unparse (opt
)),
1955 else /* its a filename */
1957 DPRINTF (("Adding filename: %s", thisarg
));
1958 fl
= cstringSList_add (fl
, cstring_fromChars (thisarg
));
1963 ** create lists of C and LCL files
1968 cstringSList_elements (fl
, current
)
1970 cstring ext
= fileLib_getExtension (current
);
1972 if (cstring_isUndefined (ext
))
1974 /* no extension --- both C and LCL with default extensions */
1977 pathName
= cstring_concat (current
, C_EXTENSION
);
1978 addFile (cfiles
, pathName
, FILE_NORMAL
);
1979 cstring_free (pathName
);
1981 pathName
= cstring_concat (current
, LCL_EXTENSION
);
1982 addFile (lclfiles
, pathName
, FILE_LCL
);
1983 cstring_free (pathName
);
1985 else if (cstring_equal (ext
, PP_EXTENSION
))
1987 if (!context_getFlag (FLG_NOPP
))
1990 (FLG_FILEEXTENSIONS
,
1991 message ("File extension %s used without +nopp flag (will be processed as C source code): %s",
1995 addFile (cfiles
, current
, FILE_NORMAL
);
1999 addFile (cfiles
, current
, FILE_PP
);
2002 else if (cstring_equal (ext
, LCL_EXTENSION
))
2004 addFile (lclfiles
, current
, FILE_LCL
);
2006 else if (cstring_equal (ext
, MTS_EXTENSION
))
2009 pathName
= findLarchPathFile (current
);
2010 if (cstring_isDefined (pathName
))
2011 addFile (mtfiles
, pathName
, FILE_METASTATE
);
2012 cstring_free (pathName
);
2014 /* fileLib_isCExtension(XH_EXTENSION) is true */
2015 else if (cstring_equal (ext
, XH_EXTENSION
))
2018 pathName
= findLarchPathFile (current
);
2019 if (cstring_isDefined (pathName
))
2020 addFile (cfiles
, pathName
, FILE_XH
);
2021 cstring_free (pathName
);
2023 else if (fileLib_isCExtension (ext
))
2025 addFile (cfiles
, current
, FILE_NORMAL
);
2030 (FLG_FILEEXTENSIONS
,
2031 message ("Unrecognized file extension: %s (assuming %s is C source code)",
2035 addFile (cfiles
, current
, FILE_NORMAL
);
2037 } end_cstringSList_elements
;
2041 if (cstringSList_size (fl
) != 0)
2043 /* Cannot list files in .splintrc files */
2044 voptgenerror (FLG_BADFLAG
,
2045 message ("Cannot list files in .splintrc files: %s (probable missing + or -)",
2046 cstringSList_unparse (fl
)),
2051 cstringSList_free (fl
); /* evans 2002-07-12: why wasn't this reported!?? */
2054 int flagcode_priority (/*@unused@*/ flagcode code
)
2057 ** For now, we do a really simple prioritization: all are 1