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"
73 # include "fileIdList.h"
75 # include "cgrammar.h"
80 extern /*@external@*/ int yydebug;
82 static void printMail (void);
83 static void printMaintainer (void);
84 static void printReferences (void);
85 static void printFlags (void);
86 static void printAnnotations (void);
87 static void printParseErrors (void);
88 static void printComments (void);
89 static void describePrefixCodes (void);
90 static void cleanupFiles (void);
91 static void showHelp (void);
92 static void interrupt (int p_i);
94 static void loadrc (FILE *p_rcfile, cstringSList *p_passThroughArgs)
95 /*@ensures closed p_rcfile@*/ ;
97 static void describeVars (void);
98 static bool specialFlagsHelp (char *p_next);
99 static bool hasShownHerald = FALSE;
100 static char *specFullName (char *p_specfile, /*@out@*/ char **p_inpath)
101 /*@modifies *p_inpath@*/ ;
103 static bool anylcl = FALSE;
104 static clock_t inittime;
106 static /*@only@*/ /*@null@*/ inputStream initFile = inputStream_undefined;
108 static fileIdList preprocessFiles (fileIdList, bool)
109 /*@modifies fileSystem@*/ ;
114 void lslCleanup (void)
115 /*@globals killed g_symtab@*/
116 /*@modifies internalState, g_symtab@*/
119 ** Cleanup all the LCL/LSL.
122 static bool didCleanup = FALSE;
124 llassert (!didCleanup);
129 lsymbol_destroyMod ();
130 LCLSynTableCleanup ();
131 LCLTokenTableCleanup ();
132 LCLScanLineCleanup ();
135 /* clean up LSL parsing */
138 ltokenTableCleanup ();
142 symtable_free (g_symtab);
148 /*@globals undef g_symtab; @*/
149 /*@modifies g_symtab, internalState, fileSystem; @*/
152 ** Open init file provided by user, or use the default LCL init file
155 cstring larchpath = context_getLarchPath ();
156 inputStream LSLinitFile = inputStream_undefined;
160 if (inputStream_isUndefined (initFile))
162 initFile = inputStream_create (cstring_makeLiteral (INITFILENAME),
163 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
166 if (!inputStream_getPath (larchpath, initFile))
168 lldiagmsg (message ("Continuing without LCL init file: %s",
169 inputStream_fileName (initFile)));
173 if (!inputStream_open (initFile))
175 lldiagmsg (message ("Continuing without LCL init file: %s",
176 inputStream_fileName (initFile)));
182 if (!inputStream_open (initFile))
184 lldiagmsg (message ("Continuing without LCL init file: %s",
185 inputStream_fileName (initFile)));
189 /* Initialize checker */
197 LCLTokenTableInit ();
209 /* need this to initialize LCL checker */
211 llassert (inputStream_isDefined (initFile));
212 if (inputStream_isOpen (initFile))
216 LCLScanReset (initFile);
217 LCLProcessInitFileInit ();
218 LCLProcessInitFileReset ();
221 LCLProcessInitFile ();
222 LCLProcessInitFileCleanup ();
225 check (inputStream_close (initFile));
228 /* Initialize LSL init files, for parsing LSL signatures from LSL */
230 LSLinitFile = inputStream_create (cstring_makeLiteral ("lslinit.lsi"),
231 cstring_makeLiteralTemp (".lsi"),
234 if (!inputStream_getPath (larchpath, LSLinitFile))
236 lldiagmsg (message ("Continuing without LSL init file: %s",
237 inputStream_fileName (LSLinitFile)));
241 if (!inputStream_open (LSLinitFile))
243 lldiagmsg (message ("Continuing without LSL init file: %s",
244 inputStream_fileName (LSLinitFile)));
260 if (inputStream_isOpen (LSLinitFile))
263 LSLScanReset (LSLinitFile);
264 LSLProcessInitFileInit ();
266 LSLProcessInitFile ();
268 check (inputStream_close (LSLinitFile));
271 inputStream_free (LSLinitFile);
276 (cstring_makeLiteral ("LSL init file error. Attempting to continue."));
280 g_symtab = symtable_new ();
283 ** sort_init must come after symtab has been initialized
292 ** Equivalent to importing old spec_csupport.lcl
293 ** define immutable LCL type "bool" and bool constants TRUE and FALSE
294 ** and initialized them to be equal to LSL's "true" and "false".
296 ** Reads in CTrait.syms (derived from CTrait.lsl) on LARCH_PATH.
300 LCLReportEolTokens (FALSE);
304 lslProcess (fileIdList lclfiles)
305 /*@globals undef g_currentSpec, undef g_currentSpecName, g_currentloc,
306 undef killed g_symtab; @*/
307 /*@modifies g_currentSpec, g_currentSpecName, g_currentloc, internalState, fileSystem; @*/
310 bool parser_status = FALSE;
311 bool overallStatus = FALSE;
315 context_resetSpecLines ();
317 fileIdList_elements (lclfiles, fid)
319 cstring actualName = cstring_undefined;
320 cstring fname = fileName (fid);
322 if (osd_getPath (cstring_fromChars (g_localSpecPath),
323 fname, &actualName) == OSD_FILENOTFOUND)
325 if (mstring_equal (g_localSpecPath, "."))
327 lldiagmsg (message ("Spec file not found: %q", osd_outputPath (fname)));
331 lldiagmsg (message ("Spec file not found: %q (on %s)",
332 osd_outputPath (fname),
333 cstring_fromChars (g_localSpecPath)));
338 inputStream specFile;
340 char *namePtr = actualName;
342 while (*namePtr == '.' && *(namePtr + 1) == CONNECTCHAR)
346 /*@noaccess cstring@*/
348 g_currentSpec = cstring_fromCharsNew (namePtr);
350 specFile = inputStream_create (cstring_copy (g_currentSpec),
351 LCL_EXTENSION, TRUE);
353 llassert (inputStream_isDefined (specFile));
355 g_currentSpecName = specFullName
356 (cstring_toCharsSafe (g_currentSpec),
361 if (context_getFlag (FLG_SHOWSCAN))
363 lldiagmsg (message ("< reading spec %s >", g_currentSpec));
366 /* Open source file */
368 if (!inputStream_open (specFile))
370 lldiagmsg (message ("Cannot open file: %q",
371 osd_outputPath (inputStream_fileName (specFile))));
372 inputStream_free (specFile);
376 scopeInfo dummy_scope = (scopeInfo) dmalloc (sizeof (*dummy_scope));
377 dummy_scope->kind = SPE_INVALID;
380 LCLScanReset (specFile);
383 ** Minor hacks to allow more than one LCL file to
384 ** be scanned, while keeping initializations
387 symtable_enterScope (g_symtab, dummy_scope);
388 resetImports (cstring_fromChars (g_currentSpecName));
389 context_enterLCLfile ();
390 (void) lclHadNewError ();
392 parser_status = (ylparse () != 0);
393 context_exitLCLfile ();
395 overallStatus = parser_status || lclHadNewError ();
397 if (context_getFlag (FLG_DOLCS))
401 outputLCSFile (path, "%FAILED Output from ",
406 outputLCSFile (path, "%PASSED Output from ",
411 (void) inputStream_close (specFile);
412 inputStream_free (specFile);
414 symtable_exitScope (g_symtab);
417 cstring_free (actualName);
418 } end_fileIdList_elements;
420 /* Can cleanup lsl stuff right away */
424 g_currentSpec = cstring_undefined;
425 g_currentSpecName = NULL;
429 static void handlePassThroughFlag (char *arg)
432 char *quotechar = strchr (curarg, '\"');
435 char *freearg = NULL;
437 while (quotechar != NULL)
439 if (*(quotechar - 1) == '\\')
441 char *tp = quotechar - 2;
452 curarg = quotechar + 1;
453 quotechar = strchr (curarg, '\"');
458 llassert (quotechar != NULL);
460 offset = (quotechar - arg) + 2;
464 arg = cstring_toCharsSafe
465 (message ("%s\"\'%s",
466 cstring_fromChars (arg),
467 cstring_fromChars (quotechar + 1)));
473 arg = cstring_toCharsSafe
474 (message ("%s\'\"%s",
475 cstring_fromChars (arg),
476 cstring_fromChars (quotechar + 1)));
481 curarg = arg + offset;
482 quotechar = strchr (curarg, '\"');
488 voptgenerror (FLG_BADFLAG,
489 message ("Unclosed quote in flag: %s",
490 cstring_fromChars (arg)),
499 ** If the value is surrounded by single quotes ('), remove
500 ** them. This is an artifact of UNIX command line?
503 def = osd_fixDefine (cstring_fromChars (arg + 1));
504 DPRINTF (("Do define: %s", def));
506 DPRINTF (("After define"));
508 } else if (arg[0] == 'U') {
509 cppDoUndefine (cstring_fromChars (arg + 1));
518 void showHerald (void)
520 if (hasShownHerald || context_getFlag (FLG_QUIET)) return;
524 fprintf (g_msgstream, "%s\n\n", LCL_VERSION);
525 hasShownHerald = TRUE;
530 static cstring findLarchPathFile (/*@temp@*/ cstring s)
535 status = osd_getPath (context_getLarchPath (), s, &pathName);
537 if (status == OSD_FILEFOUND)
541 else if (status == OSD_FILENOTFOUND)
544 lldiagmsg (message ("Cannot find file on LARCHPATH: %s", s));
546 else if (status == OSD_PATHTOOLONG)
548 /* Directory and filename are too long. Report error. */
549 llbuglit ("soure_getPath: Filename plus directory from search path too long");
556 return cstring_undefined;
559 static void addLarchPathFile (fileIdList files, /*@temp@*/ cstring s)
561 cstring pathName = findLarchPathFile (s);
563 if (cstring_isDefined (pathName))
565 if (fileTable_exists (context_fileTable (), pathName))
568 lldiagmsg (message ("File listed multiple times: %s", pathName));
569 cstring_free (pathName);
573 fileIdList_add (files, fileTable_addFileOnly (context_fileTable (), pathName));
578 static void addFile (fileIdList files, /*@only@*/ cstring s)
580 if (fileTable_exists (context_fileTable (), s))
583 lldiagmsg (message ("File listed multiple times: %s", s));
588 fileIdList_add (files, fileTable_addFileOnly (context_fileTable (), s));
592 static void addXHFile (fileIdList files, /*@temp@*/ cstring s)
594 cstring pathName = findLarchPathFile (s);
596 if (cstring_isDefined (pathName))
598 if (fileTable_exists (context_fileTable (), pathName))
601 lldiagmsg (message ("File listed multiple times: %s", s));
605 fileIdList_add (files, fileTable_addXHFile (context_fileTable (), pathName));
609 cstring_free (pathName);
613 ** Disable MSVC++ warning about return value. Methinks humbly lclint control
614 ** comments are a mite more legible.
618 # pragma warning (disable:4035)
621 int main (int argc, char *argv[])
623 /*@globals killed undef g_currentloc,
627 /*@modifies g_currentloc, fileSystem,
631 /*@globals killed undef g_currentloc,
632 killed undef initFile,
633 killed g_localSpecPath,
634 killed undef g_currentSpec,
635 killed undef g_currentSpecName,
639 /*@modifies g_currentloc, initFile,
640 g_localSpecPath, g_currentSpec, g_currentSpecName, fileSystem,
645 bool first_time = TRUE;
646 bool showhelp = FALSE;
649 inputStream sourceFile = inputStream_undefined;
651 fileIdList dercfiles;
652 cstringSList fl = cstringSList_undefined;
653 cstringSList passThroughArgs = cstringSList_undefined;
654 fileIdList cfiles, xfiles, lclfiles, mtfiles;
655 clock_t before, lcltime, libtime, pptime, cptime, rstime;
659 _wildcard (&argc, &argv);
662 g_msgstream = stdout;
664 (void) signal (SIGINT, interrupt);
665 (void) signal (SIGSEGV, interrupt);
667 cfiles = fileIdList_create ();
668 xfiles = fileIdList_create ();
669 lclfiles = fileIdList_create ();
670 mtfiles = fileIdList_create ();
673 clabstract_initMod ();
674 typeIdSet_initMod ();
675 cppReader_initMod ();
680 g_currentloc = fileloc_createBuiltin ();
685 context_setInCommandLine ();
697 ** Add include directories from environment.
701 cstring incval = cstring_copy (osd_getEnvironmentVariable (INCLUDEPATH_VAR));
702 cstring oincval = incval;
704 if (cstring_isDefined (incval))
707 ** Each directory on the include path is a system include directory.
710 DPRINTF (("include: %s", incval));
711 context_setString (FLG_SYSTEMDIRS, cstring_copy (incval));
713 while (cstring_isDefined (incval))
716 char *nextsep = strchr (incval, PATH_SEPARATOR);
722 dir = cstring_copy (incval);
724 if (cstring_length (dir) == 0
725 || !isalpha ((int) cstring_firstChar (dir)))
728 ** win32 environment values can have special values,
734 cppAddIncludeDir (dir);
737 *nextsep = PATH_SEPARATOR;
738 incval = cstring_fromChars (nextsep + 1);
746 /*@noaccess cstring@*/
749 else /* 2001-09-09: herbert */
751 /* Put C_INCLUDE_PATH directories in sysdirs */
752 cstring cincval = osd_getEnvironmentVariable (cstring_makeLiteralTemp ("C_INCLUDE_PATH"));
753 if (cstring_isDefined (cincval))
755 context_setString (FLG_SYSTEMDIRS, cstring_copy (cincval));
760 cstring_free (oincval);
764 ** check RCFILE for default flags
768 cstring home = osd_getHomeDir ();
771 bool defaultf = TRUE;
774 for (i = 1; i < argc; i++)
779 if (*thisarg == '-' || *thisarg == '+')
783 if (mstring_equal (thisarg, "nof"))
787 else if (mstring_equal (thisarg, "f"))
793 rcfile = fileTable_openFile (context_fileTable (), cstring_fromChars (fname), "r");
797 fileloc oloc = g_currentloc;
799 g_currentloc = fileloc_createRc (cstring_fromChars (fname));
800 loadrc (rcfile, &passThroughArgs);
801 fileloc_reallyFree (g_currentloc);
807 lldiagmsg (message ("Options file not found: %s",
808 cstring_fromChars (fname)));
813 (cstring_makeLiteral ("Flag f to select options file "
814 "requires an argument"));
818 ; /* wait to process later */
825 if (!cstring_isEmpty (home)) {
826 fname = cstring_toCharsSafe (message ("%s%h%s", home, CONNECTCHAR,
827 cstring_fromChars (RCFILE)));
828 mstring_markFree (fname);
834 if (!nof && defaultf)
836 if (!mstring_isEmpty (fname)) {
837 rcfile = fileTable_openFile (context_fileTable (), cstring_fromChars (fname), "r");
841 fileloc oloc = g_currentloc;
843 g_currentloc = fileloc_createRc (cstring_fromChars (fname));
844 loadrc (rcfile, &passThroughArgs);
845 fileloc_reallyFree (g_currentloc);
850 # if defined(MSDOS) || defined(OS2)
851 fname = cstring_toCharsSafe (message ("%s",
852 cstring_fromChars (RCFILE)));
854 fname = cstring_toCharsSafe (message ("./%s",
855 cstring_fromChars (RCFILE)));
858 rcfile = fileTable_openFile (context_fileTable (), cstring_fromChars (fname), "r");
862 fileloc oloc = g_currentloc;
864 g_currentloc = fileloc_createRc (cstring_fromChars (fname));
865 loadrc (rcfile, &passThroughArgs);
866 fileloc_reallyFree (g_currentloc);
876 for (i = 1; i < argc; i++)
892 if (*thisarg == '-' || *thisarg == '+')
894 thisarg++; /* skip '-' */
896 if (mstring_equal (thisarg, "modes"))
898 llmsg (describeModes ());
900 else if (mstring_equal (thisarg, "vars")
901 || mstring_equal (thisarg, "env"))
905 else if (mstring_equal (thisarg, "annotations"))
909 else if (mstring_equal (thisarg, "parseerrors"))
913 else if (mstring_equal (thisarg, "comments"))
917 else if (mstring_equal (thisarg, "prefixcodes"))
919 describePrefixCodes ();
921 else if (mstring_equal (thisarg, "references")
922 || mstring_equal (thisarg, "refs"))
926 else if (mstring_equal (thisarg, "mail"))
930 else if (mstring_equal (thisarg, "maintainer")
931 || mstring_equal (thisarg, "version"))
935 else if (mstring_equal (thisarg, "flags"))
939 char *next = argv[i + 1];
941 if (specialFlagsHelp (next))
947 flagkind k = identifyCategory (cstring_fromChars (next));
963 cstring s = describeFlag (cstring_fromChars (thisarg));
965 if (cstring_isDefined (s))
973 if (*thisarg == '-' || *thisarg == '+')
975 bool set = (*thisarg == '+');
978 thisarg++; /* skip '-' */
979 flagname = cstring_fromChars (thisarg);
981 DPRINTF (("Flag: %s", flagname));
982 opt = identifyFlag (flagname);
983 DPRINTF (("Flag: %s", flagcode_unparse (opt)));
985 if (flagcode_isSkip (opt))
987 DPRINTF (("Skipping!"));
989 else if (flagcode_isInvalid (opt))
991 DPRINTF (("Invalid: %s", flagname));
993 if (isMode (flagname))
995 context_setMode (flagname);
999 DPRINTF (("Error!"));
1000 voptgenerror (FLG_BADFLAG,
1001 message ("Unrecognized option: %s",
1002 cstring_fromChars (thisarg)),
1008 context_userSetFlag (opt, set);
1010 if (flagcode_hasArgument (opt))
1012 if (opt == FLG_HELP)
1016 else if (flagcode_isPassThrough (opt)) /* -D or -U */
1018 passThroughArgs = cstringSList_add
1019 (passThroughArgs, cstring_fromChars (thisarg));
1021 else if (flagcode_hasValue (opt))
1025 setValueFlag (opt, cstring_fromChars (argv[i]));
1031 ("Flag %s must be followed by a number",
1032 flagcode_unparse (opt)));
1035 else if (opt == FLG_INCLUDEPATH || opt == FLG_SPECPATH)
1037 cstring dir = cstring_suffix (cstring_fromChars (thisarg), 1); /* skip over I */
1041 case FLG_INCLUDEPATH:
1042 cppAddIncludeDir (dir);
1043 /*@switchbreak@*/ break;
1046 g_localSpecPath = cstring_toCharsSafe
1048 cstring_fromChars (g_localSpecPath),
1052 /*@switchbreak@*/ break;
1056 else if (flagcode_hasString (opt)
1057 || opt == FLG_INIT || opt == FLG_OPTF)
1061 cstring arg = cstring_fromChars (argv[i]);
1063 if (opt == FLG_OPTF)
1065 ; /* -f already processed */
1067 else if (opt == FLG_INIT)
1070 initFile = inputStream_create
1072 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
1079 DPRINTF (("String flag: %s / %s",
1080 flagcode_unparse (opt), arg));
1081 if (opt == FLG_MTSFILE)
1084 ** arg identifies mts files
1086 cstring tmp = message ("%s%s", arg, MTS_EXTENSION);
1087 addLarchPathFile (mtfiles, tmp);
1089 tmp = message ("%s%s", arg, XH_EXTENSION);
1090 addXHFile (xfiles, tmp);
1095 setStringFlag (opt, arg);
1103 ("Flag %s must be followed by a string",
1104 flagcode_unparse (opt)));
1114 else /* its a filename */
1116 DPRINTF (("Adding filename: %s", thisarg));
1117 fl = cstringSList_add (fl, cstring_fromChars (thisarg));
1125 ** create lists of C and LCL files
1128 cstringSList_elements (fl, current)
1130 cstring ext = fileLib_getExtension (current);
1132 if (cstring_isUndefined (ext))
1134 /* no extension --- both C and LCL with default extensions */
1136 addFile (cfiles, message ("%s%s", current, C_EXTENSION));
1137 addFile (lclfiles, message ("%s%s", current, LCL_EXTENSION));
1139 else if (cstring_equal (ext, XH_EXTENSION))
1141 addXHFile (xfiles, current);
1143 else if (cstring_equal (ext, PP_EXTENSION))
1145 if (!context_getFlag (FLG_NOPP))
1148 (FLG_FILEEXTENSIONS,
1149 message ("File extension %s used without +nopp flag (will be processed as C source code): %s",
1154 addFile (cfiles, cstring_copy (current));
1156 else if (cstring_equal (ext, LCL_EXTENSION))
1158 addFile (lclfiles, cstring_copy (current));
1160 else if (fileLib_isCExtension (ext))
1162 addFile (cfiles, cstring_copy (current));
1164 else if (cstring_equal (ext, MTS_EXTENSION))
1166 addLarchPathFile (mtfiles, current);
1171 (FLG_FILEEXTENSIONS,
1172 message ("Unrecognized file extension: %s (assuming %s is C source code)",
1176 addFile (cfiles, cstring_copy (current));
1178 } end_cstringSList_elements;
1180 showHerald (); /*@i723 move earlier? */
1188 fprintf (g_msgstream, "\n");
1190 fileIdList_free (cfiles);
1191 fileIdList_free (xfiles);
1192 fileIdList_free (lclfiles);
1201 inittime = clock ();
1203 context_resetErrors ();
1204 context_clearInCommandLine ();
1206 anylcl = !fileIdList_isEmpty (lclfiles);
1208 if (context_doMerge ())
1210 cstring m = context_getMerge ();
1212 if (context_getFlag (FLG_SHOWSCAN))
1214 fprintf (g_msgstream, "< loading %s ", cstring_toCharsSafe (m));
1219 if (context_getFlag (FLG_SHOWSCAN))
1221 fprintf (g_msgstream, " >\n");
1224 if (!usymtab_existsType (context_getBoolName ()))
1226 usymtab_initBool ();
1231 if (!context_getFlag (FLG_NOLIB) && loadStandardState ())
1240 /* setup bool type and constants */
1241 usymtab_initBool ();
1244 fileloc_free (g_currentloc);
1245 g_currentloc = fileloc_createBuiltin ();
1248 ** Read metastate files (must happen before loading libraries)
1251 fileIdList_elements (mtfiles, mtfile)
1253 context_setFileId (mtfile);
1255 if (context_getFlag (FLG_SHOWSCAN))
1257 lldiagmsg (message ("< processing %s >", rootFileName (mtfile)));
1260 mtreader_readFile (cstring_copy (fileName (mtfile)));
1261 } end_fileIdList_elements;
1268 llfatalerror (cstring_makeLiteral ("This version of LCLint does not handle LCL files."));
1270 lslProcess (lclfiles);
1274 usymtab_initGlobalMarker ();
1279 ** call the pre-preprocessor and /lib/cpp to generate appropriate
1284 context_setInCommandLine ();
1286 DPRINTF (("Pass through: %s", cstringSList_unparse (passThroughArgs)));
1288 cstringSList_elements (passThroughArgs, thisarg) {
1289 handlePassThroughFlag (cstring_toCharsSafe (thisarg));
1290 } end_cstringSList_elements;
1292 cstringSList_free (passThroughArgs);
1296 DPRINTF (("Initializing cpp reader!"));
1297 cppReader_initialize ();
1298 cppReader_saveDefinitions ();
1300 context_clearInCommandLine ();
1302 if (!context_getFlag (FLG_NOPP))
1308 if (context_getFlag (FLG_SHOWSCAN))
1310 fprintf (stderr, "< preprocessing");
1315 context_setPreprocessing ();
1316 dercfiles = preprocessFiles (xfiles, TRUE);
1317 tfiles = preprocessFiles (cfiles, FALSE);
1318 dercfiles = fileIdList_append (dercfiles, tfiles);
1319 fileIdList_free (tfiles);
1321 context_clearPreprocessing ();
1323 fileIdList_free (cfiles);
1325 if (context_getFlag (FLG_SHOWSCAN))
1327 fprintf (stderr, " >\n");
1335 dercfiles = fileIdList_append (cfiles, xfiles);
1340 ** now, check all the corresponding C files
1342 ** (for now these are just <file>.c, but after pre-processing
1343 ** will be <tmpprefix>.<file>.c)
1348 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1352 llbug (message ("Files unclosed: %d", nfiles));
1357 DPRINTF (("Initializing..."));
1359 exprNode_initMod ();
1361 DPRINTF (("Okay..."));
1363 fileIdList_elements (dercfiles, fid)
1365 sourceFile = inputStream_create (cstring_copy (fileName (fid)), C_EXTENSION, TRUE);
1366 context_setFileId (fid);
1368 /* Open source file */
1370 if (inputStream_isUndefined (sourceFile) || (!inputStream_open (sourceFile)))
1372 /* previously, this was ignored ?! */
1373 llbug (message ("Could not open temp file: %s", fileName (fid)));
1377 yyin = inputStream_getFile (sourceFile); /*< shared <- only */
1379 llassert (yyin != NULL);
1381 if (context_getFlag (FLG_SHOWSCAN))
1383 lldiagmsg (message ("< checking %q >", osd_outputPath (rootFileName (fid))));
1387 ** Every time, except the first time, through the loop,
1388 ** need to call yyrestart to clean up the parse buffer.
1393 (void) yyrestart (yyin);
1400 DPRINTF (("Entering..."));
1401 context_enterFile ();
1403 context_exitCFile ();
1405 (void) inputStream_close (sourceFile);
1407 } end_fileIdList_elements;
1411 /* process any leftover macros */
1413 context_processAllMacros ();
1415 /* check everything that was specified was defined */
1417 /* don't check if no c files were processed ?
1418 ** is this correct behaviour?
1421 if (context_getFlag (FLG_SHOWSCAN))
1423 lldiagmsg (cstring_makeLiteral ("< global checks >"));
1428 if (context_getLinesProcessed () > 0)
1430 usymtab_allDefined ();
1433 if (context_maybeSet (FLG_TOPUNUSED))
1435 uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main"));
1437 if (uentry_isValid (ue))
1439 uentry_setUsed (ue, fileloc_observeBuiltin ());
1445 if (context_maybeSet (FLG_EXPORTLOCAL))
1447 usymtab_exportLocal ();
1451 if (context_maybeSet (FLG_EXPORTHEADER))
1453 usymtab_exportHeader ();
1456 if (context_getFlag (FLG_SHOWUSES))
1458 usymtab_displayAllUses ();
1461 context_checkSuppressCounts ();
1463 if (context_doDump ())
1465 cstring dump = context_getDump ();
1476 if (context_getFlag (FLG_SHOWSUMMARY))
1483 bool isQuiet = context_getFlag (FLG_QUIET);
1484 cstring specErrors = cstring_undefined;
1486 int nspecErrors = lclNumberErrors ();
1491 if (context_neednl ())
1492 fprintf (g_msgstream, "\n");
1495 if (nspecErrors > 0)
1497 if (nspecErrors == context_getLCLExpect ())
1500 message ("%d spec error%& found, as expected\n ",
1505 if (context_getLCLExpect () > 0)
1508 message ("%d spec error%& found, expected %d\n ",
1510 (int) context_getLCLExpect ());
1514 specErrors = message ("%d spec error%& found\n ",
1522 if (context_getLCLExpect () > 0)
1524 specErrors = message ("No spec errors found, expected %d\n ",
1525 (int) context_getLCLExpect ());
1531 if (context_anyErrors ())
1533 if (context_numErrors () == context_getExpect ())
1536 llmsg (message ("Finished LCLint checking --- "
1537 "%s%d code error%& found, as expected",
1538 specErrors, context_numErrors ()));
1543 if (context_getExpect () > 0)
1547 ("Finished LCLint checking --- "
1548 "%s%d code error%& found, expected %d",
1549 specErrors, context_numErrors (),
1550 (int) context_getExpect ()));
1560 llmsg (message ("Finished LCLint checking --- "
1561 "%s%d code error%& found",
1562 specErrors, context_numErrors ()));
1571 if (context_getExpect () > 0)
1575 ("Finished LCLint checking --- "
1576 "%sno code errors found, expected %d",
1578 (int) context_getExpect ()));
1585 if (context_getLinesProcessed () > 0)
1588 llmsg (message ("Finished LCLint checking --- %sno code errors found",
1595 llmsg (message ("Finished LCLint checking --- %sno code processed",
1602 cstring_free (specErrors);
1605 if (context_getFlag (FLG_STATS))
1607 clock_t ttime = clock () - before;
1608 int specLines = context_getSpecLinesProcessed ();
1614 fprintf (g_msgstream, "%d spec, ", specLines);
1617 # ifndef CLOCKS_PER_SEC
1618 fprintf (g_msgstream, "%d source lines in %ld time steps (steps/sec unknown)\n",
1619 context_getLinesProcessed (),
1622 fprintf (g_msgstream, "%d source lines in %.2f s.\n",
1623 context_getLinesProcessed (),
1624 (double) ttime / CLOCKS_PER_SEC);
1632 if (context_getFlag (FLG_TIMEDIST))
1634 clock_t ttime = clock () - before;
1638 char *msg = (char *) dmalloc (256 * sizeof (*msg));
1643 "Time distribution (percent): initialize %.2f / lcl %.2f / "
1644 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1645 (100.0 * (double) (libtime - before) / ttime),
1646 (100.0 * (double) (lcltime - libtime) / ttime),
1647 (100.0 * (double) (pptime - lcltime) / ttime),
1648 (100.0 * (double) (cptime - pptime) / ttime),
1649 (100.0 * (double) (rstime - cptime) / ttime));
1654 "Time distribution (percent): initialize %.2f / "
1655 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1656 (100.0 * (double) (libtime - before) / ttime),
1657 (100.0 * (double) (pptime - libtime) / ttime),
1658 (100.0 * (double) (cptime - pptime) / ttime),
1659 (100.0 * (double) (rstime - cptime) / ttime));
1662 llgenindentmsgnoloc (cstring_fromCharsO (msg));
1666 llexit (expsuccess ? LLSUCCESS : LLFAILURE);
1667 BADBRANCHRET (LLFAILURE);
1672 ** Reenable return value warnings.
1674 # pragma warning (default:4035)
1682 llmsg (message ("Source files are .c, .h and %s files. If there is no suffix,",
1684 llmsg (message (" LCLint will look for <file>.c and <file>%s.", LCL_EXTENSION));
1686 llmsglit ("Use lclint -help <topic or flag name> for more information");
1688 llmsglit ("Topics:");
1690 llmsglit (" annotations (describes source-code annotations)");
1691 llmsglit (" comments (describes control comments)");
1692 llmsglit (" flags (describes flag categories)");
1693 llmsglit (" flags <category> (describes flags in category)");
1694 llmsglit (" flags all (short description of all flags)");
1695 llmsglit (" flags alpha (list all flags alphabetically)");
1696 llmsglit (" flags full (full description of all flags)");
1697 llmsglit (" mail (information on mailing lists)");
1698 llmsglit (" modes (show mode settings)");
1699 llmsglit (" parseerrors (help on handling parser errors)");
1700 llmsglit (" prefixcodes (character codes in namespace prefixes)");
1701 llmsglit (" references (sources for more information)");
1702 llmsglit (" vars (environment variables)");
1703 llmsglit (" version (information on compilation, maintainer)");
1708 specialFlagsHelp (char *next)
1710 if ((next != NULL) && (*next != '-') && (*next != '+'))
1712 if (mstring_equal (next, "alpha"))
1717 else if (mstring_equal (next, "all"))
1719 printAllFlags (TRUE, FALSE);
1722 else if (mstring_equal (next, "categories")
1723 || mstring_equal (next, "cats"))
1725 listAllCategories ();
1728 else if (mstring_equal (next, "full"))
1730 printAllFlags (FALSE, TRUE);
1745 printParseErrors (void)
1747 llmsglit ("Parse Errors");
1748 llmsglit ("------------");
1750 llmsglit ("LCLint will sometimes encounter a parse error for code that "
1751 "can be parsed with a local compiler. There are a few likely "
1752 "causes for this and a number of techniques that can be used "
1753 "to work around the problem.");
1755 llmsglit ("Compiler extensions --- compilers sometimes extend the C "
1756 "language with compiler-specific keywords and syntax. While "
1757 "it is not advisible to use these, oftentimes one has no choice "
1758 "when the system header files use compiler extensions. ");
1760 llmsglit ("LCLint supports some of the GNU (gcc) compiler extensions, "
1761 "if the +gnuextensions flag is set. You may be able to workaround "
1762 "other compiler extensions by using a pre-processor define. "
1763 "Alternately, you can surround the unparseable code with");
1765 llmsglit (" # ifndef __LCLINT__");
1767 llmsglit (" # endif");
1769 /* evans 2000-12-21 fixed typo reported by Jeroen Ruigrok/Asmodai */
1770 llmsglit ("Missing type definitions --- an undefined type name will usually "
1771 "lead to a parse error. This often occurs when a standard header "
1772 "file defines some type that is not part of the standard library. ");
1773 llmsglit ("By default, LCLint does not process the local files corresponding "
1774 "to standard library headers, but uses a library specification "
1775 "instead so dependencies on local system headers can be detected. "
1776 "If another system header file that does not correspond to a "
1777 "standard library header uses one of these superfluous types, "
1778 "a parse error will result.");
1780 llmsglit ("If the parse error is inside a posix standard header file, the "
1781 "first thing to try is +posixlib. This make LCLint use "
1782 "the posix library specification instead of reading the posix "
1785 llmsglit ("Otherwise, you may need to either manually define the problematic "
1786 "type (e.g., add -Dmlink_t=int to your .lclintrc file) or force "
1787 "lclint to process the header file that defines it. This is done "
1788 "by setting -skipansiheaders or -skipposixheaders before "
1789 "the file that defines the type is #include'd.");
1790 llmsglit ("(See lclint -help "
1791 "skipansiheaders and lclint -help skipposixheaders for a list of "
1792 "standard headers.) For example, if <sys/local.h> uses a type "
1793 "defined by posix header <sys/types.h> but not defined by the "
1794 "posix library, we might do: ");
1796 llmsglit (" /*@-skipposixheaders@*/");
1797 llmsglit (" # include <sys/types.h>");
1798 llmsglit (" /*@=skipposixheaders@*/");
1799 llmsglit (" # include <sys/local.h>");
1801 llmsglit ("to force LCLint to process <sys/types.h>.");
1803 llmsglit ("At last resort, +trytorecover can be used to make LCLint attempt "
1804 "to continue after a parse error. This is usually not successful "
1805 "and the author does not consider assertion failures when +trytorecover "
1806 "is used to be bugs.");
1810 printAnnotations (void)
1812 llmsglit ("Annotations");
1813 llmsglit ("-----------");
1815 llmsglit ("Annotations are semantic comments that document certain "
1816 "assumptions about functions, variables, parameters, and types. ");
1818 llmsglit ("They may be used to indicate where the representation of a "
1819 "user-defined type is hidden, to limit where a global variable may "
1820 "be used or modified, to constrain what a function implementation "
1821 "may do to its parameters, and to express checked assumptions about "
1822 "variables, types, structure fields, function parameters, and "
1823 "function results.");
1825 llmsglit ("Annotations are introduced by \"/*@\". The role of the @ may be "
1826 "played by any printable character, selected using -commentchar <char>.");
1828 llmsglit ("Consult the User's Guide for descriptions of checking associated with each annotation.");
1830 llmsglit ("Globals: (in function declarations)");
1831 llmsglit (" /*@globals <globitem>,+ @*/");
1832 llmsglit (" globitem is an identifier, internalState or fileSystem");
1834 llmsglit ("Modifies: (in function declarations)");
1835 llmsglit (" /*@modifies <moditem>,+ @*/");
1836 llmsglit (" moditem is an lvalue");
1837 llmsglit (" /*@modifies nothing @*/");
1838 llmsglit (" /*@*/ (Abbreviation for no globals and modifies nothing.)");
1840 llmsglit ("Iterators:");
1841 llmsglit (" /*@iter <identifier> (<parameter-type-list>) @*/ - declare an iterator");
1843 llmsglit ("Constants:");
1844 llmsglit (" /*@constant <declaration> @*/ - declares a constant");
1846 llmsglit ("Alternate Types:");
1847 llmsglit (" /*@alt <basic-type>,+ @*/");
1848 llmsglit (" (e.g., int /*@alt char@*/ is a type matching either int or char)");
1850 llmsglit ("Declarator Annotations");
1852 llmsglit ("Type Definitions:");
1853 llmsglit (" /*@abstract@*/ - representation is hidden from clients");
1854 llmsglit (" /*@concrete@*/ - representation is visible to clients");
1855 llmsglit (" /*@immutable@*/ - instances of the type cannot change value");
1856 llmsglit (" /*@mutable@*/ - instances of the type can change value");
1857 llmsglit (" /*@refcounted@*/ - reference counted type");
1859 llmsglit ("Global Variables:");
1860 llmsglit (" /*@unchecked@*/ - weakest checking for global use");
1861 llmsglit (" /*@checkmod@*/ - check modification by not use of global");
1862 llmsglit (" /*@checked@*/ - check use and modification of global");
1863 llmsglit (" /*@checkedstrict@*/ - check use of global strictly");
1865 llmsglit ("Memory Management:");
1866 llmsglit (" /*@dependent@*/ - a reference to externally-owned storage");
1867 llmsglit (" /*@keep@*/ - a parameter that is kept by the called function");
1868 llmsglit (" /*@killref@*/ - a refcounted parameter, killed by the call");
1869 llmsglit (" /*@only@*/ - an unshared reference");
1870 llmsglit (" /*@owned@*/ - owner of storage that may be shared by /*@dependent@*/ references");
1871 llmsglit (" /*@shared@*/ - shared reference that is never deallocated");
1872 llmsglit (" /*@temp@*/ - temporary parameter");
1874 llmsglit ("Aliasing:");
1875 llmsglit (" /*@unique@*/ - may not be aliased by any other visible reference");
1876 llmsglit (" /*@returned@*/ - may be aliased by the return value");
1878 llmsglit ("Exposure:");
1879 llmsglit (" /*@observer@*/ - reference that cannot be modified");
1880 llmsglit (" /*@exposed@*/ - exposed reference to storage in another object");
1882 llmsglit ("Definition State:");
1883 llmsglit (" /*@out@*/ - storage reachable from reference need not be defined");
1884 llmsglit (" /*@in@*/ - all storage reachable from reference must be defined");
1885 llmsglit (" /*@partial@*/ - partially defined, may have undefined fields");
1886 llmsglit (" /*@reldef@*/ - relax definition checking");
1888 llmsglit ("Global State: (for globals lists, no /*@, since list is already in /*@\'s)");
1889 llmsglit (" undef - variable is undefined before the call");
1890 llmsglit (" killed - variable is undefined after the call");
1892 llmsglit ("Null State:");
1893 llmsglit (" /*@null@*/ - possibly null pointer");
1894 llmsglit (" /*@notnull@*/ - non-null pointer");
1895 llmsglit (" /*@relnull@*/ - relax null checking");
1897 llmsglit ("Null Predicates:");
1898 llmsglit (" /*@truenull@*/ - if result is TRUE, first parameter is NULL");
1899 llmsglit (" /*@falsenull@*/ - if result is TRUE, first parameter is not NULL");
1901 llmsglit ("Execution:");
1902 llmsglit (" /*@exits@*/ - function never returns");
1903 llmsglit (" /*@mayexit@*/ - function may or may not return");
1904 llmsglit (" /*@trueexit@*/ - function does not return if first parameter is TRUE");
1905 llmsglit (" /*@falseexit@*/ - function does not return if first parameter if FALSE");
1906 llmsglit (" /*@neverexit@*/ - function always returns");
1908 llmsglit ("Side-Effects:");
1909 llmsglit (" /*@sef@*/ - corresponding actual parameter has no side effects");
1911 llmsglit ("Declaration:");
1912 llmsglit (" /*@unused@*/ - need not be used (no unused errors reported)");
1913 llmsglit (" /*@external@*/ - defined externally (no undefined error reported)");
1916 llmsglit (" /*@fallthrough@*/ - fall-through case");
1918 llmsglit ("Break:");
1919 llmsglit (" /*@innerbreak@*/ - break is breaking an inner loop or switch");
1920 llmsglit (" /*@loopbreak@*/ - break is breaking a loop");
1921 llmsglit (" /*@switchbreak@*/ - break is breaking a switch");
1922 llmsglit (" /*@innercontinue@*/ - continue is continuing an inner loop");
1924 llmsglit ("Unreachable Code:");
1925 llmsglit (" /*@notreached@*/ - statement may be unreachable.");
1927 llmsglit ("Special Functions:");
1928 llmsglit (" /*@printflike@*/ - check variable arguments like printf");
1929 llmsglit (" /*@scanflike@*/ - check variable arguments like scanf");
1933 printComments (void)
1935 llmsglit ("Control Comments");
1936 llmsglit ("----------------");
1938 llmsglit ("Setting Flags");
1940 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.");
1942 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,");
1943 llmsglit (" /*@+boolint -modifies =showfunc@*/");
1944 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).");
1946 llmsglit ("Error Suppression");
1948 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.");
1950 llmsglit ("/*@ignore@*/ ... /*@end@*/");
1952 (cstring_makeLiteral
1953 ("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."));
1954 llmsglit ("/*@i@*/");
1956 (cstring_makeLiteral
1957 ("No errors will be reported from an /*@i@*/ comment to the end of the line."));
1958 llmsglit ("/*@i<n>@*/");
1960 (cstring_makeLiteral
1961 ("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."));
1962 llmsglit ("/*@t@*/, /*@t<n>@*/");
1964 (cstring_makeLiteral
1965 ("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."));
1967 llmsglit ("Type Access");
1969 llmsglit ("/*@access <type>@*/");
1970 llmsglit (" Allows the following code to access the representation of <type>");
1971 llmsglit ("/*@noaccess <type>@*/");
1972 llmsglit (" Hides the representation of <type>");
1974 llmsglit ("Macro Expansion");
1976 llmsglit ("/*@notfunction@*/");
1978 (cstring_makeLiteral
1979 ("Indicates that the next macro definition is not intended to be a "
1980 "function, and should be expanded in line instead of checked as a "
1981 "macro function definition."));
1988 llmsglit ("Flag Categories");
1989 llmsglit ("---------------");
1990 listAllCategories ();
1991 llmsglit ("\nTo see the flags in a flag category, do\n lclint -help flags <category>");
1992 llmsglit ("To see a list of all flags in alphabetical order, do\n lclint -help flags alpha");
1993 llmsglit ("To see a full description of all flags, do\n lclint -help flags full");
1997 printMaintainer (void)
1999 llmsg (message ("Maintainer: %s", cstring_makeLiteralTemp (LCLINT_MAINTAINER)));
2000 llmsglit (LCL_COMPILE);
2006 llmsglit ("Mailing Lists");
2007 llmsglit ("-------------");
2009 llmsglit ("There are two mailing lists associated with LCLint: ");
2011 llmsglit (" lclint-announce@virginia.edu");
2013 llmsglit (" Reserved for announcements of new releases and bug fixes.");
2014 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
2015 llmsglit (" subscribe lclint-announce");
2017 llmsglit (" lclint-interest@virginia.edu");
2019 llmsglit (" Informal discussions on the use and development of lclint.");
2020 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
2021 llmsglit (" subscribe lclint-interest");
2025 printReferences (void)
2027 llmsglit ("References");
2028 llmsglit ("----------");
2030 llmsglit ("The LCLint web site is http://lclint.cs.virginia.edu");
2032 llmsglit ("Technical papers relating to LCLint include:");
2034 llmsglit (" David Evans. \"Static Detection of Dynamic Memory Errors\".");
2035 llmsglit (" SIGPLAN Conference on Programming Language Design and ");
2036 llmsglit (" Implementation (PLDI '96), Philadelphia, PA, May 1996.");
2038 llmsglit (" David Evans, John Guttag, Jim Horning and Yang Meng Tan. ");
2039 llmsglit (" \"LCLint: A Tool for Using Specifications to Check Code\".");
2040 llmsglit (" SIGSOFT Symposium on the Foundations of Software Engineering,");
2041 llmsglit (" December 1994.");
2043 llmsglit ("A general book on Larch is:");
2045 llmsglit (" Guttag, John V., Horning, James J., (with Garland, S. J., Jones, ");
2046 llmsglit (" K. D., Modet, A., and Wing, J. M.), \"Larch: Languages and Tools ");
2047 llmsglit (" for Formal Specification\", Springer-Verlag, 1993.");
2051 describePrefixCodes (void)
2053 llmsglit ("Prefix Codes");
2054 llmsglit ("------------");
2056 llmsglit ("These characters have special meaning in name prefixes:");
2058 llmsg (message (" %h Any uppercase letter [A-Z]", PFX_UPPERCASE));
2059 llmsg (message (" %h Any lowercase letter [a-z]", PFX_LOWERCASE));
2060 llmsg (message (" %h Any character (valid in a C identifier)", PFX_ANY));
2061 llmsg (message (" %h Any digit [0-9]", PFX_DIGIT));
2062 llmsg (message (" %h Any non-uppercase letter [a-z0-9_]", PFX_NOTUPPER));
2063 llmsg (message (" %h Any non-lowercase letter [A-Z0-9_]", PFX_NOTLOWER));
2064 llmsg (message (" %h Any letter [A-Za-z]", PFX_ANYLETTER));
2065 llmsg (message (" %h Any letter or digit [A-Za-z0-9]", PFX_ANYLETTERDIGIT));
2066 llmsglit (" * Zero or more repetitions of the previous character class until the end of the name");
2075 eval = context_getLarchPath ();
2076 def = osd_getEnvironmentVariable (LARCH_PATH);
2078 if (cstring_isDefined (def) ||
2079 !cstring_equal (eval, cstring_fromChars (DEFAULT_LARCHPATH)))
2081 llmsg (message ("LARCH_PATH = %s", eval));
2085 llmsg (message ("LARCH_PATH = <not set> (default = %s)",
2086 cstring_fromChars (DEFAULT_LARCHPATH)));
2089 llmsglit (" --- path used to find larch initialization files and LSL traits");
2091 eval = context_getLCLImportDir ();
2092 def = osd_getEnvironmentVariable (cstring_makeLiteralTemp (LCLIMPORTDIR));
2094 if (cstring_isDefined (def) ||
2095 !cstring_equal (eval, cstring_fromChars (DEFAULT_LCLIMPORTDIR)))
2097 llmsg (message ("%q = %s", cstring_makeLiteral (LCLIMPORTDIR), eval));
2101 llmsg (message ("%s = <not set, default: %s>", cstring_makeLiteralTemp (LCLIMPORTDIR),
2102 cstring_makeLiteralTemp (DEFAULT_LCLIMPORTDIR)));
2105 llmsglit (" --- directory containing lcl standard library files "
2106 "(import with < ... >)");;
2109 ("include path = %q (set by environment variable %s and -I flags)",
2110 cppReader_getIncludePath (), INCLUDEPATH_VAR));
2112 llmsglit (" --- path used to find #include'd files");
2115 ("systemdirs = %s (set by -systemdirs or environment variable %s)", /*@i413223@*/
2116 context_getString (FLG_SYSTEMDIRS),
2119 llmsglit (" --- if file is found on this path, it is treated as a system file for error reporting");
2128 fprintf (stderr, "*** Interrupt\n");
2129 llexit (LLINTERRUPT);
2134 /* Cheat when there are parse errors */
2137 fprintf (stderr, "*** Segmentation Violation\n");
2139 /* Don't catch it if fileloc_unparse causes a signal */
2140 (void) signal (SIGSEGV, NULL);
2142 loc = fileloc_unparse (g_currentloc);
2144 fprintf (stderr, "*** Location (not trusted): %s\n",
2145 cstring_toCharsSafe (loc));
2148 fprintf (stderr, "*** Please report bug to %s\n", LCLINT_MAINTAINER);
2152 fprintf (stderr, "*** Signal: %d\n", i);
2154 fprintf (stderr, "*** Location (not trusted): %s\n",
2155 cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
2158 fprintf (stderr, "*** Please report bug to %s ***\n", LCLINT_MAINTAINER);
2166 static bool doneCleanup = FALSE;
2168 /* make sure this is only called once! */
2170 if (doneCleanup) return;
2175 ** Close all open files
2176 ** (There should only be open files, if we exited after a fatal error.)
2179 fileTable_closeAll (context_fileTable ());
2181 if (context_getFlag (FLG_KEEP))
2183 check (fputs ("Temporary files kept:\n", stderr) != EOF);
2184 fileTable_printTemps (context_fileTable ());
2189 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
2193 llbug (message ("Files unclosed: %d", nfiles));
2196 fileTable_cleanup (context_fileTable ());
2203 ** cleans up temp files (if necessary)
2210 DPRINTF (("llexit: %d", status));
2213 if (status == LLFAILURE)
2221 if (status != LLFAILURE)
2223 context_destroyMod ();
2224 exprNode_destroyMod ();
2227 uentry_destroyMod ();
2228 typeIdSet_destroyMod ();
2231 dmalloc_shutdown ();
2235 exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
2239 ** This shouldn't be necessary, but Apple Darwin can't handle '"''s.
2243 loadrc (/*:open:*/ FILE *rcfile, cstringSList *passThroughArgs)
2244 /*@ensures closed rcfile@*/
2246 char *s = mstring_create (MAX_LINE_LENGTH);
2249 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2253 while (reader_readLine (rcfile, s, MAX_LINE_LENGTH) != NULL)
2260 DPRINTF (("Line: %s", s));
2261 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2263 while (*s == ' ' || *s == '\t')
2271 bool escaped = FALSE;
2272 bool quoted = FALSE;
2275 DPRINTF (("Process: %s", s));
2276 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2277 /* comment characters */
2278 if (c == '#' || c == ';' || c == '\n')
2284 if (c == '-' || c == '+')
2291 voptgenerror (FLG_BADFLAG,
2292 message ("Bad flag syntax (+ or - expected, "
2293 "+ is assumed): %s",
2294 cstring_fromChars (s)),
2305 while ((c = *s) != '\0')
2306 { /* remember to handle spaces and quotes in -D and -U ... */
2332 if (c == ' ' || c == '\t' || c == '\n')
2334 /*@innerbreak@*/ break;
2342 DPRINTF (("Nulling: %c", *s));
2345 if (mstring_isEmpty (thisflag))
2347 llfatalerror (message ("Missing flag: %s",
2348 cstring_fromChars (os)));
2351 DPRINTF (("Flag: %s", thisflag));
2353 opt = identifyFlag (cstring_fromChars (thisflag));
2355 if (flagcode_isSkip (opt))
2359 else if (flagcode_isInvalid (opt))
2361 DPRINTF (("Invalid: %s", thisflag));
2363 if (isMode (cstring_fromChars (thisflag)))
2365 context_setMode (cstring_fromChars (thisflag));
2369 voptgenerror (FLG_BADFLAG,
2370 message ("Unrecognized option: %s",
2371 cstring_fromChars (thisflag)),
2377 context_userSetFlag (opt, set);
2379 if (flagcode_hasArgument (opt))
2381 if (opt == FLG_HELP)
2384 voptgenerror (FLG_BADFLAG,
2385 message ("Cannot use help in rc files"),
2388 else if (flagcode_isPassThrough (opt)) /* -D or -U */
2390 cstring arg = cstring_fromCharsNew (thisflag);
2391 cstring_markOwned (arg);
2392 *passThroughArgs = cstringSList_add (*passThroughArgs, arg);
2393 DPRINTF (("Pass through: %s",
2394 cstringSList_unparse (*passThroughArgs)));
2396 else if (opt == FLG_INCLUDEPATH
2397 || opt == FLG_SPECPATH)
2399 cstring dir = cstring_suffix (cstring_fromChars (thisflag), 1); /* skip over I/S */
2403 case FLG_INCLUDEPATH:
2404 cppAddIncludeDir (dir);
2405 /*@switchbreak@*/ break;
2408 g_localSpecPath = cstring_toCharsSafe
2409 (message ("%s:%s", cstring_fromChars (g_localSpecPath), dir));
2411 /*@switchbreak@*/ break;
2415 else if (flagcode_hasString (opt)
2416 || flagcode_hasValue (opt)
2417 || opt == FLG_INIT || opt == FLG_OPTF)
2419 cstring extra = cstring_undefined;
2424 rest = mstring_copy (s);
2425 DPRINTF (("Here: rest = %s", rest));
2429 while ((rchar = *rest) != '\0'
2430 && (isspace ((int) rchar)))
2436 DPRINTF (("Yo: %s", rest));
2438 while ((rchar = *rest) != '\0'
2439 && !isspace ((int) rchar))
2441 extra = cstring_appendChar (extra, rchar);
2446 DPRINTF (("Yo: %s", extra));
2449 if (cstring_isUndefined (extra))
2455 ("Flag %s must be followed by an argument",
2456 flagcode_unparse (opt)),
2463 DPRINTF (("Here we are: %s", extra));
2465 if (flagcode_hasValue (opt))
2467 DPRINTF (("Set value flag: %s", extra));
2468 setValueFlag (opt, extra);
2469 cstring_free (extra);
2471 else if (opt == FLG_OPTF)
2473 FILE *innerf = fileTable_openFile (context_fileTable (), extra, "r");
2474 cstring_markOwned (extra);
2478 fileloc fc = g_currentloc;
2479 g_currentloc = fileloc_createRc (extra);
2480 loadrc (innerf, passThroughArgs);
2481 fileloc_reallyFree (g_currentloc);
2489 message ("Options file not found: %s",
2494 else if (opt == FLG_INIT)
2497 llassert (inputStream_isUndefined (initFile));
2499 initFile = inputStream_create
2501 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
2504 cstring_free (extra);
2507 else if (flagcode_hasString (opt))
2509 if (cstring_firstChar (extra) == '\"')
2511 if (cstring_lastChar (extra) == '\"')
2513 char *extras = cstring_toCharsSafe (extra);
2515 llassert (extras[strlen(extras) - 1] == '\"');
2516 extras[strlen(extras) - 1] = '\0';
2517 extra = cstring_fromChars (extras + 1);
2518 DPRINTF (("Remove quotes: %s", extra));
2524 message ("Unmatched \" in option string: %s",
2530 setStringFlag (opt, extra);
2534 cstring_free (extra);
2547 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2548 while ((c == ' ') || (c == '\t'))
2554 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2558 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2560 check (fileTable_closeFile (context_fileTable (), rcfile));
2563 static fileIdList preprocessFiles (fileIdList fl, bool xhfiles)
2564 /*@modifies fileSystem@*/
2566 bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
2567 int skip = (fileIdList_size (fl) / 5);
2568 int filesprocessed = 0;
2569 fileIdList dfiles = fileIdList_create ();
2571 fileloc_free (g_currentloc);
2572 g_currentloc = fileloc_createBuiltin ();
2574 fileIdList_elements (fl, fid)
2576 cstring ppfname = fileName (fid);
2578 if (!(osd_fileIsReadable (ppfname)))
2580 lldiagmsg (message ("Cannot open file: %s", osd_outputPath (ppfname)));
2581 ppfname = cstring_undefined;
2584 if (cstring_isDefined (ppfname))
2586 fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
2590 llassert (fileTable_isXHFile (context_fileTable (), dfile));
2593 llassert (cstring_isNonEmpty (ppfname));
2597 if ((filesprocessed % skip) == 0)
2599 if (filesprocessed == 0) {
2600 fprintf (stderr, " ");
2603 fprintf (stderr, ".");
2606 (void) fflush (stderr);
2611 if (cppProcess (ppfname, fileName (dfile)) != 0)
2613 llfatalerror (message ("Preprocessing error for file: %s",
2614 rootFileName (fid)));
2617 fileIdList_add (dfiles, dfile);
2619 } end_fileIdList_elements;
2624 /* This should be in an lclUtils.c file... */
2626 char *specFullName (char *specfile, /*@out@*/ char **inpath)
2628 /* extract the path and the specname associated with the given file */
2629 char *specname = (char *) dmalloc (sizeof (*specname)
2630 * (strlen (specfile) + 9));
2631 char *ospecname = specname;
2632 char *path = (char *) dmalloc (sizeof (*path) * (strlen (specfile)));
2636 /* initialized path to empty string or may have accidental garbage */
2639 /*@-mayaliasunique@*/
2640 strcpy (specname, specfile);
2641 /*@=mayaliasunique@*/
2643 /* trim off pathnames in specfile */
2644 size = strlen (specname);
2646 for (i = size_toInt (size) - 1; i >= 0; i--)
2648 if (specname[i] == CONNECTCHAR)
2650 /* strcpy (specname, (char *)specname+i+1); */
2651 for (j = 0; j <= i; j++) /* include '/' */
2653 path[j] = specname[j];
2663 ** also remove .lcl file extension, assume it's the last extension
2667 size = strlen (specname);
2669 for (i = size_toInt (size) - 1; i >= 0; i--)
2671 if (specname[i] == '.')
2681 ** If specname no longer points to the original char,
2682 ** we need to allocate a new pointer and copy the string.
2685 if (specname != ospecname) {
2686 char *rspecname = (char *) dmalloc (sizeof (*rspecname) * (strlen (specname) + 1));
2687 strcpy (rspecname, specname); /* evs 2000-05-16: Bug: was ospecname! */