2 ** Splint - 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://www.splint.org
27 ** Main module for Splint annotation-assisted program 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", SPLINT_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 ();
769 cstring fname = cstring_undefined;
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"))
792 fname = cstring_fromChars (argv[i]);
793 rcfile = fileTable_openFile (context_fileTable (), 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", fname));
812 (cstring_makeLiteral ("Flag f to select options file "
813 "requires an argument"));
817 ; /* wait to process later */
822 if (cstring_isUndefined (fname))
824 if (!cstring_isEmpty (home)) {
825 fname = message ("%s%h%s", home, CONNECTCHAR,
826 cstring_fromChars (RCFILE));
827 cstring_markOwned (fname);
833 if (!nof && defaultf)
835 if (!cstring_isEmpty (fname))
837 rcfile = fileTable_openFile (context_fileTable (), fname, "r");
841 fileloc oloc = g_currentloc;
843 g_currentloc = fileloc_createRc (fname);
844 loadrc (rcfile, &passThroughArgs);
845 fileloc_reallyFree (g_currentloc);
850 # if defined(MSDOS) || defined(OS2)
851 fname = message ("%s",cstring_fromChars (RCFILE));
853 fname = message ("./%s", cstring_fromChars (RCFILE));
856 rcfile = fileTable_openFile (context_fileTable (), fname, "r");
859 ** If no RCFILE, try ALTRCFILE
864 cstring_free (fname);
865 # if defined(MSDOS) || defined(OS2)
866 fname = message ("%s", cstring_fromChars (ALTRCFILE));
868 fname = message ("./%s", cstring_fromChars (ALTRCFILE));
870 rcfile = fileTable_openFile (context_fileTable (), fname, "r");
875 ** Warn if ALTRCFILE also exists
880 # if defined(MSDOS) || defined(OS2)
881 afname = message ("%s", cstring_fromChars (ALTRCFILE));
883 afname = message ("./%s", cstring_fromChars (ALTRCFILE));
885 arcfile = fileTable_openFile (context_fileTable (), afname, "r");
889 voptgenerror (FLG_WARNRC,
890 message ("Found both %s and %s files. Using %s file only.",
891 fname, afname, fname),
894 fileTable_closeFile (context_fileTable (), arcfile);
900 fileloc oloc = g_currentloc;
902 g_currentloc = fileloc_createRc (cstring_fromChars (fname));
903 loadrc (rcfile, &passThroughArgs);
904 fileloc_reallyFree (g_currentloc);
914 for (i = 1; i < argc; i++)
930 if (*thisarg == '-' || *thisarg == '+')
932 thisarg++; /* skip '-' */
934 if (mstring_equal (thisarg, "modes"))
936 llmsg (describeModes ());
938 else if (mstring_equal (thisarg, "vars")
939 || mstring_equal (thisarg, "env"))
943 else if (mstring_equal (thisarg, "annotations"))
947 else if (mstring_equal (thisarg, "parseerrors"))
951 else if (mstring_equal (thisarg, "comments"))
955 else if (mstring_equal (thisarg, "prefixcodes"))
957 describePrefixCodes ();
959 else if (mstring_equal (thisarg, "references")
960 || mstring_equal (thisarg, "refs"))
964 else if (mstring_equal (thisarg, "mail"))
968 else if (mstring_equal (thisarg, "maintainer")
969 || mstring_equal (thisarg, "version"))
973 else if (mstring_equal (thisarg, "flags"))
977 char *next = argv[i + 1];
979 if (specialFlagsHelp (next))
985 flagkind k = identifyCategory (cstring_fromChars (next));
1001 cstring s = describeFlag (cstring_fromChars (thisarg));
1003 if (cstring_isDefined (s))
1011 if (*thisarg == '-' || *thisarg == '+')
1013 bool set = (*thisarg == '+');
1016 thisarg++; /* skip '-' */
1017 flagname = cstring_fromChars (thisarg);
1019 DPRINTF (("Flag: %s", flagname));
1020 opt = identifyFlag (flagname);
1021 DPRINTF (("Flag: %s", flagcode_unparse (opt)));
1023 if (flagcode_isSkip (opt))
1025 DPRINTF (("Skipping!"));
1027 else if (flagcode_isInvalid (opt))
1029 DPRINTF (("Invalid: %s", flagname));
1031 if (isMode (flagname))
1033 context_setMode (flagname);
1037 DPRINTF (("Error!"));
1038 voptgenerror (FLG_BADFLAG,
1039 message ("Unrecognized option: %s",
1040 cstring_fromChars (thisarg)),
1046 context_userSetFlag (opt, set);
1048 if (flagcode_hasArgument (opt))
1050 if (opt == FLG_HELP)
1054 else if (flagcode_isPassThrough (opt)) /* -D or -U */
1056 passThroughArgs = cstringSList_add
1057 (passThroughArgs, cstring_fromChars (thisarg));
1059 else if (flagcode_hasValue (opt))
1063 setValueFlag (opt, cstring_fromChars (argv[i]));
1069 ("Flag %s must be followed by a number",
1070 flagcode_unparse (opt)));
1073 else if (opt == FLG_INCLUDEPATH || opt == FLG_SPECPATH)
1075 cstring dir = cstring_suffix (cstring_fromChars (thisarg), 1); /* skip over I */
1079 case FLG_INCLUDEPATH:
1080 cppAddIncludeDir (dir);
1081 /*@switchbreak@*/ break;
1084 g_localSpecPath = cstring_toCharsSafe
1086 cstring_fromChars (g_localSpecPath),
1090 /*@switchbreak@*/ break;
1094 else if (flagcode_hasString (opt)
1095 || opt == FLG_INIT || opt == FLG_OPTF)
1099 cstring arg = cstring_fromChars (argv[i]);
1101 if (opt == FLG_OPTF)
1103 ; /* -f already processed */
1105 else if (opt == FLG_INIT)
1108 initFile = inputStream_create
1110 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
1117 DPRINTF (("String flag: %s / %s",
1118 flagcode_unparse (opt), arg));
1119 if (opt == FLG_MTSFILE)
1122 ** arg identifies mts files
1124 cstring tmp = message ("%s%s", arg, MTS_EXTENSION);
1125 addLarchPathFile (mtfiles, tmp);
1127 tmp = message ("%s%s", arg, XH_EXTENSION);
1128 addXHFile (xfiles, tmp);
1133 setStringFlag (opt, arg);
1141 ("Flag %s must be followed by a string",
1142 flagcode_unparse (opt)));
1152 else /* its a filename */
1154 DPRINTF (("Adding filename: %s", thisarg));
1155 fl = cstringSList_add (fl, cstring_fromChars (thisarg));
1163 ** create lists of C and LCL files
1166 cstringSList_elements (fl, current)
1168 cstring ext = fileLib_getExtension (current);
1170 if (cstring_isUndefined (ext))
1172 /* no extension --- both C and LCL with default extensions */
1174 addFile (cfiles, message ("%s%s", current, C_EXTENSION));
1175 addFile (lclfiles, message ("%s%s", current, LCL_EXTENSION));
1177 else if (cstring_equal (ext, XH_EXTENSION))
1179 addXHFile (xfiles, current);
1181 else if (cstring_equal (ext, PP_EXTENSION))
1183 if (!context_getFlag (FLG_NOPP))
1186 (FLG_FILEEXTENSIONS,
1187 message ("File extension %s used without +nopp flag (will be processed as C source code): %s",
1192 addFile (cfiles, cstring_copy (current));
1194 else if (cstring_equal (ext, LCL_EXTENSION))
1196 addFile (lclfiles, cstring_copy (current));
1198 else if (fileLib_isCExtension (ext))
1200 addFile (cfiles, cstring_copy (current));
1202 else if (cstring_equal (ext, MTS_EXTENSION))
1204 addLarchPathFile (mtfiles, current);
1209 (FLG_FILEEXTENSIONS,
1210 message ("Unrecognized file extension: %s (assuming %s is C source code)",
1214 addFile (cfiles, cstring_copy (current));
1216 } end_cstringSList_elements;
1218 showHerald (); /*@i723 move earlier? */
1226 fprintf (g_msgstream, "\n");
1228 fileIdList_free (cfiles);
1229 fileIdList_free (xfiles);
1230 fileIdList_free (lclfiles);
1239 inittime = clock ();
1241 context_resetErrors ();
1242 context_clearInCommandLine ();
1244 anylcl = !fileIdList_isEmpty (lclfiles);
1246 if (context_doMerge ())
1248 cstring m = context_getMerge ();
1250 if (context_getFlag (FLG_SHOWSCAN))
1252 fprintf (g_msgstream, "< loading %s ", cstring_toCharsSafe (m));
1257 if (context_getFlag (FLG_SHOWSCAN))
1259 fprintf (g_msgstream, " >\n");
1262 if (!usymtab_existsType (context_getBoolName ()))
1264 usymtab_initBool ();
1269 if (!context_getFlag (FLG_NOLIB) && loadStandardState ())
1278 /* setup bool type and constants */
1279 usymtab_initBool ();
1282 fileloc_free (g_currentloc);
1283 g_currentloc = fileloc_createBuiltin ();
1286 ** Read metastate files (must happen before loading libraries)
1289 fileIdList_elements (mtfiles, mtfile)
1291 context_setFileId (mtfile);
1293 if (context_getFlag (FLG_SHOWSCAN))
1295 lldiagmsg (message ("< processing %s >", rootFileName (mtfile)));
1298 mtreader_readFile (cstring_copy (fileName (mtfile)));
1299 } end_fileIdList_elements;
1306 llfatalerror (cstring_makeLiteral ("This version of Splint does not handle LCL files."));
1308 lslProcess (lclfiles);
1312 usymtab_initGlobalMarker ();
1317 ** call the pre-preprocessor and /lib/cpp to generate appropriate
1322 context_setInCommandLine ();
1324 DPRINTF (("Pass through: %s", cstringSList_unparse (passThroughArgs)));
1326 cstringSList_elements (passThroughArgs, thisarg) {
1327 handlePassThroughFlag (cstring_toCharsSafe (thisarg));
1328 } end_cstringSList_elements;
1330 cstringSList_free (passThroughArgs);
1334 DPRINTF (("Initializing cpp reader!"));
1335 cppReader_initialize ();
1336 cppReader_saveDefinitions ();
1338 context_clearInCommandLine ();
1340 if (!context_getFlag (FLG_NOPP))
1346 if (context_getFlag (FLG_SHOWSCAN))
1348 fprintf (stderr, "< preprocessing");
1353 context_setPreprocessing ();
1354 dercfiles = preprocessFiles (xfiles, TRUE);
1355 tfiles = preprocessFiles (cfiles, FALSE);
1356 dercfiles = fileIdList_append (dercfiles, tfiles);
1357 fileIdList_free (tfiles);
1359 context_clearPreprocessing ();
1361 fileIdList_free (cfiles);
1363 if (context_getFlag (FLG_SHOWSCAN))
1365 fprintf (stderr, " >\n");
1373 dercfiles = fileIdList_append (cfiles, xfiles);
1378 ** now, check all the corresponding C files
1380 ** (for now these are just <file>.c, but after pre-processing
1381 ** will be <tmpprefix>.<file>.c)
1386 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1390 llbug (message ("Files unclosed: %d", nfiles));
1395 DPRINTF (("Initializing..."));
1397 exprNode_initMod ();
1399 DPRINTF (("Okay..."));
1401 fileIdList_elements (dercfiles, fid)
1403 sourceFile = inputStream_create (cstring_copy (fileName (fid)), C_EXTENSION, TRUE);
1404 context_setFileId (fid);
1406 /* Open source file */
1408 if (inputStream_isUndefined (sourceFile) || (!inputStream_open (sourceFile)))
1410 /* previously, this was ignored ?! */
1411 llbug (message ("Could not open temp file: %s", fileName (fid)));
1415 yyin = inputStream_getFile (sourceFile); /*< shared <- only */
1417 llassert (yyin != NULL);
1419 if (context_getFlag (FLG_SHOWSCAN))
1421 lldiagmsg (message ("< checking %q >", osd_outputPath (rootFileName (fid))));
1425 ** Every time, except the first time, through the loop,
1426 ** need to call yyrestart to clean up the parse buffer.
1431 (void) yyrestart (yyin);
1438 DPRINTF (("Entering..."));
1439 context_enterFile ();
1441 context_exitCFile ();
1443 (void) inputStream_close (sourceFile);
1445 } end_fileIdList_elements;
1449 /* process any leftover macros */
1451 context_processAllMacros ();
1453 /* check everything that was specified was defined */
1455 /* don't check if no c files were processed ?
1456 ** is this correct behaviour?
1459 if (context_getFlag (FLG_SHOWSCAN))
1461 lldiagmsg (cstring_makeLiteral ("< global checks >"));
1466 if (context_getLinesProcessed () > 0)
1468 usymtab_allDefined ();
1471 if (context_maybeSet (FLG_TOPUNUSED))
1473 uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main"));
1475 if (uentry_isValid (ue))
1477 uentry_setUsed (ue, fileloc_observeBuiltin ());
1483 if (context_maybeSet (FLG_EXPORTLOCAL))
1485 usymtab_exportLocal ();
1489 if (context_maybeSet (FLG_EXPORTHEADER))
1491 usymtab_exportHeader ();
1494 if (context_getFlag (FLG_SHOWUSES))
1496 usymtab_displayAllUses ();
1499 context_checkSuppressCounts ();
1501 if (context_doDump ())
1503 cstring dump = context_getDump ();
1514 if (context_getFlag (FLG_SHOWSUMMARY))
1521 bool isQuiet = context_getFlag (FLG_QUIET);
1522 cstring specErrors = cstring_undefined;
1524 int nspecErrors = lclNumberErrors ();
1529 if (context_neednl ())
1530 fprintf (g_msgstream, "\n");
1533 if (nspecErrors > 0)
1535 if (nspecErrors == context_getLCLExpect ())
1538 message ("%d spec warning%&, as expected\n ",
1543 if (context_getLCLExpect () > 0)
1546 message ("%d spec warning%&, expected %d\n ",
1548 (int) context_getLCLExpect ());
1552 specErrors = message ("%d spec warning%& found\n ",
1560 if (context_getLCLExpect () > 0)
1562 specErrors = message ("No spec warnings, expected %d\n ",
1563 (int) context_getLCLExpect ());
1569 if (context_anyErrors ())
1571 if (context_numErrors () == context_getExpect ())
1574 llmsg (message ("Finished checking --- "
1575 "%s%d code warning%&, as expected",
1576 specErrors, context_numErrors ()));
1581 if (context_getExpect () > 0)
1585 ("Finished checking --- "
1586 "%s%d code warning%&, expected %d",
1587 specErrors, context_numErrors (),
1588 (int) context_getExpect ()));
1598 llmsg (message ("Finished checking --- "
1599 "%s%d code warning%& found",
1600 specErrors, context_numErrors ()));
1609 if (context_getExpect () > 0)
1613 ("Finished checking --- "
1614 "%sno code warnings, expected %d",
1616 (int) context_getExpect ()));
1623 if (context_getLinesProcessed () > 0)
1625 if (cstring_isEmpty (specErrors))
1629 llmsg (message ("Finished checking --- no warnings"));
1635 llmsg (message ("Finished checking --- %sno code warnings",
1642 llmsg (message ("Finished checking --- %sno code processed",
1649 cstring_free (specErrors);
1652 if (context_getFlag (FLG_STATS))
1654 clock_t ttime = clock () - before;
1655 int specLines = context_getSpecLinesProcessed ();
1661 fprintf (g_msgstream, "%d spec, ", specLines);
1664 # ifndef CLOCKS_PER_SEC
1665 fprintf (g_msgstream, "%d source lines in %ld time steps (steps/sec unknown)\n",
1666 context_getLinesProcessed (),
1669 fprintf (g_msgstream, "%d source lines in %.2f s.\n",
1670 context_getLinesProcessed (),
1671 (double) ttime / CLOCKS_PER_SEC);
1679 if (context_getFlag (FLG_TIMEDIST))
1681 clock_t ttime = clock () - before;
1685 char *msg = (char *) dmalloc (256 * sizeof (*msg));
1690 "Time distribution (percent): initialize %.2f / lcl %.2f / "
1691 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1692 (100.0 * (double) (libtime - before) / ttime),
1693 (100.0 * (double) (lcltime - libtime) / ttime),
1694 (100.0 * (double) (pptime - lcltime) / ttime),
1695 (100.0 * (double) (cptime - pptime) / ttime),
1696 (100.0 * (double) (rstime - cptime) / ttime));
1701 "Time distribution (percent): initialize %.2f / "
1702 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1703 (100.0 * (double) (libtime - before) / ttime),
1704 (100.0 * (double) (pptime - libtime) / ttime),
1705 (100.0 * (double) (cptime - pptime) / ttime),
1706 (100.0 * (double) (rstime - cptime) / ttime));
1709 llgenindentmsgnoloc (cstring_fromCharsO (msg));
1713 llexit (expsuccess ? LLSUCCESS : LLFAILURE);
1714 BADBRANCHRET (LLFAILURE);
1719 ** Reenable return value warnings.
1721 # pragma warning (default:4035)
1729 llmsg (message ("Source files are .c, .h and %s files. If there is no suffix,",
1731 llmsg (message (" Splint will look for <file>.c and <file>%s.", LCL_EXTENSION));
1733 llmsglit ("Use splint -help <topic or flag name> for more information");
1735 llmsglit ("Topics:");
1737 llmsglit (" annotations (describes source-code annotations)");
1738 llmsglit (" comments (describes control comments)");
1739 llmsglit (" flags (describes flag categories)");
1740 llmsglit (" flags <category> (describes flags in category)");
1741 llmsglit (" flags all (short description of all flags)");
1742 llmsglit (" flags alpha (list all flags alphabetically)");
1743 llmsglit (" flags full (full description of all flags)");
1744 llmsglit (" mail (information on mailing lists)");
1745 llmsglit (" modes (show mode settings)");
1746 llmsglit (" parseerrors (help on handling parser errors)");
1747 llmsglit (" prefixcodes (character codes in namespace prefixes)");
1748 llmsglit (" references (sources for more information)");
1749 llmsglit (" vars (environment variables)");
1750 llmsglit (" version (information on compilation, maintainer)");
1755 specialFlagsHelp (char *next)
1757 if ((next != NULL) && (*next != '-') && (*next != '+'))
1759 if (mstring_equal (next, "alpha"))
1764 else if (mstring_equal (next, "all"))
1766 printAllFlags (TRUE, FALSE);
1769 else if (mstring_equal (next, "categories")
1770 || mstring_equal (next, "cats"))
1772 listAllCategories ();
1775 else if (mstring_equal (next, "full"))
1777 printAllFlags (FALSE, TRUE);
1792 printParseErrors (void)
1794 llmsglit ("Parse Errors");
1795 llmsglit ("------------");
1797 llmsglit ("LCLint will sometimes encounter a parse error for code that "
1798 "can be parsed with a local compiler. There are a few likely "
1799 "causes for this and a number of techniques that can be used "
1800 "to work around the problem.");
1802 llmsglit ("Compiler extensions --- compilers sometimes extend the C "
1803 "language with compiler-specific keywords and syntax. While "
1804 "it is not advisible to use these, oftentimes one has no choice "
1805 "when the system header files use compiler extensions. ");
1807 llmsglit ("Splint supports some of the GNU (gcc) compiler extensions, "
1808 "if the +gnuextensions flag is set. You may be able to workaround "
1809 "other compiler extensions by using a pre-processor define. "
1810 "Alternately, you can surround the unparseable code with");
1812 llmsglit (" # ifndef __LCLINT__");
1814 llmsglit (" # endif");
1816 /* evans 2000-12-21 fixed typo reported by Jeroen Ruigrok/Asmodai */
1817 llmsglit ("Missing type definitions --- an undefined type name will usually "
1818 "lead to a parse error. This often occurs when a standard header "
1819 "file defines some type that is not part of the standard library. ");
1820 llmsglit ("By default, Splint does not process the local files corresponding "
1821 "to standard library headers, but uses a library specification "
1822 "instead so dependencies on local system headers can be detected. "
1823 "If another system header file that does not correspond to a "
1824 "standard library header uses one of these superfluous types, "
1825 "a parse error will result.");
1827 llmsglit ("If the parse error is inside a posix standard header file, the "
1828 "first thing to try is +posixlib. This makes Splint use "
1829 "the posix library specification instead of reading the posix "
1832 llmsglit ("Otherwise, you may need to either manually define the problematic "
1833 "type (e.g., add -Dmlink_t=int to your .lclintrc file) or force "
1834 "lclint to process the header file that defines it. This is done "
1835 "by setting -skipansiheaders or -skipposixheaders before "
1836 "the file that defines the type is #include'd.");
1837 llmsglit ("(See lclint -help "
1838 "skipansiheaders and lclint -help skipposixheaders for a list of "
1839 "standard headers.) For example, if <sys/local.h> uses a type "
1840 "defined by posix header <sys/types.h> but not defined by the "
1841 "posix library, we might do: ");
1843 llmsglit (" /*@-skipposixheaders@*/");
1844 llmsglit (" # include <sys/types.h>");
1845 llmsglit (" /*@=skipposixheaders@*/");
1846 llmsglit (" # include <sys/local.h>");
1848 llmsglit ("to force Splint to process <sys/types.h>.");
1850 llmsglit ("At last resort, +trytorecover can be used to make Splint attempt "
1851 "to continue after a parse error. This is usually not successful "
1852 "and the author does not consider assertion failures when +trytorecover "
1853 "is used to be bugs.");
1857 printAnnotations (void)
1859 llmsglit ("Annotations");
1860 llmsglit ("-----------");
1862 llmsglit ("Annotations are semantic comments that document certain "
1863 "assumptions about functions, variables, parameters, and types. ");
1865 llmsglit ("They may be used to indicate where the representation of a "
1866 "user-defined type is hidden, to limit where a global variable may "
1867 "be used or modified, to constrain what a function implementation "
1868 "may do to its parameters, and to express checked assumptions about "
1869 "variables, types, structure fields, function parameters, and "
1870 "function results.");
1872 llmsglit ("Annotations are introduced by \"/*@\". The role of the @ may be "
1873 "played by any printable character, selected using -commentchar <char>.");
1875 llmsglit ("Consult the User's Guide for descriptions of checking associated with each annotation.");
1877 llmsglit ("Globals: (in function declarations)");
1878 llmsglit (" /*@globals <globitem>,+ @*/");
1879 llmsglit (" globitem is an identifier, internalState or fileSystem");
1881 llmsglit ("Modifies: (in function declarations)");
1882 llmsglit (" /*@modifies <moditem>,+ @*/");
1883 llmsglit (" moditem is an lvalue");
1884 llmsglit (" /*@modifies nothing @*/");
1885 llmsglit (" /*@*/ (Abbreviation for no globals and modifies nothing.)");
1887 llmsglit ("Iterators:");
1888 llmsglit (" /*@iter <identifier> (<parameter-type-list>) @*/ - declare an iterator");
1890 llmsglit ("Constants:");
1891 llmsglit (" /*@constant <declaration> @*/ - declares a constant");
1893 llmsglit ("Alternate Types:");
1894 llmsglit (" /*@alt <basic-type>,+ @*/");
1895 llmsglit (" (e.g., int /*@alt char@*/ is a type matching either int or char)");
1897 llmsglit ("Declarator Annotations");
1899 llmsglit ("Type Definitions:");
1900 llmsglit (" /*@abstract@*/ - representation is hidden from clients");
1901 llmsglit (" /*@concrete@*/ - representation is visible to clients");
1902 llmsglit (" /*@immutable@*/ - instances of the type cannot change value");
1903 llmsglit (" /*@mutable@*/ - instances of the type can change value");
1904 llmsglit (" /*@refcounted@*/ - reference counted type");
1906 llmsglit ("Global Variables:");
1907 llmsglit (" /*@unchecked@*/ - weakest checking for global use");
1908 llmsglit (" /*@checkmod@*/ - check modification by not use of global");
1909 llmsglit (" /*@checked@*/ - check use and modification of global");
1910 llmsglit (" /*@checkedstrict@*/ - check use of global strictly");
1912 llmsglit ("Memory Management:");
1913 llmsglit (" /*@dependent@*/ - a reference to externally-owned storage");
1914 llmsglit (" /*@keep@*/ - a parameter that is kept by the called function");
1915 llmsglit (" /*@killref@*/ - a refcounted parameter, killed by the call");
1916 llmsglit (" /*@only@*/ - an unshared reference");
1917 llmsglit (" /*@owned@*/ - owner of storage that may be shared by /*@dependent@*/ references");
1918 llmsglit (" /*@shared@*/ - shared reference that is never deallocated");
1919 llmsglit (" /*@temp@*/ - temporary parameter");
1921 llmsglit ("Aliasing:");
1922 llmsglit (" /*@unique@*/ - may not be aliased by any other visible reference");
1923 llmsglit (" /*@returned@*/ - may be aliased by the return value");
1925 llmsglit ("Exposure:");
1926 llmsglit (" /*@observer@*/ - reference that cannot be modified");
1927 llmsglit (" /*@exposed@*/ - exposed reference to storage in another object");
1929 llmsglit ("Definition State:");
1930 llmsglit (" /*@out@*/ - storage reachable from reference need not be defined");
1931 llmsglit (" /*@in@*/ - all storage reachable from reference must be defined");
1932 llmsglit (" /*@partial@*/ - partially defined, may have undefined fields");
1933 llmsglit (" /*@reldef@*/ - relax definition checking");
1935 llmsglit ("Global State: (for globals lists, no /*@, since list is already in /*@\'s)");
1936 llmsglit (" undef - variable is undefined before the call");
1937 llmsglit (" killed - variable is undefined after the call");
1939 llmsglit ("Null State:");
1940 llmsglit (" /*@null@*/ - possibly null pointer");
1941 llmsglit (" /*@notnull@*/ - non-null pointer");
1942 llmsglit (" /*@relnull@*/ - relax null checking");
1944 llmsglit ("Null Predicates:");
1945 llmsglit (" /*@truenull@*/ - if result is TRUE, first parameter is NULL");
1946 llmsglit (" /*@falsenull@*/ - if result is TRUE, first parameter is not NULL");
1948 llmsglit ("Execution:");
1949 llmsglit (" /*@exits@*/ - function never returns");
1950 llmsglit (" /*@mayexit@*/ - function may or may not return");
1951 llmsglit (" /*@trueexit@*/ - function does not return if first parameter is TRUE");
1952 llmsglit (" /*@falseexit@*/ - function does not return if first parameter if FALSE");
1953 llmsglit (" /*@neverexit@*/ - function always returns");
1955 llmsglit ("Side-Effects:");
1956 llmsglit (" /*@sef@*/ - corresponding actual parameter has no side effects");
1958 llmsglit ("Declaration:");
1959 llmsglit (" /*@unused@*/ - need not be used (no unused errors reported)");
1960 llmsglit (" /*@external@*/ - defined externally (no undefined error reported)");
1963 llmsglit (" /*@fallthrough@*/ - fall-through case");
1965 llmsglit ("Break:");
1966 llmsglit (" /*@innerbreak@*/ - break is breaking an inner loop or switch");
1967 llmsglit (" /*@loopbreak@*/ - break is breaking a loop");
1968 llmsglit (" /*@switchbreak@*/ - break is breaking a switch");
1969 llmsglit (" /*@innercontinue@*/ - continue is continuing an inner loop");
1971 llmsglit ("Unreachable Code:");
1972 llmsglit (" /*@notreached@*/ - statement may be unreachable.");
1974 llmsglit ("Special Functions:");
1975 llmsglit (" /*@printflike@*/ - check variable arguments like printf");
1976 llmsglit (" /*@scanflike@*/ - check variable arguments like scanf");
1980 printComments (void)
1982 llmsglit ("Control Comments");
1983 llmsglit ("----------------");
1985 llmsglit ("Setting Flags");
1987 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.");
1989 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,");
1990 llmsglit (" /*@+boolint -modifies =showfunc@*/");
1991 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).");
1993 llmsglit ("Error Suppression");
1995 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.");
1997 llmsglit ("/*@ignore@*/ ... /*@end@*/");
1999 (cstring_makeLiteral
2000 ("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."));
2001 llmsglit ("/*@i@*/");
2003 (cstring_makeLiteral
2004 ("No errors will be reported from an /*@i@*/ comment to the end of the line."));
2005 llmsglit ("/*@i<n>@*/");
2007 (cstring_makeLiteral
2008 ("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, Splint will report an error."));
2009 llmsglit ("/*@t@*/, /*@t<n>@*/");
2011 (cstring_makeLiteral
2012 ("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."));
2014 llmsglit ("Type Access");
2016 llmsglit ("/*@access <type>@*/");
2017 llmsglit (" Allows the following code to access the representation of <type>");
2018 llmsglit ("/*@noaccess <type>@*/");
2019 llmsglit (" Hides the representation of <type>");
2021 llmsglit ("Macro Expansion");
2023 llmsglit ("/*@notfunction@*/");
2025 (cstring_makeLiteral
2026 ("Indicates that the next macro definition is not intended to be a "
2027 "function, and should be expanded in line instead of checked as a "
2028 "macro function definition."));
2035 llmsglit ("Flag Categories");
2036 llmsglit ("---------------");
2037 listAllCategories ();
2038 llmsglit ("\nTo see the flags in a flag category, do\n lclint -help flags <category>");
2039 llmsglit ("To see a list of all flags in alphabetical order, do\n lclint -help flags alpha");
2040 llmsglit ("To see a full description of all flags, do\n lclint -help flags full");
2044 printMaintainer (void)
2046 llmsg (message ("Maintainer: %s", cstring_makeLiteralTemp (LCLINT_MAINTAINER)));
2047 llmsglit (LCL_COMPILE);
2053 llmsglit ("Mailing Lists");
2054 llmsglit ("-------------");
2056 llmsglit ("There are two mailing lists associated with Splint: ");
2058 llmsglit (" lclint-announce@virginia.edu");
2060 llmsglit (" Reserved for announcements of new releases and bug fixes.");
2061 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
2062 llmsglit (" subscribe lclint-announce");
2064 llmsglit (" lclint-interest@virginia.edu");
2066 llmsglit (" Informal discussions on the use and development of lclint.");
2067 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
2068 llmsglit (" subscribe lclint-interest");
2072 printReferences (void)
2074 llmsglit ("References");
2075 llmsglit ("----------");
2077 llmsglit ("For more information, see the Splint web site: http://www.splint.org");
2081 describePrefixCodes (void)
2083 llmsglit ("Prefix Codes");
2084 llmsglit ("------------");
2086 llmsglit ("These characters have special meaning in name prefixes:");
2088 llmsg (message (" %h Any uppercase letter [A-Z]", PFX_UPPERCASE));
2089 llmsg (message (" %h Any lowercase letter [a-z]", PFX_LOWERCASE));
2090 llmsg (message (" %h Any character (valid in a C identifier)", PFX_ANY));
2091 llmsg (message (" %h Any digit [0-9]", PFX_DIGIT));
2092 llmsg (message (" %h Any non-uppercase letter [a-z0-9_]", PFX_NOTUPPER));
2093 llmsg (message (" %h Any non-lowercase letter [A-Z0-9_]", PFX_NOTLOWER));
2094 llmsg (message (" %h Any letter [A-Za-z]", PFX_ANYLETTER));
2095 llmsg (message (" %h Any letter or digit [A-Za-z0-9]", PFX_ANYLETTERDIGIT));
2096 llmsglit (" * Zero or more repetitions of the previous character class until the end of the name");
2105 eval = context_getLarchPath ();
2106 def = osd_getEnvironmentVariable (LARCH_PATH);
2108 if (cstring_isDefined (def) ||
2109 !cstring_equal (eval, cstring_fromChars (DEFAULT_LARCHPATH)))
2111 llmsg (message ("LARCH_PATH = %s", eval));
2115 llmsg (message ("LARCH_PATH = <not set> (default = %s)",
2116 cstring_fromChars (DEFAULT_LARCHPATH)));
2119 llmsglit (" --- path used to find larch initialization files and LSL traits");
2121 eval = context_getLCLImportDir ();
2122 def = osd_getEnvironmentVariable (cstring_makeLiteralTemp (LCLIMPORTDIR));
2124 if (cstring_isDefined (def) ||
2125 !cstring_equal (eval, cstring_fromChars (DEFAULT_LCLIMPORTDIR)))
2127 llmsg (message ("%q = %s", cstring_makeLiteral (LCLIMPORTDIR), eval));
2131 llmsg (message ("%s = <not set, default: %s>", cstring_makeLiteralTemp (LCLIMPORTDIR),
2132 cstring_makeLiteralTemp (DEFAULT_LCLIMPORTDIR)));
2135 llmsglit (" --- directory containing lcl standard library files "
2136 "(import with < ... >)");;
2139 ("include path = %q (set by environment variable %s and -I flags)",
2140 cppReader_getIncludePath (), INCLUDEPATH_VAR));
2142 llmsglit (" --- path used to find #include'd files");
2145 ("systemdirs = %s (set by -systemdirs or environment variable %s)", /*@i413223@*/
2146 context_getString (FLG_SYSTEMDIRS),
2149 llmsglit (" --- if file is found on this path, it is treated as a system file for error reporting");
2158 fprintf (stderr, "*** Interrupt\n");
2159 llexit (LLINTERRUPT);
2164 /* Cheat when there are parse errors */
2167 fprintf (stderr, "*** Segmentation Violation\n");
2169 /* Don't catch it if fileloc_unparse causes a signal */
2170 (void) signal (SIGSEGV, NULL);
2172 loc = fileloc_unparse (g_currentloc);
2174 fprintf (stderr, "*** Location (not trusted): %s\n",
2175 cstring_toCharsSafe (loc));
2178 fprintf (stderr, "*** Please report bug to %s\n", LCLINT_MAINTAINER);
2182 fprintf (stderr, "*** Signal: %d\n", i);
2184 fprintf (stderr, "*** Location (not trusted): %s\n",
2185 cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
2188 fprintf (stderr, "*** Please report bug to %s ***\n", LCLINT_MAINTAINER);
2196 static bool doneCleanup = FALSE;
2198 /* make sure this is only called once! */
2200 if (doneCleanup) return;
2205 ** Close all open files
2206 ** (There should only be open files, if we exited after a fatal error.)
2209 fileTable_closeAll (context_fileTable ());
2211 if (context_getFlag (FLG_KEEP))
2213 check (fputs ("Temporary files kept:\n", stderr) != EOF);
2214 fileTable_printTemps (context_fileTable ());
2219 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
2223 llbug (message ("Files unclosed: %d", nfiles));
2226 fileTable_cleanup (context_fileTable ());
2233 ** cleans up temp files (if necessary) and exits
2239 DPRINTF (("llexit: %d", status));
2242 if (status == LLFAILURE)
2250 if (status != LLFAILURE)
2252 context_destroyMod ();
2253 exprNode_destroyMod ();
2256 uentry_destroyMod ();
2257 typeIdSet_destroyMod ();
2260 dmalloc_shutdown ();
2264 exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
2268 ** This shouldn't be necessary, but Apple Darwin can't handle '"''s.
2272 loadrc (/*:open:*/ FILE *rcfile, cstringSList *passThroughArgs)
2273 /*@ensures closed rcfile@*/
2275 char *s = mstring_create (MAX_LINE_LENGTH);
2278 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2282 while (reader_readLine (rcfile, s, MAX_LINE_LENGTH) != NULL)
2289 DPRINTF (("Line: %s", s));
2290 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2292 while (*s == ' ' || *s == '\t')
2300 bool escaped = FALSE;
2301 bool quoted = FALSE;
2304 DPRINTF (("Process: %s", s));
2305 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2306 /* comment characters */
2307 if (c == '#' || c == ';' || c == '\n')
2313 if (c == '-' || c == '+')
2320 voptgenerror (FLG_BADFLAG,
2321 message ("Bad flag syntax (+ or - expected, "
2322 "+ is assumed): %s",
2323 cstring_fromChars (s)),
2334 while ((c = *s) != '\0')
2335 { /* remember to handle spaces and quotes in -D and -U ... */
2361 if (c == ' ' || c == '\t' || c == '\n')
2363 /*@innerbreak@*/ break;
2371 DPRINTF (("Nulling: %c", *s));
2374 if (mstring_isEmpty (thisflag))
2376 llfatalerror (message ("Missing flag: %s",
2377 cstring_fromChars (os)));
2380 DPRINTF (("Flag: %s", thisflag));
2382 opt = identifyFlag (cstring_fromChars (thisflag));
2384 if (flagcode_isSkip (opt))
2388 else if (flagcode_isInvalid (opt))
2390 DPRINTF (("Invalid: %s", thisflag));
2392 if (isMode (cstring_fromChars (thisflag)))
2394 context_setMode (cstring_fromChars (thisflag));
2398 voptgenerror (FLG_BADFLAG,
2399 message ("Unrecognized option: %s",
2400 cstring_fromChars (thisflag)),
2406 context_userSetFlag (opt, set);
2408 if (flagcode_hasArgument (opt))
2410 if (opt == FLG_HELP)
2413 voptgenerror (FLG_BADFLAG,
2414 message ("Cannot use help in rc files"),
2417 else if (flagcode_isPassThrough (opt)) /* -D or -U */
2419 cstring arg = cstring_fromCharsNew (thisflag);
2420 cstring_markOwned (arg);
2421 *passThroughArgs = cstringSList_add (*passThroughArgs, arg);
2422 DPRINTF (("Pass through: %s",
2423 cstringSList_unparse (*passThroughArgs)));
2425 else if (opt == FLG_INCLUDEPATH
2426 || opt == FLG_SPECPATH)
2428 cstring dir = cstring_suffix (cstring_fromChars (thisflag), 1); /* skip over I/S */
2432 case FLG_INCLUDEPATH:
2433 cppAddIncludeDir (dir);
2434 /*@switchbreak@*/ break;
2437 g_localSpecPath = cstring_toCharsSafe
2438 (message ("%s:%s", cstring_fromChars (g_localSpecPath), dir));
2440 /*@switchbreak@*/ break;
2444 else if (flagcode_hasString (opt)
2445 || flagcode_hasValue (opt)
2446 || opt == FLG_INIT || opt == FLG_OPTF)
2448 cstring extra = cstring_undefined;
2453 rest = mstring_copy (s);
2454 DPRINTF (("Here: rest = %s", rest));
2458 while ((rchar = *rest) != '\0'
2459 && (isspace ((int) rchar)))
2465 DPRINTF (("Yo: %s", rest));
2467 while ((rchar = *rest) != '\0'
2468 && !isspace ((int) rchar))
2470 extra = cstring_appendChar (extra, rchar);
2475 DPRINTF (("Yo: %s", extra));
2478 if (cstring_isUndefined (extra))
2484 ("Flag %s must be followed by an argument",
2485 flagcode_unparse (opt)),
2492 DPRINTF (("Here we are: %s", extra));
2494 if (flagcode_hasValue (opt))
2496 DPRINTF (("Set value flag: %s", extra));
2497 setValueFlag (opt, extra);
2498 cstring_free (extra);
2500 else if (opt == FLG_OPTF)
2502 FILE *innerf = fileTable_openFile (context_fileTable (), extra, "r");
2503 cstring_markOwned (extra);
2507 fileloc fc = g_currentloc;
2508 g_currentloc = fileloc_createRc (extra);
2509 loadrc (innerf, passThroughArgs);
2510 fileloc_reallyFree (g_currentloc);
2518 message ("Options file not found: %s",
2523 else if (opt == FLG_INIT)
2526 llassert (inputStream_isUndefined (initFile));
2528 initFile = inputStream_create
2530 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
2533 cstring_free (extra);
2536 else if (flagcode_hasString (opt))
2538 if (cstring_firstChar (extra) == '\"')
2540 if (cstring_lastChar (extra) == '\"')
2542 char *extras = cstring_toCharsSafe (extra);
2544 llassert (extras[strlen(extras) - 1] == '\"');
2545 extras[strlen(extras) - 1] = '\0';
2546 extra = cstring_fromChars (extras + 1);
2547 DPRINTF (("Remove quotes: %s", extra));
2553 message ("Unmatched \" in option string: %s",
2559 setStringFlag (opt, extra);
2563 cstring_free (extra);
2576 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2577 while ((c == ' ') || (c == '\t'))
2583 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2587 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2589 check (fileTable_closeFile (context_fileTable (), rcfile));
2592 static fileIdList preprocessFiles (fileIdList fl, bool xhfiles)
2593 /*@modifies fileSystem@*/
2595 bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
2596 int skip = (fileIdList_size (fl) / 5);
2597 int filesprocessed = 0;
2598 fileIdList dfiles = fileIdList_create ();
2600 fileloc_free (g_currentloc);
2601 g_currentloc = fileloc_createBuiltin ();
2603 fileIdList_elements (fl, fid)
2605 cstring ppfname = fileName (fid);
2607 if (!(osd_fileIsReadable (ppfname)))
2609 lldiagmsg (message ("Cannot open file: %s", osd_outputPath (ppfname)));
2610 ppfname = cstring_undefined;
2613 if (cstring_isDefined (ppfname))
2615 fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
2619 llassert (fileTable_isXHFile (context_fileTable (), dfile));
2622 llassert (cstring_isNonEmpty (ppfname));
2626 if ((filesprocessed % skip) == 0)
2628 if (filesprocessed == 0) {
2629 fprintf (stderr, " ");
2632 fprintf (stderr, ".");
2635 (void) fflush (stderr);
2640 if (cppProcess (ppfname, fileName (dfile)) != 0)
2642 llfatalerror (message ("Preprocessing error for file: %s",
2643 rootFileName (fid)));
2646 fileIdList_add (dfiles, dfile);
2648 } end_fileIdList_elements;
2653 /* This should be in an lclUtils.c file... */
2655 char *specFullName (char *specfile, /*@out@*/ char **inpath)
2657 /* extract the path and the specname associated with the given file */
2658 char *specname = (char *) dmalloc (sizeof (*specname)
2659 * (strlen (specfile) + 9));
2660 char *ospecname = specname;
2661 char *path = (char *) dmalloc (sizeof (*path) * (strlen (specfile)));
2665 /* initialized path to empty string or may have accidental garbage */
2668 /*@-mayaliasunique@*/
2669 strcpy (specname, specfile);
2670 /*@=mayaliasunique@*/
2672 /* trim off pathnames in specfile */
2673 size = strlen (specname);
2675 for (i = size_toInt (size) - 1; i >= 0; i--)
2677 if (specname[i] == CONNECTCHAR)
2679 /* strcpy (specname, (char *)specname+i+1); */
2680 for (j = 0; j <= i; j++) /* include '/' */
2682 path[j] = specname[j];
2692 ** also remove .lcl file extension, assume it's the last extension
2696 size = strlen (specname);
2698 for (i = size_toInt (size) - 1; i >= 0; i--)
2700 if (specname[i] == '.')
2710 ** If specname no longer points to the original char,
2711 ** we need to allocate a new pointer and copy the string.
2714 if (specname != ospecname) {
2715 char *rspecname = (char *) dmalloc (sizeof (*rspecname) * (strlen (specname) + 1));
2716 strcpy (rspecname, specname); /* evs 2000-05-16: Bug: was ospecname! */