2 ** LCLint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2001 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 lclint: lclint-request@cs.virginia.edu
21 ** To report a bug: lclint-bug@cs.virginia.edu
22 ** For more information: http://lclint.cs.virginia.edu
27 ** Main module for LCLint checker
33 ** Ensure that WIN32 and _WIN32 are both defined or both undefined.
38 # error "Inconsistent definitions."
42 # error "Inconsistent definitions."
51 # include "lclintMacros.nf"
58 # include "scanline.h"
59 # include "lclscanline.h"
60 # include "lclsyntable.h"
61 # include "lcltokentable.h"
62 # include "lslparse.h"
64 # include "syntable.h"
65 # include "tokentable.h"
74 # include "fileIdList.h"
76 # include "cgrammar.h"
81 extern /*@external@*/ int yydebug;
83 static void printMail (void);
84 static void printMaintainer (void);
85 static void printReferences (void);
86 static void printFlags (void);
87 static void printAnnotations (void);
88 static void printParseErrors (void);
89 static void printComments (void);
90 static void describePrefixCodes (void);
91 static void cleanupFiles (void);
92 static void showHelp (void);
93 static void interrupt (int p_i);
95 static void loadrc (FILE *p_rcfile, cstringSList *p_passThroughArgs)
96 /*@ensures closed p_rcfile@*/ ;
98 static void describeVars (void);
99 static bool specialFlagsHelp (char *p_next);
100 static bool hasShownHerald = FALSE;
101 static char *specFullName (char *p_specfile, /*@out@*/ char **p_inpath)
102 /*@modifies *p_inpath@*/ ;
104 static bool anylcl = FALSE;
105 static clock_t inittime;
107 static /*@only@*/ /*@null@*/ inputStream initFile = inputStream_undefined;
109 static fileIdList preprocessFiles (fileIdList, bool)
110 /*@modifies fileSystem@*/ ;
115 void lslCleanup (void)
116 /*@globals killed g_symtab@*/
117 /*@modifies internalState, g_symtab@*/
120 ** Cleanup all the LCL/LSL.
123 static bool didCleanup = FALSE;
125 llassert (!didCleanup);
130 lsymbol_destroyMod ();
131 LCLSynTableCleanup ();
132 LCLTokenTableCleanup ();
133 LCLScanLineCleanup ();
136 /* clean up LSL parsing */
139 ltokenTableCleanup ();
143 symtable_free (g_symtab);
149 /*@globals undef g_symtab; @*/
150 /*@modifies g_symtab, internalState, fileSystem; @*/
153 ** Open init file provided by user, or use the default LCL init file
156 cstring larchpath = context_getLarchPath ();
157 inputStream LSLinitFile = inputStream_undefined;
161 if (inputStream_isUndefined (initFile))
163 initFile = inputStream_create (cstring_makeLiteral (INITFILENAME),
164 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
167 if (!inputStream_getPath (larchpath, initFile))
169 lldiagmsg (message ("Continuing without LCL init file: %s",
170 inputStream_fileName (initFile)));
174 if (!inputStream_open (initFile))
176 lldiagmsg (message ("Continuing without LCL init file: %s",
177 inputStream_fileName (initFile)));
183 if (!inputStream_open (initFile))
185 lldiagmsg (message ("Continuing without LCL init file: %s",
186 inputStream_fileName (initFile)));
190 /* Initialize checker */
198 LCLTokenTableInit ();
210 /* need this to initialize LCL checker */
212 llassert (inputStream_isDefined (initFile));
213 if (inputStream_isOpen (initFile))
217 LCLScanReset (initFile);
218 LCLProcessInitFileInit ();
219 LCLProcessInitFileReset ();
222 LCLProcessInitFile ();
223 LCLProcessInitFileCleanup ();
226 check (inputStream_close (initFile));
229 /* Initialize LSL init files, for parsing LSL signatures from LSL */
231 LSLinitFile = inputStream_create (cstring_makeLiteral ("lslinit.lsi"),
232 cstring_makeLiteralTemp (".lsi"),
235 if (!inputStream_getPath (larchpath, LSLinitFile))
237 lldiagmsg (message ("Continuing without LSL init file: %s",
238 inputStream_fileName (LSLinitFile)));
242 if (!inputStream_open (LSLinitFile))
244 lldiagmsg (message ("Continuing without LSL init file: %s",
245 inputStream_fileName (LSLinitFile)));
261 if (inputStream_isOpen (LSLinitFile))
264 LSLScanReset (LSLinitFile);
265 LSLProcessInitFileInit ();
267 LSLProcessInitFile ();
269 check (inputStream_close (LSLinitFile));
272 inputStream_free (LSLinitFile);
277 (cstring_makeLiteral ("LSL init file error. Attempting to continue."));
281 g_symtab = symtable_new ();
284 ** sort_init must come after symtab has been initialized
293 ** Equivalent to importing old spec_csupport.lcl
294 ** define immutable LCL type "bool" and bool constants TRUE and FALSE
295 ** and initialized them to be equal to LSL's "true" and "false".
297 ** Reads in CTrait.syms (derived from CTrait.lsl) on LARCH_PATH.
301 LCLReportEolTokens (FALSE);
305 lslProcess (fileIdList lclfiles)
306 /*@globals undef g_currentSpec, undef g_currentSpecName, g_currentloc,
307 undef killed g_symtab; @*/
308 /*@modifies g_currentSpec, g_currentSpecName, g_currentloc, internalState, fileSystem; @*/
311 bool parser_status = FALSE;
312 bool overallStatus = FALSE;
316 context_resetSpecLines ();
318 fileIdList_elements (lclfiles, fid)
320 cstring actualName = cstring_undefined;
321 cstring fname = fileName (fid);
323 if (osd_getPath (cstring_fromChars (g_localSpecPath),
324 fname, &actualName) == OSD_FILENOTFOUND)
326 if (mstring_equal (g_localSpecPath, "."))
328 lldiagmsg (message ("Spec file not found: %s", fname));
332 lldiagmsg (message ("Spec file not found: %s (on %s)",
334 cstring_fromChars (g_localSpecPath)));
339 inputStream specFile;
341 char *namePtr = actualName;
343 while (*namePtr == '.' && *(namePtr + 1) == CONNECTCHAR)
347 /*@noaccess cstring@*/
349 g_currentSpec = cstring_fromCharsNew (namePtr);
351 specFile = inputStream_create (cstring_copy (g_currentSpec),
352 LCL_EXTENSION, TRUE);
354 llassert (inputStream_isDefined (specFile));
356 g_currentSpecName = specFullName
357 (cstring_toCharsSafe (g_currentSpec),
362 if (context_getFlag (FLG_SHOWSCAN))
364 lldiagmsg (message ("< reading spec %s >", g_currentSpec));
367 /* Open source file */
369 if (!inputStream_open (specFile))
371 lldiagmsg (message ("Cannot open file: %s",
372 inputStream_fileName (specFile)));
373 inputStream_free (specFile);
377 scopeInfo dummy_scope = (scopeInfo) dmalloc (sizeof (*dummy_scope));
378 dummy_scope->kind = SPE_INVALID;
381 LCLScanReset (specFile);
384 ** Minor hacks to allow more than one LCL file to
385 ** be scanned, while keeping initializations
388 symtable_enterScope (g_symtab, dummy_scope);
389 resetImports (cstring_fromChars (g_currentSpecName));
390 context_enterLCLfile ();
391 (void) lclHadNewError ();
393 parser_status = (ylparse () != 0);
394 context_exitLCLfile ();
396 overallStatus = parser_status || lclHadNewError ();
398 if (context_getFlag (FLG_DOLCS))
402 outputLCSFile (path, "%FAILED Output from ",
407 outputLCSFile (path, "%PASSED Output from ",
412 (void) inputStream_close (specFile);
413 inputStream_free (specFile);
415 symtable_exitScope (g_symtab);
418 cstring_free (actualName);
419 } end_fileIdList_elements;
421 /* Can cleanup lsl stuff right away */
425 g_currentSpec = cstring_undefined;
426 g_currentSpecName = NULL;
430 static void handlePassThroughFlag (char *arg)
433 char *quotechar = strchr (curarg, '\"');
436 char *freearg = NULL;
438 while (quotechar != NULL)
440 if (*(quotechar - 1) == '\\')
442 char *tp = quotechar - 2;
453 curarg = quotechar + 1;
454 quotechar = strchr (curarg, '\"');
459 llassert (quotechar != NULL);
461 offset = (quotechar - arg) + 2;
465 arg = cstring_toCharsSafe
466 (message ("%s\"\'%s",
467 cstring_fromChars (arg),
468 cstring_fromChars (quotechar + 1)));
474 arg = cstring_toCharsSafe
475 (message ("%s\'\"%s",
476 cstring_fromChars (arg),
477 cstring_fromChars (quotechar + 1)));
482 curarg = arg + offset;
483 quotechar = strchr (curarg, '\"');
489 voptgenerror (FLG_BADFLAG,
490 message ("Unclosed quote in flag: %s",
491 cstring_fromChars (arg)),
500 ** If the value is surrounded by single quotes ('), remove
501 ** them. This is an artifact of UNIX command line?
504 def = osd_fixDefine (cstring_fromChars (arg + 1));
505 DPRINTF (("Do define: %s", def));
507 DPRINTF (("After define"));
509 } else if (arg[0] == 'U') {
510 cppDoUndefine (cstring_fromChars (arg + 1));
519 void showHerald (void)
521 if (hasShownHerald || context_getFlag (FLG_QUIET)) return;
525 fprintf (g_msgstream, "%s\n\n", LCL_VERSION);
526 hasShownHerald = TRUE;
531 static void addFile (fileIdList files, /*@only@*/ cstring s)
533 if (fileTable_exists (context_fileTable (), s))
536 lldiagmsg (message ("File listed multiple times: %s", s));
541 fileIdList_add (files, fileTable_addFileOnly (context_fileTable (), s));
545 static void addXHFile (fileIdList files, /*@only@*/ cstring s)
547 if (fileTable_exists (context_fileTable (), s))
550 lldiagmsg (message ("File listed multiple times: %s", s));
555 fileIdList_add (files, fileTable_addXHFile (context_fileTable (), s));
561 ** Disable MSVC++ warning about return value. Methinks humbly lclint control
562 ** comments are a mite more legible.
566 # pragma warning (disable:4035)
569 int main (int argc, char *argv[])
571 /*@globals killed undef g_currentloc,
575 /*@modifies g_currentloc, fileSystem,
579 /*@globals killed undef g_currentloc,
580 killed undef initFile,
581 killed g_localSpecPath,
582 killed undef g_currentSpec,
583 killed undef g_currentSpecName,
587 /*@modifies g_currentloc, initFile,
588 g_localSpecPath, g_currentSpec, g_currentSpecName, fileSystem,
593 bool first_time = TRUE;
594 bool showhelp = FALSE;
597 inputStream sourceFile = inputStream_undefined;
599 fileIdList dercfiles;
600 cstringSList fl = cstringSList_undefined;
601 cstringSList passThroughArgs = cstringSList_undefined;
602 fileIdList cfiles, xfiles, lclfiles, mtfiles;
603 clock_t before, lcltime, libtime, pptime, cptime, rstime;
607 _wildcard (&argc, &argv);
610 g_msgstream = stdout;
612 (void) signal (SIGINT, interrupt);
613 (void) signal (SIGSEGV, interrupt);
615 cfiles = fileIdList_create ();
616 xfiles = fileIdList_create ();
617 lclfiles = fileIdList_create ();
618 mtfiles = fileIdList_create ();
621 clabstract_initMod ();
622 typeIdSet_initMod ();
623 cppReader_initMod ();
626 g_currentloc = fileloc_createBuiltin ();
631 context_setInCommandLine ();
643 ** Add include directories from environment.
647 cstring incval = cstring_copy (osd_getEnvironmentVariable (INCLUDEPATH_VAR));
648 cstring oincval = incval;
650 if (cstring_isDefined (incval))
653 ** Each directory on the include path is a system include directory.
656 DPRINTF (("include: %s", incval));
657 context_setString (FLG_SYSTEMDIRS, cstring_copy (incval));
659 while (cstring_isDefined (incval))
662 char *nextsep = strchr (incval, PATH_SEPARATOR);
668 dir = cstring_copy (incval);
670 if (cstring_length (dir) == 0
671 || !isalpha ((int) cstring_firstChar (dir)))
674 ** win32 environment values can have special values,
680 cppAddIncludeDir (dir);
683 *nextsep = PATH_SEPARATOR;
684 incval = cstring_fromChars (nextsep + 1);
692 /*@noaccess cstring@*/
695 else /* 2001-09-09: herbert */
697 /* Put C_INCLUDE_PATH directories in sysdirs */
698 cstring cincval = osd_getEnvironmentVariable (cstring_makeLiteralTemp ("C_INCLUDE_PATH"));
699 if (cstring_isDefined (cincval))
701 context_setString (FLG_SYSTEMDIRS, cstring_copy (cincval));
706 cstring_free (oincval);
710 ** check RCFILE for default flags
714 cstring home = osd_getHomeDir ();
717 bool defaultf = TRUE;
720 for (i = 1; i < argc; i++)
725 if (*thisarg == '-' || *thisarg == '+')
729 if (mstring_equal (thisarg, "nof"))
733 else if (mstring_equal (thisarg, "f"))
739 rcfile = fileTable_openFile (context_fileTable (), cstring_fromChars (fname), "r");
743 fileloc oloc = g_currentloc;
745 g_currentloc = fileloc_createRc (cstring_fromChars (fname));
746 loadrc (rcfile, &passThroughArgs);
747 fileloc_reallyFree (g_currentloc);
753 lldiagmsg (message ("Options file not found: %s",
754 cstring_fromChars (fname)));
759 (cstring_makeLiteral ("Flag f to select options file "
760 "requires an argument"));
764 ; /* wait to process later */
771 if (!cstring_isEmpty (home)) {
772 fname = cstring_toCharsSafe (message ("%s%h%s", home, CONNECTCHAR,
773 cstring_fromChars (RCFILE)));
774 mstring_markFree (fname);
780 if (!nof && defaultf)
782 if (!mstring_isEmpty (fname)) {
783 rcfile = fileTable_openFile (context_fileTable (), cstring_fromChars (fname), "r");
787 fileloc oloc = g_currentloc;
789 g_currentloc = fileloc_createRc (cstring_fromChars (fname));
790 loadrc (rcfile, &passThroughArgs);
791 fileloc_reallyFree (g_currentloc);
796 # if defined(MSDOS) || defined(OS2)
797 fname = cstring_toCharsSafe (message ("%s",
798 cstring_fromChars (RCFILE)));
800 fname = cstring_toCharsSafe (message ("./%s",
801 cstring_fromChars (RCFILE)));
804 rcfile = fileTable_openFile (context_fileTable (), cstring_fromChars (fname), "r");
808 fileloc oloc = g_currentloc;
810 g_currentloc = fileloc_createRc (cstring_fromChars (fname));
811 loadrc (rcfile, &passThroughArgs);
812 fileloc_reallyFree (g_currentloc);
822 for (i = 1; i < argc; i++)
838 if (*thisarg == '-' || *thisarg == '+')
840 thisarg++; /* skip '-' */
842 if (mstring_equal (thisarg, "modes"))
844 llmsg (describeModes ());
846 else if (mstring_equal (thisarg, "vars")
847 || mstring_equal (thisarg, "env"))
851 else if (mstring_equal (thisarg, "annotations"))
855 else if (mstring_equal (thisarg, "parseerrors"))
859 else if (mstring_equal (thisarg, "comments"))
863 else if (mstring_equal (thisarg, "prefixcodes"))
865 describePrefixCodes ();
867 else if (mstring_equal (thisarg, "references")
868 || mstring_equal (thisarg, "refs"))
872 else if (mstring_equal (thisarg, "mail"))
876 else if (mstring_equal (thisarg, "maintainer")
877 || mstring_equal (thisarg, "version"))
881 else if (mstring_equal (thisarg, "flags"))
885 char *next = argv[i + 1];
887 if (specialFlagsHelp (next))
893 flagkind k = identifyCategory (cstring_fromChars (next));
909 cstring s = describeFlag (cstring_fromChars (thisarg));
911 if (cstring_isDefined (s))
919 if (*thisarg == '-' || *thisarg == '+')
921 bool set = (*thisarg == '+');
924 thisarg++; /* skip '-' */
925 flagname = cstring_fromChars (thisarg);
927 DPRINTF (("Flag: %s", flagname));
928 opt = identifyFlag (flagname);
929 DPRINTF (("Flag: %s", flagcode_unparse (opt)));
931 if (flagcode_isSkip (opt))
933 DPRINTF (("Skipping!"));
935 else if (flagcode_isInvalid (opt))
937 DPRINTF (("Invalid: %s", flagname));
939 if (isMode (flagname))
941 context_setMode (flagname);
945 DPRINTF (("Error!"));
946 voptgenerror (FLG_BADFLAG,
947 message ("Unrecognized option: %s",
948 cstring_fromChars (thisarg)),
954 context_userSetFlag (opt, set);
956 if (flagcode_hasArgument (opt))
962 else if (flagcode_isPassThrough (opt)) /* -D or -U */
964 passThroughArgs = cstringSList_add
965 (passThroughArgs, cstring_fromChars (thisarg));
967 else if (flagcode_hasValue (opt))
971 setValueFlag (opt, cstring_fromChars (argv[i]));
977 ("Flag %s must be followed by a number",
978 flagcode_unparse (opt)));
981 else if (opt == FLG_INCLUDEPATH || opt == FLG_SPECPATH)
983 cstring dir = cstring_suffix (cstring_fromChars (thisarg), 1); /* skip over I */
987 case FLG_INCLUDEPATH:
988 cppAddIncludeDir (dir);
989 /*@switchbreak@*/ break;
992 g_localSpecPath = cstring_toCharsSafe
994 cstring_fromChars (g_localSpecPath),
998 /*@switchbreak@*/ break;
1002 else if (flagcode_hasString (opt)
1003 || opt == FLG_INIT || opt == FLG_OPTF)
1007 cstring arg = cstring_fromChars (argv[i]);
1009 if (opt == FLG_OPTF)
1011 ; /* -f already processed */
1013 else if (opt == FLG_INIT)
1016 initFile = inputStream_create
1018 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
1025 DPRINTF (("String flag: %s / %s",
1026 flagcode_unparse (opt), arg));
1027 if (opt == FLG_MTSFILE)
1030 ** arg identifies mts files
1033 addFile (mtfiles, message ("%s%s", arg, MTS_EXTENSION));
1034 addXHFile (xfiles, message ("%s%s", arg, XH_EXTENSION));
1038 setStringFlag (opt, arg);
1046 ("Flag %s must be followed by a string",
1047 flagcode_unparse (opt)));
1057 else /* its a filename */
1059 DPRINTF (("Adding filename: %s", thisarg));
1060 fl = cstringSList_add (fl, cstring_fromChars (thisarg));
1068 ** create lists of C and LCL files
1071 cstringSList_elements (fl, current)
1073 cstring ext = fileLib_getExtension (current);
1075 if (cstring_isUndefined (ext))
1077 /* no extension --- both C and LCL with default extensions */
1079 addFile (cfiles, message ("%s%s", current, C_EXTENSION));
1080 addFile (lclfiles, message ("%s%s", current, LCL_EXTENSION));
1082 else if (cstring_equal (ext, XH_EXTENSION))
1084 addXHFile (xfiles, cstring_copy (current));
1086 else if (cstring_equal (ext, PP_EXTENSION))
1088 if (!context_getFlag (FLG_NOPP))
1091 (FLG_FILEEXTENSIONS,
1092 message ("File extension %s used without +nopp flag (will be processed as C source code): %s",
1097 addFile (cfiles, cstring_copy (current));
1099 else if (cstring_equal (ext, LCL_EXTENSION))
1101 addFile (lclfiles, cstring_copy (current));
1103 else if (fileLib_isCExtension (ext))
1105 addFile (cfiles, cstring_copy (current));
1107 else if (cstring_equal (ext, MTS_EXTENSION))
1109 addFile (mtfiles, cstring_copy (current));
1114 (FLG_FILEEXTENSIONS,
1115 message ("Unrecognized file extension: %s (assuming %s is C source code)",
1119 addFile (cfiles, cstring_copy (current));
1121 } end_cstringSList_elements;
1123 showHerald (); /*@i723 move earlier? */
1131 fprintf (g_msgstream, "\n");
1133 fileIdList_free (cfiles);
1134 fileIdList_free (xfiles);
1135 fileIdList_free (lclfiles);
1144 inittime = clock ();
1146 context_resetErrors ();
1147 context_clearInCommandLine ();
1149 anylcl = !fileIdList_isEmpty (lclfiles);
1151 if (context_doMerge ())
1153 cstring m = context_getMerge ();
1155 if (context_getFlag (FLG_SHOWSCAN))
1157 fprintf (g_msgstream, "< loading %s ", cstring_toCharsSafe (m));
1162 if (context_getFlag (FLG_SHOWSCAN))
1164 fprintf (g_msgstream, " >\n");
1167 if (!usymtab_existsType (context_getBoolName ()))
1169 usymtab_initBool ();
1174 if (!context_getFlag (FLG_NOLIB) && loadStandardState ())
1183 /* setup bool type and constants */
1184 usymtab_initBool ();
1187 fileloc_free (g_currentloc);
1188 g_currentloc = fileloc_createBuiltin ();
1191 ** Read metastate files (must happen before loading libraries)
1194 fileIdList_elements (mtfiles, mtfile)
1196 context_setFileId (mtfile);
1198 if (context_getFlag (FLG_SHOWSCAN))
1200 lldiagmsg (message ("< processing %s >", rootFileName (mtfile)));
1203 mtreader_readFile (cstring_copy (fileName (mtfile)));
1204 } end_fileIdList_elements;
1211 llfatalerror (cstring_makeLiteral ("This version of LCLint does not handle LCL files."));
1213 lslProcess (lclfiles);
1217 usymtab_initGlobalMarker ();
1222 ** call the pre-preprocessor and /lib/cpp to generate appropriate
1227 context_setInCommandLine ();
1229 DPRINTF (("Pass through: %s", cstringSList_unparse (passThroughArgs)));
1231 cstringSList_elements (passThroughArgs, thisarg) {
1232 handlePassThroughFlag (cstring_toCharsSafe (thisarg));
1233 } end_cstringSList_elements;
1235 cstringSList_free (passThroughArgs);
1239 DPRINTF (("Initializing cpp reader!"));
1240 cppReader_initialize ();
1241 cppReader_saveDefinitions ();
1243 context_clearInCommandLine ();
1245 if (!context_getFlag (FLG_NOPP))
1251 if (context_getFlag (FLG_SHOWSCAN))
1253 fprintf (stderr, "< preprocessing");
1258 context_setPreprocessing ();
1259 dercfiles = preprocessFiles (xfiles, TRUE);
1260 tfiles = preprocessFiles (cfiles, FALSE);
1261 dercfiles = fileIdList_append (dercfiles, tfiles);
1262 fileIdList_free (tfiles);
1264 context_clearPreprocessing ();
1266 fileIdList_free (cfiles);
1268 if (context_getFlag (FLG_SHOWSCAN))
1270 fprintf (stderr, " >\n");
1278 dercfiles = fileIdList_append (cfiles, xfiles);
1283 ** now, check all the corresponding C files
1285 ** (for now these are just <file>.c, but after pre-processing
1286 ** will be <tmpprefix>.<file>.c)
1291 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1295 llbug (message ("Files unclosed: %d", nfiles));
1300 DPRINTF (("Initializing..."));
1302 exprNode_initMod ();
1304 DPRINTF (("Okay..."));
1306 fileIdList_elements (dercfiles, fid)
1308 sourceFile = inputStream_create (cstring_copy (fileName (fid)), C_EXTENSION, TRUE);
1309 context_setFileId (fid);
1311 /* Open source file */
1313 if (inputStream_isUndefined (sourceFile) || (!inputStream_open (sourceFile)))
1315 /* previously, this was ignored ?! */
1316 llbug (message ("Could not open temp file: %s", fileName (fid)));
1320 yyin = inputStream_getFile (sourceFile); /*< shared <- only */
1322 llassert (yyin != NULL);
1324 if (context_getFlag (FLG_SHOWSCAN))
1326 lldiagmsg (message ("< checking %s >", rootFileName (fid)));
1330 ** Every time, except the first time, through the loop,
1331 ** need to call yyrestart to clean up the parse buffer.
1336 (void) yyrestart (yyin);
1343 DPRINTF (("Entering..."));
1344 context_enterFile ();
1346 context_exitCFile ();
1348 (void) inputStream_close (sourceFile);
1350 } end_fileIdList_elements;
1354 /* process any leftover macros */
1356 context_processAllMacros ();
1358 /* check everything that was specified was defined */
1360 /* don't check if no c files were processed ?
1361 ** is this correct behaviour?
1364 if (context_getFlag (FLG_SHOWSCAN))
1366 lldiagmsg (cstring_makeLiteral ("< global checks >"));
1371 if (context_getLinesProcessed () > 0)
1373 usymtab_allDefined ();
1376 if (context_maybeSet (FLG_TOPUNUSED))
1378 uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main"));
1380 if (uentry_isValid (ue))
1382 uentry_setUsed (ue, fileloc_observeBuiltin ());
1388 if (context_maybeSet (FLG_EXPORTLOCAL))
1390 usymtab_exportLocal ();
1394 if (context_maybeSet (FLG_EXPORTHEADER))
1396 usymtab_exportHeader ();
1399 if (context_getFlag (FLG_SHOWUSES))
1401 usymtab_displayAllUses ();
1404 context_checkSuppressCounts ();
1406 if (context_doDump ())
1408 cstring dump = context_getDump ();
1419 if (context_getFlag (FLG_SHOWSUMMARY))
1426 bool isQuiet = context_getFlag (FLG_QUIET);
1427 cstring specErrors = cstring_undefined;
1429 int nspecErrors = lclNumberErrors ();
1434 if (context_neednl ())
1435 fprintf (g_msgstream, "\n");
1438 if (nspecErrors > 0)
1440 if (nspecErrors == context_getLCLExpect ())
1443 message ("%d spec error%& found, as expected\n ",
1448 if (context_getLCLExpect () > 0)
1451 message ("%d spec error%& found, expected %d\n ",
1453 (int) context_getLCLExpect ());
1457 specErrors = message ("%d spec error%& found\n ",
1465 if (context_getLCLExpect () > 0)
1467 specErrors = message ("No spec errors found, expected %d\n ",
1468 (int) context_getLCLExpect ());
1474 if (context_anyErrors ())
1476 if (context_numErrors () == context_getExpect ())
1479 llmsg (message ("Finished LCLint checking --- "
1480 "%s%d code error%& found, as expected",
1481 specErrors, context_numErrors ()));
1486 if (context_getExpect () > 0)
1490 ("Finished LCLint checking --- "
1491 "%s%d code error%& found, expected %d",
1492 specErrors, context_numErrors (),
1493 (int) context_getExpect ()));
1503 llmsg (message ("Finished LCLint checking --- "
1504 "%s%d code error%& found",
1505 specErrors, context_numErrors ()));
1514 if (context_getExpect () > 0)
1518 ("Finished LCLint checking --- "
1519 "%sno code errors found, expected %d",
1521 (int) context_getExpect ()));
1528 if (context_getLinesProcessed () > 0)
1531 llmsg (message ("Finished LCLint checking --- %sno code errors found",
1538 llmsg (message ("Finished LCLint checking --- %sno code processed",
1545 cstring_free (specErrors);
1548 if (context_getFlag (FLG_STATS))
1550 clock_t ttime = clock () - before;
1551 int specLines = context_getSpecLinesProcessed ();
1557 fprintf (g_msgstream, "%d spec, ", specLines);
1560 # ifndef CLOCKS_PER_SEC
1561 fprintf (g_msgstream, "%d source lines in %ld time steps (steps/sec unknown)\n",
1562 context_getLinesProcessed (),
1565 fprintf (g_msgstream, "%d source lines in %.2f s.\n",
1566 context_getLinesProcessed (),
1567 (double) ttime / CLOCKS_PER_SEC);
1575 if (context_getFlag (FLG_TIMEDIST))
1577 clock_t ttime = clock () - before;
1581 char *msg = (char *) dmalloc (256 * sizeof (*msg));
1586 "Time distribution (percent): initialize %.2f / lcl %.2f / "
1587 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1588 (100.0 * (double) (libtime - before) / ttime),
1589 (100.0 * (double) (lcltime - libtime) / ttime),
1590 (100.0 * (double) (pptime - lcltime) / ttime),
1591 (100.0 * (double) (cptime - pptime) / ttime),
1592 (100.0 * (double) (rstime - cptime) / ttime));
1597 "Time distribution (percent): initialize %.2f / "
1598 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1599 (100.0 * (double) (libtime - before) / ttime),
1600 (100.0 * (double) (pptime - libtime) / ttime),
1601 (100.0 * (double) (cptime - pptime) / ttime),
1602 (100.0 * (double) (rstime - cptime) / ttime));
1605 llgenindentmsgnoloc (cstring_fromCharsO (msg));
1609 llexit (expsuccess ? LLSUCCESS : LLFAILURE);
1614 ** Reenable return value warnings.
1616 # pragma warning (default:4035)
1624 llmsg (message ("Source files are .c, .h and %s files. If there is no suffix,",
1626 llmsg (message (" LCLint will look for <file>.c and <file>%s.", LCL_EXTENSION));
1628 llmsglit ("Use lclint -help <topic or flag name> for more information");
1630 llmsglit ("Topics:");
1632 llmsglit (" annotations (describes source-code annotations)");
1633 llmsglit (" comments (describes control comments)");
1634 llmsglit (" flags (describes flag categories)");
1635 llmsglit (" flags <category> (describes flags in category)");
1636 llmsglit (" flags all (short description of all flags)");
1637 llmsglit (" flags alpha (list all flags alphabetically)");
1638 llmsglit (" flags full (full description of all flags)");
1639 llmsglit (" mail (information on mailing lists)");
1640 llmsglit (" modes (show mode settings)");
1641 llmsglit (" parseerrors (help on handling parser errors)");
1642 llmsglit (" prefixcodes (character codes in namespace prefixes)");
1643 llmsglit (" references (sources for more information)");
1644 llmsglit (" vars (environment variables)");
1645 llmsglit (" version (information on compilation, maintainer)");
1650 specialFlagsHelp (char *next)
1652 if ((next != NULL) && (*next != '-') && (*next != '+'))
1654 if (mstring_equal (next, "alpha"))
1659 else if (mstring_equal (next, "all"))
1661 printAllFlags (TRUE, FALSE);
1664 else if (mstring_equal (next, "categories")
1665 || mstring_equal (next, "cats"))
1667 listAllCategories ();
1670 else if (mstring_equal (next, "full"))
1672 printAllFlags (FALSE, TRUE);
1687 printParseErrors (void)
1689 llmsglit ("Parse Errors");
1690 llmsglit ("------------");
1692 llmsglit ("LCLint will sometimes encounter a parse error for code that "
1693 "can be parsed with a local compiler. There are a few likely "
1694 "causes for this and a number of techniques that can be used "
1695 "to work around the problem.");
1697 llmsglit ("Compiler extensions --- compilers sometimes extend the C "
1698 "language with compiler-specific keywords and syntax. While "
1699 "it is not advisible to use these, oftentimes one has no choice "
1700 "when the system header files use compiler extensions. ");
1702 llmsglit ("LCLint supports some of the GNU (gcc) compiler extensions, "
1703 "if the +gnuextensions flag is set. You may be able to workaround "
1704 "other compiler extensions by using a pre-processor define. "
1705 "Alternately, you can surround the unparseable code with");
1707 llmsglit (" # ifndef __LCLINT__");
1709 llmsglit (" # endif");
1711 /* evans 2000-12-21 fixed typo reported by Jeroen Ruigrok/Asmodai */
1712 llmsglit ("Missing type definitions --- an undefined type name will usually "
1713 "lead to a parse error. This often occurs when a standard header "
1714 "file defines some type that is not part of the standard library. ");
1715 llmsglit ("By default, LCLint does not process the local files corresponding "
1716 "to standard library headers, but uses a library specification "
1717 "instead so dependencies on local system headers can be detected. "
1718 "If another system header file that does not correspond to a "
1719 "standard library header uses one of these superfluous types, "
1720 "a parse error will result.");
1722 llmsglit ("If the parse error is inside a posix standard header file, the "
1723 "first thing to try is +posixlib. This make LCLint use "
1724 "the posix library specification instead of reading the posix "
1727 llmsglit ("Otherwise, you may need to either manually define the problematic "
1728 "type (e.g., add -Dmlink_t=int to your .lclintrc file) or force "
1729 "lclint to process the header file that defines it. This is done "
1730 "by setting -skipansiheaders or -skipposixheaders before "
1731 "the file that defines the type is #include'd.");
1732 llmsglit ("(See lclint -help "
1733 "skipansiheaders and lclint -help skipposixheaders for a list of "
1734 "standard headers.) For example, if <sys/local.h> uses a type "
1735 "defined by posix header <sys/types.h> but not defined by the "
1736 "posix library, we might do: ");
1738 llmsglit (" /*@-skipposixheaders@*/");
1739 llmsglit (" # include <sys/types.h>");
1740 llmsglit (" /*@=skipposixheaders@*/");
1741 llmsglit (" # include <sys/local.h>");
1743 llmsglit ("to force LCLint to process <sys/types.h>.");
1745 llmsglit ("At last resort, +trytorecover can be used to make LCLint attempt "
1746 "to continue after a parse error. This is usually not successful "
1747 "and the author does not consider assertion failures when +trytorecover "
1748 "is used to be bugs.");
1752 printAnnotations (void)
1754 llmsglit ("Annotations");
1755 llmsglit ("-----------");
1757 llmsglit ("Annotations are semantic comments that document certain "
1758 "assumptions about functions, variables, parameters, and types. ");
1760 llmsglit ("They may be used to indicate where the representation of a "
1761 "user-defined type is hidden, to limit where a global variable may "
1762 "be used or modified, to constrain what a function implementation "
1763 "may do to its parameters, and to express checked assumptions about "
1764 "variables, types, structure fields, function parameters, and "
1765 "function results.");
1767 llmsglit ("Annotations are introduced by \"/*@\". The role of the @ may be "
1768 "played by any printable character, selected using -commentchar <char>.");
1770 llmsglit ("Consult the User's Guide for descriptions of checking associated with each annotation.");
1772 llmsglit ("Globals: (in function declarations)");
1773 llmsglit (" /*@globals <globitem>,+ @*/");
1774 llmsglit (" globitem is an identifier, internalState or fileSystem");
1776 llmsglit ("Modifies: (in function declarations)");
1777 llmsglit (" /*@modifies <moditem>,+ @*/");
1778 llmsglit (" moditem is an lvalue");
1779 llmsglit (" /*@modifies nothing @*/");
1780 llmsglit (" /*@*/ (Abbreviation for no globals and modifies nothing.)");
1782 llmsglit ("Iterators:");
1783 llmsglit (" /*@iter <identifier> (<parameter-type-list>) @*/ - declare an iterator");
1785 llmsglit ("Constants:");
1786 llmsglit (" /*@constant <declaration> @*/ - declares a constant");
1788 llmsglit ("Alternate Types:");
1789 llmsglit (" /*@alt <basic-type>,+ @*/");
1790 llmsglit (" (e.g., int /*@alt char@*/ is a type matching either int or char)");
1792 llmsglit ("Declarator Annotations");
1794 llmsglit ("Type Definitions:");
1795 llmsglit (" /*@abstract@*/ - representation is hidden from clients");
1796 llmsglit (" /*@concrete@*/ - representation is visible to clients");
1797 llmsglit (" /*@immutable@*/ - instances of the type cannot change value");
1798 llmsglit (" /*@mutable@*/ - instances of the type can change value");
1799 llmsglit (" /*@refcounted@*/ - reference counted type");
1801 llmsglit ("Global Variables:");
1802 llmsglit (" /*@unchecked@*/ - weakest checking for global use");
1803 llmsglit (" /*@checkmod@*/ - check modification by not use of global");
1804 llmsglit (" /*@checked@*/ - check use and modification of global");
1805 llmsglit (" /*@checkedstrict@*/ - check use of global strictly");
1807 llmsglit ("Memory Management:");
1808 llmsglit (" /*@dependent@*/ - a reference to externally-owned storage");
1809 llmsglit (" /*@keep@*/ - a parameter that is kept by the called function");
1810 llmsglit (" /*@killref@*/ - a refcounted parameter, killed by the call");
1811 llmsglit (" /*@only@*/ - an unshared reference");
1812 llmsglit (" /*@owned@*/ - owner of storage that may be shared by /*@dependent@*/ references");
1813 llmsglit (" /*@shared@*/ - shared reference that is never deallocated");
1814 llmsglit (" /*@temp@*/ - temporary parameter");
1816 llmsglit ("Aliasing:");
1817 llmsglit (" /*@unique@*/ - may not be aliased by any other visible reference");
1818 llmsglit (" /*@returned@*/ - may be aliased by the return value");
1820 llmsglit ("Exposure:");
1821 llmsglit (" /*@observer@*/ - reference that cannot be modified");
1822 llmsglit (" /*@exposed@*/ - exposed reference to storage in another object");
1824 llmsglit ("Definition State:");
1825 llmsglit (" /*@out@*/ - storage reachable from reference need not be defined");
1826 llmsglit (" /*@in@*/ - all storage reachable from reference must be defined");
1827 llmsglit (" /*@partial@*/ - partially defined, may have undefined fields");
1828 llmsglit (" /*@reldef@*/ - relax definition checking");
1830 llmsglit ("Global State: (for globals lists, no /*@, since list is already in /*@\'s)");
1831 llmsglit (" undef - variable is undefined before the call");
1832 llmsglit (" killed - variable is undefined after the call");
1834 llmsglit ("Null State:");
1835 llmsglit (" /*@null@*/ - possibly null pointer");
1836 llmsglit (" /*@notnull@*/ - non-null pointer");
1837 llmsglit (" /*@relnull@*/ - relax null checking");
1839 llmsglit ("Null Predicates:");
1840 llmsglit (" /*@truenull@*/ - if result is TRUE, first parameter is NULL");
1841 llmsglit (" /*@falsenull@*/ - if result is TRUE, first parameter is not NULL");
1843 llmsglit ("Execution:");
1844 llmsglit (" /*@exits@*/ - function never returns");
1845 llmsglit (" /*@mayexit@*/ - function may or may not return");
1846 llmsglit (" /*@trueexit@*/ - function does not return if first parameter is TRUE");
1847 llmsglit (" /*@falseexit@*/ - function does not return if first parameter if FALSE");
1848 llmsglit (" /*@neverexit@*/ - function always returns");
1850 llmsglit ("Side-Effects:");
1851 llmsglit (" /*@sef@*/ - corresponding actual parameter has no side effects");
1853 llmsglit ("Declaration:");
1854 llmsglit (" /*@unused@*/ - need not be used (no unused errors reported)");
1855 llmsglit (" /*@external@*/ - defined externally (no undefined error reported)");
1858 llmsglit (" /*@fallthrough@*/ - fall-through case");
1860 llmsglit ("Break:");
1861 llmsglit (" /*@innerbreak@*/ - break is breaking an inner loop or switch");
1862 llmsglit (" /*@loopbreak@*/ - break is breaking a loop");
1863 llmsglit (" /*@switchbreak@*/ - break is breaking a switch");
1864 llmsglit (" /*@innercontinue@*/ - continue is continuing an inner loop");
1866 llmsglit ("Unreachable Code:");
1867 llmsglit (" /*@notreached@*/ - statement may be unreachable.");
1869 llmsglit ("Special Functions:");
1870 llmsglit (" /*@printflike@*/ - check variable arguments like printf");
1871 llmsglit (" /*@scanflike@*/ - check variable arguments like scanf");
1875 printComments (void)
1877 llmsglit ("Control Comments");
1878 llmsglit ("----------------");
1880 llmsglit ("Setting Flags");
1882 llmsglit ("Most flags (all except those characterized as \"globally-settable only\") can be set locally using control comments. A control comment can set flags locally to override the command line settings. The original flag settings are restored before processing the next file.");
1884 llmsglit ("The syntax for setting flags in control comments is the same as that of the command line, except that flags may also be preceded by = to restore their setting to the original command-line value. For instance,");
1885 llmsglit (" /*@+boolint -modifies =showfunc@*/");
1886 llmsglit ("sets boolint on (this makes bool and int indistinguishable types), sets modifies off (this prevents reporting of modification errors), and sets showfunc to its original setting (this controls whether or not the name of a function is displayed before a message).");
1888 llmsglit ("Error Suppression");
1890 llmsglit ("Several comments are provided for suppressing messages. In general, it is usually better to use specific flags to suppress a particular error permanently, but the general error suppression flags may be more convenient for quickly suppressing messages for code that will be corrected or documented later.");
1892 llmsglit ("/*@ignore@*/ ... /*@end@*/");
1894 (cstring_makeLiteral
1895 ("No errors will be reported in code regions between /*@ignore@*/ and /*@end@*/. These comments can be used to easily suppress an unlimited number of messages."));
1896 llmsglit ("/*@i@*/");
1898 (cstring_makeLiteral
1899 ("No errors will be reported from an /*@i@*/ comment to the end of the line."));
1900 llmsglit ("/*@i<n>@*/");
1902 (cstring_makeLiteral
1903 ("No errors will be reported from an /*@i<n>@*/ (e.g., /*@i3@*/) comment to the end of the line. If there are not exactly n errors suppressed from the comment point to the end of the line, LCLint will report an error."));
1904 llmsglit ("/*@t@*/, /*@t<n>@*/");
1906 (cstring_makeLiteral
1907 ("Like i and i<n>, except controlled by +tmpcomments flag. These can be used to temporarily suppress certain errors. Then, -tmpcomments can be set to find them again."));
1909 llmsglit ("Type Access");
1911 llmsglit ("/*@access <type>@*/");
1912 llmsglit (" Allows the following code to access the representation of <type>");
1913 llmsglit ("/*@noaccess <type>@*/");
1914 llmsglit (" Hides the representation of <type>");
1916 llmsglit ("Macro Expansion");
1918 llmsglit ("/*@notfunction@*/");
1920 (cstring_makeLiteral
1921 ("Indicates that the next macro definition is not intended to be a "
1922 "function, and should be expanded in line instead of checked as a "
1923 "macro function definition."));
1930 llmsglit ("Flag Categories");
1931 llmsglit ("---------------");
1932 listAllCategories ();
1933 llmsglit ("\nTo see the flags in a flag category, do\n lclint -help flags <category>");
1934 llmsglit ("To see a list of all flags in alphabetical order, do\n lclint -help flags alpha");
1935 llmsglit ("To see a full description of all flags, do\n lclint -help flags full");
1939 printMaintainer (void)
1941 llmsg (message ("Maintainer: %s", cstring_makeLiteralTemp (LCLINT_MAINTAINER)));
1942 llmsglit (LCL_COMPILE);
1948 llmsglit ("Mailing Lists");
1949 llmsglit ("-------------");
1951 llmsglit ("There are two mailing lists associated with LCLint: ");
1953 llmsglit (" lclint-announce@virginia.edu");
1955 llmsglit (" Reserved for announcements of new releases and bug fixes.");
1956 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
1957 llmsglit (" subscribe lclint-announce");
1959 llmsglit (" lclint-interest@virginia.edu");
1961 llmsglit (" Informal discussions on the use and development of lclint.");
1962 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
1963 llmsglit (" subscribe lclint-interest");
1967 printReferences (void)
1969 llmsglit ("References");
1970 llmsglit ("----------");
1972 llmsglit ("The LCLint web site is http://lclint.cs.virginia.edu");
1974 llmsglit ("Technical papers relating to LCLint include:");
1976 llmsglit (" David Evans. \"Static Detection of Dynamic Memory Errors\".");
1977 llmsglit (" SIGPLAN Conference on Programming Language Design and ");
1978 llmsglit (" Implementation (PLDI '96), Philadelphia, PA, May 1996.");
1980 llmsglit (" David Evans, John Guttag, Jim Horning and Yang Meng Tan. ");
1981 llmsglit (" \"LCLint: A Tool for Using Specifications to Check Code\".");
1982 llmsglit (" SIGSOFT Symposium on the Foundations of Software Engineering,");
1983 llmsglit (" December 1994.");
1985 llmsglit ("A general book on Larch is:");
1987 llmsglit (" Guttag, John V., Horning, James J., (with Garland, S. J., Jones, ");
1988 llmsglit (" K. D., Modet, A., and Wing, J. M.), \"Larch: Languages and Tools ");
1989 llmsglit (" for Formal Specification\", Springer-Verlag, 1993.");
1993 describePrefixCodes (void)
1995 llmsglit ("Prefix Codes");
1996 llmsglit ("------------");
1998 llmsglit ("These characters have special meaning in name prefixes:");
2000 llmsg (message (" %h Any uppercase letter [A-Z]", PFX_UPPERCASE));
2001 llmsg (message (" %h Any lowercase letter [a-z]", PFX_LOWERCASE));
2002 llmsg (message (" %h Any character (valid in a C identifier)", PFX_ANY));
2003 llmsg (message (" %h Any digit [0-9]", PFX_DIGIT));
2004 llmsg (message (" %h Any non-uppercase letter [a-z0-9_]", PFX_NOTUPPER));
2005 llmsg (message (" %h Any non-lowercase letter [A-Z0-9_]", PFX_NOTLOWER));
2006 llmsg (message (" %h Any letter [A-Za-z]", PFX_ANYLETTER));
2007 llmsg (message (" %h Any letter or digit [A-Za-z0-9]", PFX_ANYLETTERDIGIT));
2008 llmsglit (" * Zero or more repetitions of the previous character class until the end of the name");
2017 eval = context_getLarchPath ();
2018 def = osd_getEnvironmentVariable (LARCH_PATH);
2020 if (cstring_isDefined (def) ||
2021 !cstring_equal (eval, cstring_fromChars (DEFAULT_LARCHPATH)))
2023 llmsg (message ("LARCH_PATH = %s", eval));
2027 llmsg (message ("LARCH_PATH = <not set> (default = %s)",
2028 cstring_fromChars (DEFAULT_LARCHPATH)));
2031 llmsglit (" --- path used to find larch initialization files and LSL traits");
2033 eval = context_getLCLImportDir ();
2034 def = osd_getEnvironmentVariable (cstring_makeLiteralTemp (LCLIMPORTDIR));
2036 if (cstring_isDefined (def) ||
2037 !cstring_equal (eval, cstring_fromChars (DEFAULT_LCLIMPORTDIR)))
2039 llmsg (message ("%q = %s", cstring_makeLiteral (LCLIMPORTDIR), eval));
2043 llmsg (message ("%s = <not set, default: %s>", cstring_makeLiteralTemp (LCLIMPORTDIR),
2044 cstring_makeLiteralTemp (DEFAULT_LCLIMPORTDIR)));
2047 llmsglit (" --- directory containing lcl standard library files "
2048 "(import with < ... >)");;
2051 ("include path = %q (set by environment variable %s and -I flags)",
2052 cppReader_getIncludePath (), INCLUDEPATH_VAR));
2054 llmsglit (" --- path used to find #include'd files");
2057 ("systemdirs = %s (set by -systemdirs or environment variable %s)", /*@i413223@*/
2058 context_getString (FLG_SYSTEMDIRS),
2061 llmsglit (" --- if file is found on this path, it is treated as a system file for error reporting");
2070 fprintf (stderr, "*** Interrupt\n");
2071 llexit (LLINTERRUPT);
2076 /* Cheat when there are parse errors */
2079 fprintf (stderr, "*** Segmentation Violation\n");
2081 /* Don't catch it if fileloc_unparse causes a signal */
2082 (void) signal (SIGSEGV, NULL);
2084 loc = fileloc_unparse (g_currentloc);
2086 fprintf (stderr, "*** Location (not trusted): %s\n",
2087 cstring_toCharsSafe (loc));
2090 fprintf (stderr, "*** Please report bug to %s\n", LCLINT_MAINTAINER);
2094 fprintf (stderr, "*** Signal: %d\n", i);
2096 fprintf (stderr, "*** Location (not trusted): %s\n",
2097 cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
2100 fprintf (stderr, "*** Please report bug to %s ***\n", LCLINT_MAINTAINER);
2108 static bool doneCleanup = FALSE;
2110 /* make sure this is only called once! */
2112 if (doneCleanup) return;
2117 ** Close all open files
2118 ** (There should only be open files, if we exited after a fatal error.)
2121 fileTable_closeAll (context_fileTable ());
2123 if (context_getFlag (FLG_KEEP))
2125 check (fputs ("Temporary files kept:\n", stderr) != EOF);
2126 fileTable_printTemps (context_fileTable ());
2131 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
2135 llbug (message ("Files unclosed: %d", nfiles));
2138 fileTable_cleanup (context_fileTable ());
2145 ** cleans up temp files (if necessary)
2152 DPRINTF (("llexit: %d", status));
2155 if (status == LLFAILURE)
2163 if (status != LLFAILURE)
2165 context_destroyMod ();
2166 exprNode_destroyMod ();
2169 uentry_destroyMod ();
2170 typeIdSet_destroyMod ();
2173 dmalloc_shutdown ();
2177 exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
2181 loadrc (/*:open:*/ FILE *rcfile, cstringSList *passThroughArgs)
2182 /*@ensures closed rcfile@*/
2184 char *s = mstring_create (MAX_LINE_LENGTH);
2187 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2191 while (reader_readLine (rcfile, s, MAX_LINE_LENGTH) != NULL)
2198 DPRINTF (("Line: %s", s));
2199 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2201 while (*s == ' ' || *s == '\t')
2209 bool escaped = FALSE;
2210 bool quoted = FALSE;
2213 DPRINTF (("Process: %s", s));
2214 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2215 /* comment characters */
2216 if (c == '#' || c == ';' || c == '\n')
2222 if (c == '-' || c == '+')
2229 voptgenerror (FLG_BADFLAG,
2230 message ("Bad flag syntax (+ or - expected, "
2231 "+ is assumed): %s",
2232 cstring_fromChars (s)),
2243 while ((c = *s) != '\0')
2244 { /* remember to handle spaces and quotes in -D and -U ... */
2270 if (c == ' ' || c == '\t' || c == '\n')
2272 /*@innerbreak@*/ break;
2280 DPRINTF (("Nulling: %c", *s));
2283 if (mstring_isEmpty (thisflag))
2285 llfatalerror (message ("Missing flag: %s",
2286 cstring_fromChars (os)));
2289 DPRINTF (("Flag: %s", thisflag));
2291 opt = identifyFlag (cstring_fromChars (thisflag));
2293 if (flagcode_isSkip (opt))
2297 else if (flagcode_isInvalid (opt))
2299 DPRINTF (("Invalid: %s", thisflag));
2301 if (isMode (cstring_fromChars (thisflag)))
2303 context_setMode (cstring_fromChars (thisflag));
2307 voptgenerror (FLG_BADFLAG,
2308 message ("Unrecognized option: %s",
2309 cstring_fromChars (thisflag)),
2315 context_userSetFlag (opt, set);
2317 if (flagcode_hasArgument (opt))
2319 if (opt == FLG_HELP)
2322 voptgenerror (FLG_BADFLAG,
2323 message ("Cannot use help in rc files"),
2326 else if (flagcode_isPassThrough (opt)) /* -D or -U */
2328 cstring arg = cstring_fromCharsNew (thisflag);
2329 cstring_markOwned (arg);
2330 *passThroughArgs = cstringSList_add (*passThroughArgs, arg);
2331 DPRINTF (("Pass through: %s",
2332 cstringSList_unparse (*passThroughArgs)));
2334 else if (opt == FLG_INCLUDEPATH
2335 || opt == FLG_SPECPATH)
2337 cstring dir = cstring_suffix (cstring_fromChars (thisflag), 1); /* skip over I/S */
2341 case FLG_INCLUDEPATH:
2342 cppAddIncludeDir (dir);
2343 /*@switchbreak@*/ break;
2346 g_localSpecPath = cstring_toCharsSafe
2347 (message ("%s:%s", cstring_fromChars (g_localSpecPath), dir));
2349 /*@switchbreak@*/ break;
2353 else if (flagcode_hasString (opt)
2354 || flagcode_hasValue (opt)
2355 || opt == FLG_INIT || opt == FLG_OPTF)
2357 cstring extra = cstring_undefined;
2362 rest = mstring_copy (s);
2363 DPRINTF (("Here: rest = %s", rest));
2367 while ((rchar = *rest) != '\0'
2368 && (isspace ((int) rchar)))
2374 DPRINTF (("Yo: %s", rest));
2376 while ((rchar = *rest) != '\0'
2377 && !isspace ((int) rchar))
2379 extra = cstring_appendChar (extra, rchar);
2384 DPRINTF (("Yo: %s", extra));
2387 if (cstring_isUndefined (extra))
2393 ("Flag %s must be followed by an argument",
2394 flagcode_unparse (opt)),
2401 DPRINTF (("Here we are: %s", extra));
2403 if (flagcode_hasValue (opt))
2405 DPRINTF (("Set value flag: %s", extra));
2406 setValueFlag (opt, extra);
2407 cstring_free (extra);
2409 else if (opt == FLG_OPTF)
2411 FILE *innerf = fileTable_openFile (context_fileTable (), extra, "r");
2412 cstring_markOwned (extra);
2416 fileloc fc = g_currentloc;
2417 g_currentloc = fileloc_createRc (extra);
2418 loadrc (innerf, passThroughArgs);
2419 fileloc_reallyFree (g_currentloc);
2427 message ("Options file not found: %s",
2432 else if (opt == FLG_INIT)
2435 llassert (inputStream_isUndefined (initFile));
2437 initFile = inputStream_create
2439 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
2442 cstring_free (extra);
2445 else if (flagcode_hasString (opt))
2447 if (cstring_firstChar (extra) == '"')
2449 if (cstring_lastChar (extra) == '"')
2451 char *extras = cstring_toCharsSafe (extra);
2453 llassert (extras[strlen(extras) - 1] == '"');
2454 extras[strlen(extras) - 1] = '\0';
2455 extra = cstring_fromChars (extras + 1);
2456 DPRINTF (("Remove quites: %s", extra));
2462 message ("Unmatched \" in option string: %s",
2468 setStringFlag (opt, extra);
2472 cstring_free (extra);
2485 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2486 while ((c == ' ') || (c == '\t'))
2492 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2496 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2498 check (fileTable_closeFile (context_fileTable (), rcfile));
2501 static fileIdList preprocessFiles (fileIdList fl, bool xhfiles)
2502 /*@modifies fileSystem@*/
2504 bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
2505 int skip = (fileIdList_size (fl) / 5);
2506 int filesprocessed = 0;
2507 fileIdList dfiles = fileIdList_create ();
2509 fileloc_free (g_currentloc);
2510 g_currentloc = fileloc_createBuiltin ();
2512 fileIdList_elements (fl, fid)
2514 cstring ppfname = fileName (fid);
2520 if (osd_findOnLarchPath (ppfname, &fpath) == OSD_FILEFOUND)
2522 if (cstring_equal (ppfname, fpath))
2528 DPRINTF (("xh file: %s", fpath));
2530 fileTable_setFilePath (context_fileTable (), fid, fpath);
2535 lldiagmsg (message ("Cannot find .xh file on LARCH_PATH: %s", ppfname));
2536 lldiagmsg (cstring_makeLiteral (" Check LARCH_PATH environment variable."));
2537 ppfname = cstring_undefined;
2542 if (!(osd_fileIsReadable (ppfname)))
2544 lldiagmsg (message ("Cannot open file: %s", ppfname));
2545 ppfname = cstring_undefined;
2549 if (cstring_isDefined (ppfname))
2551 fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
2553 llassert (cstring_isNonEmpty (ppfname));
2557 if ((filesprocessed % skip) == 0)
2559 if (filesprocessed == 0) {
2560 fprintf (stderr, " ");
2563 fprintf (stderr, ".");
2566 (void) fflush (stderr);
2571 if (cppProcess (ppfname, fileName (dfile)) != 0)
2573 llfatalerror (message ("Preprocessing error for file: %s",
2574 rootFileName (fid)));
2577 fileIdList_add (dfiles, dfile);
2579 } end_fileIdList_elements;
2584 /* This should be in an lclUtils.c file... */
2586 char *specFullName (char *specfile, /*@out@*/ char **inpath)
2588 /* extract the path and the specname associated with the given file */
2589 char *specname = (char *) dmalloc (sizeof (*specname)
2590 * (strlen (specfile) + 9));
2591 char *ospecname = specname;
2592 char *path = (char *) dmalloc (sizeof (*path) * (strlen (specfile)));
2596 /* initialized path to empty string or may have accidental garbage */
2599 /*@-mayaliasunique@*/
2600 strcpy (specname, specfile);
2601 /*@=mayaliasunique@*/
2603 /* trim off pathnames in specfile */
2604 size = strlen (specname);
2606 for (i = size_toInt (size) - 1; i >= 0; i--)
2608 if (specname[i] == CONNECTCHAR)
2610 /* strcpy (specname, (char *)specname+i+1); */
2611 for (j = 0; j <= i; j++) /* include '/' */
2613 path[j] = specname[j];
2623 ** also remove .lcl file extension, assume it's the last extension
2627 size = strlen (specname);
2629 for (i = size_toInt (size) - 1; i >= 0; i--)
2631 if (specname[i] == '.')
2641 ** If specname no longer points to the original char,
2642 ** we need to allocate a new pointer and copy the string.
2645 if (specname != ospecname) {
2646 char *rspecname = (char *) dmalloc (sizeof (*rspecname) * (strlen (specname) + 1));
2647 strcpy (rspecname, specname); /* evs 2000-05-16: Bug: was ospecname! */