2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2002 University of Virginia,
4 ** Massachusetts Institute of Technology
6 ** This program is free software; you can redistribute it and/or modify it
7 ** under the terms of the GNU General Public License as published by the
8 ** Free Software Foundation; either version 2 of the License, or (at your
9 ** option) any later version.
11 ** This program is distributed in the hope that it will be useful, but
12 ** WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ** General Public License for more details.
16 ** The GNU General Public License is available from http://www.gnu.org/ or
17 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18 ** MA 02111-1307, USA.
20 ** For information on splint: info@splint.org
21 ** To report a bug: splint-bug@splint.org
22 ** For more information: http://www.splint.org
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 "splintMacros.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"
72 # include "Headers/version.h" /* Visual C++ finds the wrong version.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 bool readOptionsFile (cstring p_fname,
95 cstringSList *p_passThroughArgs,
97 /*@modifies fileSystem, internalState, *p_passThroughArgs@*/ ;
99 static void loadrc (FILE *p_rcfile, cstringSList *p_passThroughArgs)
100 /*@modifies *p_passThroughArgs, p_rcfile@*/
101 /*@ensures closed p_rcfile@*/ ;
103 static void describeVars (void);
104 static bool specialFlagsHelp (char *p_next);
105 static bool hasShownHerald = FALSE;
106 static char *specFullName (char *p_specfile, /*@out@*/ char **p_inpath)
107 /*@modifies *p_inpath@*/ ;
109 static bool anylcl = FALSE;
110 static clock_t inittime;
112 static /*@only@*/ /*@null@*/ inputStream initFile = inputStream_undefined;
114 static fileIdList preprocessFiles (fileIdList, bool)
115 /*@modifies fileSystem@*/ ;
117 static void warnSysFiles(fileIdList p_files) /*@modifies fileSystem@*/;
122 void lslCleanup (void)
123 /*@globals killed g_symtab@*/
124 /*@modifies internalState, g_symtab@*/
127 ** Cleanup all the LCL/LSL.
130 static bool didCleanup = FALSE;
132 llassert (!didCleanup);
137 lsymbol_destroyMod ();
138 LCLSynTableCleanup ();
139 LCLTokenTableCleanup ();
140 LCLScanLineCleanup ();
143 /* clean up LSL parsing */
146 ltokenTableCleanup ();
150 symtable_free (g_symtab);
156 /*@globals undef g_symtab; @*/
157 /*@modifies g_symtab, internalState, fileSystem; @*/
160 ** Open init file provided by user, or use the default LCL init file
163 cstring larchpath = context_getLarchPath ();
164 inputStream LSLinitFile = inputStream_undefined;
168 if (inputStream_isUndefined (initFile))
170 initFile = inputStream_create (cstring_makeLiteral (INITFILENAME),
171 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
174 if (!inputStream_getPath (larchpath, initFile))
176 lldiagmsg (message ("Continuing without LCL init file: %s",
177 inputStream_fileName (initFile)));
181 if (!inputStream_open (initFile))
183 lldiagmsg (message ("Continuing without LCL init file: %s",
184 inputStream_fileName (initFile)));
190 if (!inputStream_open (initFile))
192 lldiagmsg (message ("Continuing without LCL init file: %s",
193 inputStream_fileName (initFile)));
197 /* Initialize checker */
205 LCLTokenTableInit ();
217 /* need this to initialize LCL checker */
219 llassert (inputStream_isDefined (initFile));
220 if (inputStream_isOpen (initFile))
224 LCLScanReset (initFile);
225 LCLProcessInitFileInit ();
226 LCLProcessInitFileReset ();
229 LCLProcessInitFile ();
230 LCLProcessInitFileCleanup ();
233 check (inputStream_close (initFile));
236 /* Initialize LSL init files, for parsing LSL signatures from LSL */
238 LSLinitFile = inputStream_create (cstring_makeLiteral ("lslinit.lsi"),
239 cstring_makeLiteralTemp (".lsi"),
242 if (!inputStream_getPath (larchpath, LSLinitFile))
244 lldiagmsg (message ("Continuing without LSL init file: %s",
245 inputStream_fileName (LSLinitFile)));
249 if (!inputStream_open (LSLinitFile))
251 lldiagmsg (message ("Continuing without LSL init file: %s",
252 inputStream_fileName (LSLinitFile)));
268 if (inputStream_isOpen (LSLinitFile))
271 LSLScanReset (LSLinitFile);
272 LSLProcessInitFileInit ();
274 LSLProcessInitFile ();
276 check (inputStream_close (LSLinitFile));
279 inputStream_free (LSLinitFile);
284 (cstring_makeLiteral ("LSL init file error. Attempting to continue."));
288 g_symtab = symtable_new ();
291 ** sort_init must come after symtab has been initialized
300 ** Equivalent to importing old spec_csupport.lcl
301 ** define immutable LCL type "bool" and bool constants TRUE and FALSE
302 ** and initialized them to be equal to LSL's "true" and "false".
304 ** Reads in CTrait.syms (derived from CTrait.lsl) on LARCH_PATH.
308 LCLReportEolTokens (FALSE);
312 lslProcess (fileIdList lclfiles)
313 /*@globals undef g_currentSpec, undef g_currentSpecName, g_currentloc,
314 undef killed g_symtab; @*/
315 /*@modifies g_currentSpec, g_currentSpecName, g_currentloc, internalState, fileSystem; @*/
318 bool parser_status = FALSE;
319 bool overallStatus = FALSE;
323 context_resetSpecLines ();
325 fileIdList_elements (lclfiles, fid)
327 cstring actualName = cstring_undefined;
328 cstring fname = fileTable_fileName (fid);
330 if (osd_getPath (cstring_fromChars (g_localSpecPath),
331 fname, &actualName) == OSD_FILENOTFOUND)
333 if (mstring_equal (g_localSpecPath, "."))
335 lldiagmsg (message ("Spec file not found: %q", osd_outputPath (fname)));
339 lldiagmsg (message ("Spec file not found: %q (on %s)",
340 osd_outputPath (fname),
341 cstring_fromChars (g_localSpecPath)));
346 inputStream specFile;
348 char *namePtr = actualName;
350 while (*namePtr == '.' && *(namePtr + 1) == CONNECTCHAR)
354 /*@noaccess cstring@*/
356 g_currentSpec = cstring_fromCharsNew (namePtr);
358 specFile = inputStream_create (cstring_copy (g_currentSpec),
359 LCL_EXTENSION, TRUE);
361 llassert (inputStream_isDefined (specFile));
363 g_currentSpecName = specFullName
364 (cstring_toCharsSafe (g_currentSpec),
369 displayScan (message ("reading spec %s", g_currentSpec));
371 /* Open the source file */
373 if (!inputStream_open (specFile))
375 lldiagmsg (message ("Cannot open file: %q",
376 osd_outputPath (inputStream_fileName (specFile))));
377 inputStream_free (specFile);
381 scopeInfo dummy_scope = (scopeInfo) dmalloc (sizeof (*dummy_scope));
382 dummy_scope->kind = SPE_INVALID;
385 LCLScanReset (specFile);
388 ** Minor hacks to allow more than one LCL file to
389 ** be scanned, while keeping initializations
392 symtable_enterScope (g_symtab, dummy_scope);
393 resetImports (cstring_fromChars (g_currentSpecName));
394 context_enterLCLfile ();
395 (void) lclHadNewError ();
397 parser_status = (ylparse () != 0);
398 context_exitLCLfile ();
400 overallStatus = parser_status || lclHadNewError ();
402 if (context_getFlag (FLG_DOLCS))
406 outputLCSFile (path, "%FAILED Output from ",
411 outputLCSFile (path, "%PASSED Output from ",
416 (void) inputStream_close (specFile);
417 inputStream_free (specFile);
419 symtable_exitScope (g_symtab);
422 cstring_free (actualName);
423 } end_fileIdList_elements;
425 /* Can cleanup lsl stuff right away */
429 g_currentSpec = cstring_undefined;
430 g_currentSpecName = NULL;
434 static void handlePassThroughFlag (char *arg)
437 char *quotechar = strchr (curarg, '\"');
440 char *freearg = NULL;
442 while (quotechar != NULL)
444 if (*(quotechar - 1) == '\\')
446 char *tp = quotechar - 2;
457 curarg = quotechar + 1;
458 quotechar = strchr (curarg, '\"');
463 llassert (quotechar != NULL);
465 offset = (quotechar - arg) + 2;
469 arg = cstring_toCharsSafe
470 (message ("%s\"\'%s",
471 cstring_fromChars (arg),
472 cstring_fromChars (quotechar + 1)));
478 arg = cstring_toCharsSafe
479 (message ("%s\'\"%s",
480 cstring_fromChars (arg),
481 cstring_fromChars (quotechar + 1)));
486 curarg = arg + offset;
487 quotechar = strchr (curarg, '\"');
493 voptgenerror (FLG_BADFLAG,
494 message ("Unclosed quote in flag: %s",
495 cstring_fromChars (arg)),
504 ** If the value is surrounded by single quotes ('), remove
505 ** them. This is an artifact of UNIX command line?
508 def = osd_fixDefine (cstring_fromChars (arg + 1));
509 DPRINTF (("Do define: %s", def));
511 DPRINTF (("After define"));
513 } else if (arg[0] == 'U') {
514 cppDoUndefine (cstring_fromChars (arg + 1));
523 void showHerald (void)
525 if (hasShownHerald || context_getFlag (FLG_QUIET))
531 fprintf (g_messagestream, "%s\n\n", SPLINT_VERSION);
532 hasShownHerald = TRUE;
537 static cstring findLarchPathFile (/*@temp@*/ cstring s)
542 status = osd_getPath (context_getLarchPath (), s, &pathName);
544 if (status == OSD_FILEFOUND)
548 else if (status == OSD_FILENOTFOUND)
551 lldiagmsg (message ("Cannot find file on LARCH_PATH: %s", s));
553 else if (status == OSD_PATHTOOLONG)
555 /* Directory and filename are too long. Report error. */
556 llbuglit ("soure_getPath: Filename plus directory from search path too long");
563 return cstring_undefined;
566 static void addLarchPathFile (fileIdList files, /*@temp@*/ cstring s)
568 cstring pathName = findLarchPathFile (s);
570 if (cstring_isDefined (pathName))
572 if (fileTable_exists (context_fileTable (), pathName))
575 lldiagmsg (message ("File listed multiple times: %s", pathName));
576 cstring_free (pathName);
580 fileIdList_add (files, fileTable_addFileOnly (context_fileTable (), pathName));
585 static void addFile (fileIdList files, /*@only@*/ cstring s)
587 if (fileTable_exists (context_fileTable (), s))
590 lldiagmsg (message ("File listed multiple times: %s", s));
595 fileIdList_add (files, fileTable_addFileOnly (context_fileTable (), s));
599 static void addXHFile (fileIdList files, /*@temp@*/ cstring s)
601 cstring pathName = findLarchPathFile (s);
603 if (cstring_isDefined (pathName))
605 if (fileTable_exists (context_fileTable (), pathName))
608 lldiagmsg (message ("File listed multiple times: %s", s));
612 fileIdList_add (files, fileTable_addXHFile (context_fileTable (), pathName));
616 cstring_free (pathName);
620 ** Disable MSVC++ warning about return value. Methinks humbly splint control
621 ** comments are a mite more legible.
625 # pragma warning (disable:4035)
628 int main (int argc, char *argv[])
630 /*@globals killed undef g_currentloc,
632 undef g_warningstream, g_messagestream, g_errorstream;
634 /*@modifies g_currentloc, fileSystem,
638 /*@globals killed undef g_currentloc,
639 killed undef initFile,
640 killed g_localSpecPath,
641 killed undef g_currentSpec,
642 killed undef g_currentSpecName,
644 undef g_warningstream, g_messagestream, g_errorstream;
646 /*@modifies g_currentloc, initFile,
647 g_localSpecPath, g_currentSpec, g_currentSpecName, fileSystem,
652 bool first_time = TRUE;
653 bool showhelp = FALSE;
656 inputStream sourceFile = inputStream_undefined;
658 fileIdList dercfiles;
659 cstringSList fl = cstringSList_undefined;
660 cstringSList passThroughArgs = cstringSList_undefined;
661 fileIdList cfiles, xfiles, lclfiles, mtfiles;
662 clock_t before, lcltime, libtime, pptime, cptime, rstime;
666 _wildcard (&argc, &argv);
669 g_warningstream = stdout;
670 g_messagestream = stderr;
671 g_errorstream = stderr;
673 (void) signal (SIGINT, interrupt);
674 (void) signal (SIGSEGV, interrupt);
676 cfiles = fileIdList_create ();
677 xfiles = fileIdList_create ();
678 lclfiles = fileIdList_create ();
679 mtfiles = fileIdList_create ();
682 clabstract_initMod ();
683 typeIdSet_initMod ();
684 cppReader_initMod ();
689 g_currentloc = fileloc_createBuiltin ();
694 context_setInCommandLine ();
706 ** Add include directories from environment.
710 cstring incval = cstring_copy (osd_getEnvironmentVariable (INCLUDEPATH_VAR));
711 cstring oincval = incval;
713 if (cstring_isDefined (incval))
716 ** Each directory on the include path is a system include directory.
719 DPRINTF (("include: %s", incval));
720 context_setString (FLG_SYSTEMDIRS, cstring_copy (incval));
722 while (cstring_isDefined (incval))
725 char *nextsep = strchr (incval, PATH_SEPARATOR);
731 dir = cstring_copy (incval);
733 if (cstring_length (dir) == 0
734 || !isalpha ((int) cstring_firstChar (dir)))
737 ** win32 environment values can have special values,
743 cppAddIncludeDir (dir);
746 *nextsep = PATH_SEPARATOR;
747 incval = cstring_fromChars (nextsep + 1);
755 /*@noaccess cstring@*/
758 else /* 2001-09-09: herbert */
760 /* Put C_INCLUDE_PATH directories in sysdirs */
761 cstring cincval = osd_getEnvironmentVariable (cstring_makeLiteralTemp ("C_INCLUDE_PATH"));
762 if (cstring_isDefined (cincval))
764 context_setString (FLG_SYSTEMDIRS, cstring_copy (cincval));
769 cstring_free (oincval);
773 ** check RCFILE for default flags
777 cstring home = osd_getHomeDir ();
778 cstring fname = cstring_undefined;
779 bool defaultf = TRUE;
782 for (i = 1; i < argc; i++)
787 if (*thisarg == '-' || *thisarg == '+')
789 bool set = (*thisarg == '+');
795 ** Don't report warnings this time
798 opt = flags_identifyFlagQuiet (cstring_fromChars (thisarg));
804 else if (flagcode_isMessageControlFlag (opt))
807 ** Need to set it immediately, so rc file scan is displayed
810 context_userSetFlag (opt, set);
812 if (flagcode_hasArgument (opt))
814 llassert (flagcode_hasString (opt));
818 fname = cstring_fromChars (argv[i]);
819 setStringFlag (opt, fname);
825 ("Flag %s must be followed by a string",
826 flagcode_unparse (opt)));
830 else if (opt == FLG_OPTF)
835 fname = cstring_fromChars (argv[i]);
836 (void) readOptionsFile (fname, &passThroughArgs, TRUE);
840 (cstring_makeLiteral ("Flag f to select options file "
841 "requires an argument"));
845 ; /* wait to process later */
852 if (!nof && defaultf)
855 ** No explicit rc file, first try reading ~/.splintrc
858 if (cstring_isUndefined (fname))
860 if (!cstring_isEmpty (home))
862 bool readhomerc, readaltrc;
863 cstring homename, altname;
865 homename = message ("%s%h%s", home, CONNECTCHAR,
866 cstring_fromChars (RCFILE));
867 readhomerc = readOptionsFile (homename, &passThroughArgs, FALSE);
870 ** Try ~/.splintrc also for historical accuracy
873 altname = message ("%s%h%s", home, CONNECTCHAR,
874 cstring_fromChars (ALTRCFILE));
875 readaltrc = readOptionsFile (altname, &passThroughArgs, FALSE);
877 if (readhomerc && readaltrc)
882 message ("Found both %s and %s files. Using both files, "
883 "but recommend using only %s to avoid confusion.",
884 homename, altname, homename),
888 cstring_free (homename);
889 cstring_free (altname);
894 ** Next, read .splintrc in the current working directory
898 cstring rcname = message ("%s%s",osd_getCurrentDirectory (), cstring_fromChars (RCFILE));
899 cstring altname = message ("%s%s",osd_getCurrentDirectory (), cstring_fromChars (ALTRCFILE));
900 bool readrc, readaltrc;
902 readrc = readOptionsFile (rcname, &passThroughArgs, FALSE);
903 readaltrc = readOptionsFile (altname, &passThroughArgs, FALSE);
905 if (readrc && readaltrc)
907 voptgenerror (FLG_WARNRC,
908 message ("Found both %s and %s files. Using both files, "
909 "but recommend using only %s to avoid confusion.",
910 rcname, altname, rcname),
915 cstring_free (rcname);
916 cstring_free (altname);
923 for (i = 1; i < argc; i++)
939 if (*thisarg == '-' || *thisarg == '+')
941 thisarg++; /* skip '-' */
943 if (mstring_equal (thisarg, "modes"))
945 llmsg (describeModes ());
947 else if (mstring_equal (thisarg, "vars")
948 || mstring_equal (thisarg, "env"))
952 else if (mstring_equal (thisarg, "annotations"))
956 else if (mstring_equal (thisarg, "parseerrors"))
960 else if (mstring_equal (thisarg, "comments"))
964 else if (mstring_equal (thisarg, "prefixcodes"))
966 describePrefixCodes ();
968 else if (mstring_equal (thisarg, "references")
969 || mstring_equal (thisarg, "refs"))
973 else if (mstring_equal (thisarg, "mail"))
977 else if (mstring_equal (thisarg, "maintainer")
978 || mstring_equal (thisarg, "version"))
982 else if (mstring_equal (thisarg, "flags"))
986 char *next = argv[i + 1];
988 if (specialFlagsHelp (next))
994 flagkind k = identifyCategory (cstring_fromChars (next));
1010 cstring s = describeFlag (cstring_fromChars (thisarg));
1012 if (cstring_isDefined (s))
1020 if (*thisarg == '-' || *thisarg == '+')
1022 bool set = (*thisarg == '+');
1025 thisarg++; /* skip '-' */
1026 flagname = cstring_fromChars (thisarg);
1028 DPRINTF (("Flag: %s", flagname));
1029 opt = flags_identifyFlag (flagname);
1030 DPRINTF (("Flag: %s", flagcode_unparse (opt)));
1032 if (flagcode_isMessageControlFlag (opt))
1035 ** Processed on first pass
1038 if (flagcode_hasArgument (opt))
1043 else if (flagcode_isInvalid (opt))
1045 DPRINTF (("Invalid: %s", flagname));
1047 if (isMode (flagname))
1049 context_setMode (flagname);
1053 DPRINTF (("Error!"));
1054 voptgenerror (FLG_BADFLAG,
1055 message ("Unrecognized option: %s",
1056 cstring_fromChars (thisarg)),
1062 context_userSetFlag (opt, set);
1064 if (flagcode_hasArgument (opt))
1066 if (opt == FLG_HELP)
1070 else if (flagcode_isPassThrough (opt)) /* -D or -U */
1072 passThroughArgs = cstringSList_add
1073 (passThroughArgs, cstring_fromChars (thisarg));
1075 else if (flagcode_hasNumber (opt))
1079 setValueFlag (opt, cstring_fromChars (argv[i]));
1085 ("Flag %s must be followed by a number",
1086 flagcode_unparse (opt)));
1089 else if (flagcode_hasChar (opt))
1093 setValueFlag (opt, cstring_fromChars (argv[i]));
1099 ("Flag %s must be followed by a character",
1100 flagcode_unparse (opt)));
1103 else if (opt == FLG_INCLUDEPATH || opt == FLG_SPECPATH)
1105 cstring dir = cstring_suffix (cstring_fromChars (thisarg), 1); /* skip over I */
1109 case FLG_INCLUDEPATH:
1110 cppAddIncludeDir (dir);
1111 /*@switchbreak@*/ break;
1114 g_localSpecPath = cstring_toCharsSafe
1116 cstring_fromChars (g_localSpecPath),
1120 /*@switchbreak@*/ break;
1124 else if (flagcode_hasString (opt)
1125 || opt == FLG_INIT || opt == FLG_OPTF)
1129 cstring arg = cstring_fromChars (argv[i]);
1131 if (opt == FLG_OPTF)
1133 ; /* -f already processed */
1135 else if (opt == FLG_INIT)
1138 initFile = inputStream_create
1140 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
1147 DPRINTF (("String flag: %s / %s",
1148 flagcode_unparse (opt), arg));
1149 if (opt == FLG_MTSFILE)
1152 ** arg identifies mts files
1154 cstring tmp = message ("%s%s", arg, MTS_EXTENSION);
1155 addLarchPathFile (mtfiles, tmp);
1157 tmp = message ("%s%s", arg, XH_EXTENSION);
1158 addXHFile (xfiles, tmp);
1163 setStringFlag (opt, cstring_copy (arg));
1171 ("Flag %s must be followed by a string",
1172 flagcode_unparse (opt)));
1182 else /* its a filename */
1184 DPRINTF (("Adding filename: %s", thisarg));
1185 fl = cstringSList_add (fl, cstring_fromChars (thisarg));
1193 ** create lists of C and LCL files
1196 cstringSList_elements (fl, current)
1198 cstring ext = fileLib_getExtension (current);
1200 if (cstring_isUndefined (ext))
1202 /* no extension --- both C and LCL with default extensions */
1204 addFile (cfiles, message ("%s%s", current, C_EXTENSION));
1205 addFile (lclfiles, message ("%s%s", current, LCL_EXTENSION));
1207 else if (cstring_equal (ext, XH_EXTENSION))
1209 addXHFile (xfiles, current);
1211 else if (cstring_equal (ext, PP_EXTENSION))
1213 if (!context_getFlag (FLG_NOPP))
1216 (FLG_FILEEXTENSIONS,
1217 message ("File extension %s used without +nopp flag (will be processed as C source code): %s",
1222 addFile (cfiles, cstring_copy (current));
1224 else if (cstring_equal (ext, LCL_EXTENSION))
1226 addFile (lclfiles, cstring_copy (current));
1228 else if (fileLib_isCExtension (ext))
1230 addFile (cfiles, cstring_copy (current));
1232 else if (cstring_equal (ext, MTS_EXTENSION))
1234 addLarchPathFile (mtfiles, current);
1239 (FLG_FILEEXTENSIONS,
1240 message ("Unrecognized file extension: %s (assuming %s is C source code)",
1244 addFile (cfiles, cstring_copy (current));
1246 } end_cstringSList_elements;
1254 fprintf (g_warningstream, "\n");
1256 fileIdList_free (cfiles);
1257 fileIdList_free (xfiles);
1258 fileIdList_free (lclfiles);
1267 inittime = clock ();
1269 context_resetErrors ();
1270 context_clearInCommandLine ();
1272 anylcl = !fileIdList_isEmpty (lclfiles);
1274 if (context_doMerge ())
1276 cstring m = context_getMerge ();
1278 displayScanOpen (message ("< loading %s ", m));
1280 displayScanClose ();
1282 if (!usymtab_existsType (context_getBoolName ()))
1284 usymtab_initBool ();
1289 if (!context_getFlag (FLG_NOLIB) && loadStandardState ())
1298 /* setup bool type and constants */
1299 usymtab_initBool ();
1302 fileloc_free (g_currentloc);
1303 g_currentloc = fileloc_createBuiltin ();
1306 ** Read metastate files (must happen before loading libraries)
1309 fileIdList_elements (mtfiles, mtfile)
1311 context_setFileId (mtfile);
1312 displayScan (message ("processing %s", fileTable_rootFileName (mtfile)));
1313 mtreader_readFile (cstring_copy (fileTable_fileName (mtfile)));
1314 } end_fileIdList_elements;
1321 llfatalerror (cstring_makeLiteral ("This version of Splint does not handle LCL files."));
1323 lslProcess (lclfiles);
1327 usymtab_initGlobalMarker ();
1332 ** call the pre-preprocessor and /lib/cpp to generate appropriate
1337 context_setInCommandLine ();
1339 DPRINTF (("Pass through: %s", cstringSList_unparse (passThroughArgs)));
1341 cstringSList_elements (passThroughArgs, thisarg) {
1342 handlePassThroughFlag (cstring_toCharsSafe (thisarg));
1343 } end_cstringSList_elements;
1345 cstringSList_free (passThroughArgs);
1349 DPRINTF (("Initializing cpp reader!"));
1350 cppReader_initialize ();
1351 cppReader_saveDefinitions ();
1353 context_clearInCommandLine ();
1355 if (!context_getFlag (FLG_NOPP))
1361 displayScanOpen (cstring_makeLiteral ("preprocessing"));
1365 context_setPreprocessing ();
1366 dercfiles = preprocessFiles (xfiles, TRUE);
1367 tfiles = preprocessFiles (cfiles, FALSE);
1368 warnSysFiles(cfiles);
1369 dercfiles = fileIdList_append (dercfiles, tfiles);
1370 fileIdList_free (tfiles);
1372 context_clearPreprocessing ();
1374 fileIdList_free (cfiles);
1376 displayScanClose ();
1382 dercfiles = fileIdList_append (cfiles, xfiles);
1387 ** now, check all the corresponding C files
1389 ** (for now these are just <file>.c, but after pre-processing
1390 ** will be <tmpprefix>.<file>.c)
1395 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1399 llbug (message ("Files unclosed: %d", nfiles));
1404 DPRINTF (("Initializing..."));
1406 exprNode_initMod ();
1408 DPRINTF (("Okay..."));
1410 fileIdList_elements (dercfiles, fid)
1412 sourceFile = inputStream_create (cstring_copy (fileTable_fileName (fid)), C_EXTENSION, TRUE);
1413 context_setFileId (fid);
1415 /* Open source file */
1417 if (inputStream_isUndefined (sourceFile) || (!inputStream_open (sourceFile)))
1419 /* previously, this was ignored ?! */
1420 llbug (message ("Could not open temp file: %s", fileTable_fileName (fid)));
1424 yyin = inputStream_getFile (sourceFile); /*< shared <- only */
1426 llassert (yyin != NULL);
1428 displayScan (message ("checking %q", osd_outputPath (fileTable_rootFileName (fid))));
1431 ** Every time, except the first time, through the loop,
1432 ** need to call yyrestart to clean up the parse buffer.
1437 (void) yyrestart (yyin);
1444 DPRINTF (("Entering..."));
1445 context_enterFile ();
1447 context_exitCFile ();
1449 (void) inputStream_close (sourceFile);
1451 } end_fileIdList_elements;
1455 /* process any leftover macros */
1457 context_processAllMacros ();
1459 /* check everything that was specified was defined */
1461 /* don't check if no c files were processed ?
1462 ** is this correct behaviour?
1465 displayScan (cstring_makeLiteral ("global checks"));
1469 if (context_getLinesProcessed () > 0)
1471 usymtab_allDefined ();
1474 if (context_maybeSet (FLG_TOPUNUSED))
1476 uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main"));
1478 if (uentry_isValid (ue))
1480 uentry_setUsed (ue, fileloc_observeBuiltin ());
1486 if (context_maybeSet (FLG_EXPORTLOCAL))
1488 usymtab_exportLocal ();
1492 if (context_maybeSet (FLG_EXPORTHEADER))
1494 usymtab_exportHeader ();
1497 if (context_getFlag (FLG_SHOWUSES))
1499 usymtab_displayAllUses ();
1502 context_checkSuppressCounts ();
1504 if (context_doDump ())
1506 cstring dump = context_getDump ();
1517 if (context_getFlag (FLG_SHOWSUMMARY))
1524 bool isQuiet = context_getFlag (FLG_QUIET);
1525 cstring specErrors = cstring_undefined;
1527 int nspecErrors = lclNumberErrors ();
1532 if (context_neednl ())
1533 fprintf (g_warningstream, "\n");
1536 if (nspecErrors > 0)
1538 if (nspecErrors == context_getLCLExpect ())
1541 message ("%d spec warning%&, as expected\n ",
1546 if (context_getLCLExpect () > 0)
1549 message ("%d spec warning%&, expected %d\n ",
1551 (int) context_getLCLExpect ());
1555 specErrors = message ("%d spec warning%&\n ",
1563 if (context_getLCLExpect () > 0)
1565 specErrors = message ("No spec warnings, expected %d\n ",
1566 (int) context_getLCLExpect ());
1572 if (context_anyErrors ())
1574 if (context_numErrors () == context_getExpect ())
1577 llmsg (message ("Finished checking --- "
1578 "%s%d code warning%&, as expected",
1579 specErrors, context_numErrors ()));
1584 if (context_getExpect () > 0)
1588 ("Finished checking --- "
1589 "%s%d code warning%&, expected %d",
1590 specErrors, context_numErrors (),
1591 (int) context_getExpect ()));
1601 llmsg (message ("Finished checking --- "
1602 "%s%d code warning%&",
1603 specErrors, context_numErrors ()));
1612 if (context_getExpect () > 0)
1616 ("Finished checking --- "
1617 "%sno code warnings, expected %d",
1619 (int) context_getExpect ()));
1626 if (context_getLinesProcessed () > 0)
1628 if (cstring_isEmpty (specErrors))
1632 llmsg (message ("Finished checking --- no warnings"));
1639 llmsg (message ("Finished checking --- %sno code warnings",
1647 llmsg (message ("Finished checking --- %sno code processed",
1654 cstring_free (specErrors);
1657 if (context_getFlag (FLG_STATS))
1659 clock_t ttime = clock () - before;
1660 int specLines = context_getSpecLinesProcessed ();
1666 fprintf (g_warningstream, "%d spec, ", specLines);
1669 # ifndef CLOCKS_PER_SEC
1670 fprintf (g_warningstream, "%d source lines in %ld time steps (steps/sec unknown)\n",
1671 context_getLinesProcessed (),
1674 fprintf (g_warningstream, "%d source lines in %.2f s.\n",
1675 context_getLinesProcessed (),
1676 (double) ttime / CLOCKS_PER_SEC);
1684 if (context_getFlag (FLG_TIMEDIST))
1686 clock_t ttime = clock () - before;
1690 char *msg = (char *) dmalloc (256 * sizeof (*msg));
1695 "Time distribution (percent): initialize %.2f / lcl %.2f / "
1696 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1697 (100.0 * (double) (libtime - before) / ttime),
1698 (100.0 * (double) (lcltime - libtime) / ttime),
1699 (100.0 * (double) (pptime - lcltime) / ttime),
1700 (100.0 * (double) (cptime - pptime) / ttime),
1701 (100.0 * (double) (rstime - cptime) / ttime));
1706 "Time distribution (percent): initialize %.2f / "
1707 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1708 (100.0 * (double) (libtime - before) / ttime),
1709 (100.0 * (double) (pptime - libtime) / ttime),
1710 (100.0 * (double) (cptime - pptime) / ttime),
1711 (100.0 * (double) (rstime - cptime) / ttime));
1714 llgenindentmsgnoloc (cstring_fromCharsO (msg));
1718 llexit (expsuccess ? LLSUCCESS : LLFAILURE);
1719 BADBRANCHRET (LLFAILURE);
1724 ** Reenable return value warnings.
1726 # pragma warning (default:4035)
1734 llmsg (message ("Source files are .c, .h and %s files. If there is no suffix,",
1736 llmsg (message (" Splint will look for <file>.c and <file>%s.", LCL_EXTENSION));
1738 llmsglit ("Use splint -help <topic or flag name> for more information");
1740 llmsglit ("Topics:");
1742 llmsglit (" annotations (describes source-code annotations)");
1743 llmsglit (" comments (describes control comments)");
1744 llmsglit (" flags (describes flag categories)");
1745 llmsglit (" flags <category> (describes flags in category)");
1746 llmsglit (" flags all (short description of all flags)");
1747 llmsglit (" flags alpha (list all flags alphabetically)");
1748 llmsglit (" flags full (full description of all flags)");
1749 llmsglit (" mail (information on mailing lists)");
1750 llmsglit (" modes (show mode settings)");
1751 llmsglit (" parseerrors (help on handling parser errors)");
1752 llmsglit (" prefixcodes (character codes in namespace prefixes)");
1753 llmsglit (" references (sources for more information)");
1754 llmsglit (" vars (environment variables)");
1755 llmsglit (" version (information on compilation, maintainer)");
1760 specialFlagsHelp (char *next)
1762 if ((next != NULL) && (*next != '-') && (*next != '+'))
1764 if (mstring_equal (next, "alpha"))
1769 else if (mstring_equal (next, "all"))
1771 printAllFlags (TRUE, FALSE);
1774 else if (mstring_equal (next, "categories")
1775 || mstring_equal (next, "cats"))
1777 listAllCategories ();
1780 else if (mstring_equal (next, "full"))
1782 printAllFlags (FALSE, TRUE);
1785 else if (mstring_equal (next, "manual"))
1787 printFlagManual (FALSE);
1790 else if (mstring_equal (next, "webmanual"))
1792 printFlagManual (TRUE);
1807 printParseErrors (void)
1809 llmsglit ("Parse Errors");
1810 llmsglit ("------------");
1812 llmsglit ("Splint will sometimes encounter a parse error for code that "
1813 "can be parsed with a local compiler. There are a few likely "
1814 "causes for this and a number of techniques that can be used "
1815 "to work around the problem.");
1817 llmsglit ("Compiler extensions --- compilers sometimes extend the C "
1818 "language with compiler-specific keywords and syntax. While "
1819 "it is not advisible to use these, oftentimes one has no choice "
1820 "when the system header files use compiler extensions. ");
1822 llmsglit ("Splint supports some of the GNU (gcc) compiler extensions, "
1823 "if the +gnuextensions flag is set. You may be able to workaround "
1824 "other compiler extensions by using a pre-processor define. "
1825 "Alternately, you can surround the unparseable code with");
1827 llmsglit (" # ifndef S_SPLINT_S");
1829 llmsglit (" # endif");
1831 /* evans 2000-12-21 fixed typo reported by Jeroen Ruigrok/Asmodai */
1832 llmsglit ("Missing type definitions --- an undefined type name will usually "
1833 "lead to a parse error. This often occurs when a standard header "
1834 "file defines some type that is not part of the standard library. ");
1835 llmsglit ("By default, Splint does not process the local files corresponding "
1836 "to standard library headers, but uses a library specification "
1837 "instead so dependencies on local system headers can be detected. "
1838 "If another system header file that does not correspond to a "
1839 "standard library header uses one of these superfluous types, "
1840 "a parse error will result.");
1842 llmsglit ("If the parse error is inside a posix standard header file, the "
1843 "first thing to try is +posixlib. This makes Splint use "
1844 "the posix library specification instead of reading the posix "
1847 llmsglit ("Otherwise, you may need to either manually define the problematic "
1848 "type (e.g., add -Dmlink_t=int to your .splintrc file) or force "
1849 "splint to process the header file that defines it. This is done "
1850 "by setting -skipisoheaders or -skipposixheaders before "
1851 "the file that defines the type is #include'd.");
1852 llmsglit ("(See splint -help "
1853 "skipisoheaders and splint -help skipposixheaders for a list of "
1854 "standard headers.) For example, if <sys/local.h> uses a type "
1855 "defined by posix header <sys/types.h> but not defined by the "
1856 "posix library, we might do: ");
1858 llmsglit (" /*@-skipposixheaders@*/");
1859 llmsglit (" # include <sys/types.h>");
1860 llmsglit (" /*@=skipposixheaders@*/");
1861 llmsglit (" # include <sys/local.h>");
1863 llmsglit ("to force Splint to process <sys/types.h>.");
1865 llmsglit ("At last resort, +trytorecover can be used to make Splint attempt "
1866 "to continue after a parse error. This is usually not successful "
1867 "and the author does not consider assertion failures when +trytorecover "
1868 "is used to be bugs.");
1872 printAnnotations (void)
1874 llmsglit ("Annotations");
1875 llmsglit ("-----------");
1877 llmsglit ("Annotations are semantic comments that document certain "
1878 "assumptions about functions, variables, parameters, and types. ");
1880 llmsglit ("They may be used to indicate where the representation of a "
1881 "user-defined type is hidden, to limit where a global variable may "
1882 "be used or modified, to constrain what a function implementation "
1883 "may do to its parameters, and to express checked assumptions about "
1884 "variables, types, structure fields, function parameters, and "
1885 "function results.");
1887 llmsglit ("Annotations are introduced by \"/*@\". The role of the @ may be "
1888 "played by any printable character, selected using -commentchar <char>.");
1890 llmsglit ("Consult the User's Guide for descriptions of checking associated with each annotation.");
1892 llmsglit ("Globals: (in function declarations)");
1893 llmsglit (" /*@globals <globitem>,+ @*/");
1894 llmsglit (" globitem is an identifier, internalState or fileSystem");
1896 llmsglit ("Modifies: (in function declarations)");
1897 llmsglit (" /*@modifies <moditem>,+ @*/");
1898 llmsglit (" moditem is an lvalue");
1899 llmsglit (" /*@modifies nothing @*/");
1900 llmsglit (" /*@*/ (Abbreviation for no globals and modifies nothing.)");
1902 llmsglit ("Iterators:");
1903 llmsglit (" /*@iter <identifier> (<parameter-type-list>) @*/ - declare an iterator");
1905 llmsglit ("Constants:");
1906 llmsglit (" /*@constant <declaration> @*/ - declares a constant");
1908 llmsglit ("Alternate Types:");
1909 llmsglit (" /*@alt <basic-type>,+ @*/");
1910 llmsglit (" (e.g., int /*@alt char@*/ is a type matching either int or char)");
1912 llmsglit ("Declarator Annotations");
1914 llmsglit ("Type Definitions:");
1915 llmsglit (" /*@abstract@*/ - representation is hidden from clients");
1916 llmsglit (" /*@concrete@*/ - representation is visible to clients");
1917 llmsglit (" /*@immutable@*/ - instances of the type cannot change value");
1918 llmsglit (" /*@mutable@*/ - instances of the type can change value");
1919 llmsglit (" /*@refcounted@*/ - reference counted type");
1921 llmsglit ("Global Variables:");
1922 llmsglit (" /*@unchecked@*/ - weakest checking for global use");
1923 llmsglit (" /*@checkmod@*/ - check modification by not use of global");
1924 llmsglit (" /*@checked@*/ - check use and modification of global");
1925 llmsglit (" /*@checkedstrict@*/ - check use of global strictly");
1927 llmsglit ("Memory Management:");
1928 llmsglit (" /*@dependent@*/ - a reference to externally-owned storage");
1929 llmsglit (" /*@keep@*/ - a parameter that is kept by the called function");
1930 llmsglit (" /*@killref@*/ - a refcounted parameter, killed by the call");
1931 llmsglit (" /*@only@*/ - an unshared reference");
1932 llmsglit (" /*@owned@*/ - owner of storage that may be shared by /*@dependent@*/ references");
1933 llmsglit (" /*@shared@*/ - shared reference that is never deallocated");
1934 llmsglit (" /*@temp@*/ - temporary parameter");
1936 llmsglit ("Aliasing:");
1937 llmsglit (" /*@unique@*/ - may not be aliased by any other visible reference");
1938 llmsglit (" /*@returned@*/ - may be aliased by the return value");
1940 llmsglit ("Exposure:");
1941 llmsglit (" /*@observer@*/ - reference that cannot be modified");
1942 llmsglit (" /*@exposed@*/ - exposed reference to storage in another object");
1944 llmsglit ("Definition State:");
1945 llmsglit (" /*@out@*/ - storage reachable from reference need not be defined");
1946 llmsglit (" /*@in@*/ - all storage reachable from reference must be defined");
1947 llmsglit (" /*@partial@*/ - partially defined, may have undefined fields");
1948 llmsglit (" /*@reldef@*/ - relax definition checking");
1950 llmsglit ("Global State: (for globals lists, no /*@, since list is already in /*@\'s)");
1951 llmsglit (" undef - variable is undefined before the call");
1952 llmsglit (" killed - variable is undefined after the call");
1954 llmsglit ("Null State:");
1955 llmsglit (" /*@null@*/ - possibly null pointer");
1956 llmsglit (" /*@notnull@*/ - definitely non-null pointer");
1957 llmsglit (" /*@relnull@*/ - relax null checking");
1959 llmsglit ("Null Predicates:");
1960 llmsglit (" /*@nullwhentrue@*/ - if result is TRUE, first parameter is NULL");
1961 llmsglit (" /*@falsewhennull@*/ - if result is TRUE, first parameter is not NULL");
1963 llmsglit ("Execution:");
1964 llmsglit (" /*@noreturn@*/ - function never returns");
1965 llmsglit (" /*@maynotreturn@*/ - function may or may not return");
1966 llmsglit (" /*@noreturnwhentrue@*/ - function does not return if first parameter is TRUE");
1967 llmsglit (" /*@noreturnwhenfalse@*/ - function does not return if first parameter if FALSE");
1968 llmsglit (" /*@alwaysreturns@*/ - function always returns");
1970 llmsglit ("Side-Effects:");
1971 llmsglit (" /*@sef@*/ - corresponding actual parameter has no side effects");
1973 llmsglit ("Declaration:");
1974 llmsglit (" /*@unused@*/ - need not be used (no unused errors reported)");
1975 llmsglit (" /*@external@*/ - defined externally (no undefined error reported)");
1978 llmsglit (" /*@fallthrough@*/ - fall-through case");
1980 llmsglit ("Break:");
1981 llmsglit (" /*@innerbreak@*/ - break is breaking an inner loop or switch");
1982 llmsglit (" /*@loopbreak@*/ - break is breaking a loop");
1983 llmsglit (" /*@switchbreak@*/ - break is breaking a switch");
1984 llmsglit (" /*@innercontinue@*/ - continue is continuing an inner loop");
1986 llmsglit ("Unreachable Code:");
1987 llmsglit (" /*@notreached@*/ - statement may be unreachable.");
1989 llmsglit ("Special Functions:");
1990 llmsglit (" /*@printflike@*/ - check variable arguments like printf");
1991 llmsglit (" /*@scanflike@*/ - check variable arguments like scanf");
1995 printComments (void)
1997 llmsglit ("Control Comments");
1998 llmsglit ("----------------");
2000 llmsglit ("Setting Flags");
2002 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.");
2004 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,");
2005 llmsglit (" /*@+boolint -modifies =showfunc@*/");
2006 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).");
2008 llmsglit ("Error Suppression");
2010 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.");
2012 llmsglit ("/*@ignore@*/ ... /*@end@*/");
2014 (cstring_makeLiteral
2015 ("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."));
2016 llmsglit ("/*@i@*/");
2018 (cstring_makeLiteral
2019 ("No errors will be reported from an /*@i@*/ comment to the end of the line."));
2020 llmsglit ("/*@i<n>@*/");
2022 (cstring_makeLiteral
2023 ("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."));
2024 llmsglit ("/*@t@*/, /*@t<n>@*/");
2026 (cstring_makeLiteral
2027 ("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."));
2029 llmsglit ("Type Access");
2031 llmsglit ("/*@access <type>@*/");
2032 llmsglit (" Allows the following code to access the representation of <type>");
2033 llmsglit ("/*@noaccess <type>@*/");
2034 llmsglit (" Hides the representation of <type>");
2036 llmsglit ("Macro Expansion");
2038 llmsglit ("/*@notfunction@*/");
2040 (cstring_makeLiteral
2041 ("Indicates that the next macro definition is not intended to be a "
2042 "function, and should be expanded in line instead of checked as a "
2043 "macro function definition."));
2050 llmsglit ("Flag Categories");
2051 llmsglit ("---------------");
2052 listAllCategories ();
2053 llmsglit ("\nTo see the flags in a flag category, do\n splint -help flags <category>");
2054 llmsglit ("To see a list of all flags in alphabetical order, do\n splint -help flags alpha");
2055 llmsglit ("To see a full description of all flags, do\n splint -help flags full");
2059 printMaintainer (void)
2061 llmsg (message ("Maintainer: %s", cstring_makeLiteralTemp (SPLINT_MAINTAINER)));
2062 llmsglit (LCL_COMPILE);
2068 llmsglit ("Mailing Lists");
2069 llmsglit ("-------------");
2071 llmsglit ("There are two mailing lists associated with Splint: ");
2073 llmsglit (" lclint-announce@virginia.edu");
2075 llmsglit (" Reserved for announcements of new releases and bug fixes.");
2076 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
2077 llmsglit (" subscribe lclint-announce");
2079 llmsglit (" lclint-interest@virginia.edu");
2081 llmsglit (" Informal discussions on the use and development of Splint.");
2082 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
2083 llmsglit (" subscribe lclint-interest");
2087 printReferences (void)
2089 llmsglit ("References");
2090 llmsglit ("----------");
2092 llmsglit ("For more information, see the Splint web site: http://www.splint.org");
2096 describePrefixCodes (void)
2098 llmsglit ("Prefix Codes");
2099 llmsglit ("------------");
2101 llmsglit ("These characters have special meaning in name prefixes:");
2103 llmsg (message (" %h Any uppercase letter [A-Z]", PFX_UPPERCASE));
2104 llmsg (message (" %h Any lowercase letter [a-z]", PFX_LOWERCASE));
2105 llmsg (message (" %h Any character (valid in a C identifier)", PFX_ANY));
2106 llmsg (message (" %h Any digit [0-9]", PFX_DIGIT));
2107 llmsg (message (" %h Any non-uppercase letter [a-z0-9_]", PFX_NOTUPPER));
2108 llmsg (message (" %h Any non-lowercase letter [A-Z0-9_]", PFX_NOTLOWER));
2109 llmsg (message (" %h Any letter [A-Za-z]", PFX_ANYLETTER));
2110 llmsg (message (" %h Any letter or digit [A-Za-z0-9]", PFX_ANYLETTERDIGIT));
2111 llmsglit (" * Zero or more repetitions of the previous character class until the end of the name");
2120 eval = context_getLarchPath ();
2121 def = osd_getEnvironmentVariable (LARCH_PATH);
2123 if (cstring_isDefined (def) ||
2124 !cstring_equal (eval, cstring_fromChars (DEFAULT_LARCHPATH)))
2126 llmsg (message ("LARCH_PATH = %s", eval));
2130 llmsg (message ("LARCH_PATH = <not set> (default = %s)",
2131 cstring_fromChars (DEFAULT_LARCHPATH)));
2134 llmsglit (" --- path used to find larch initialization files and LSL traits");
2136 eval = context_getLCLImportDir ();
2137 def = osd_getEnvironmentVariable (cstring_makeLiteralTemp (LCLIMPORTDIR));
2139 if (cstring_isDefined (def) ||
2140 !cstring_equal (eval, cstring_fromChars (DEFAULT_LCLIMPORTDIR)))
2142 llmsg (message ("%q = %s", cstring_makeLiteral (LCLIMPORTDIR), eval));
2146 llmsg (message ("%s = <not set, default: %s>", cstring_makeLiteralTemp (LCLIMPORTDIR),
2147 cstring_makeLiteralTemp (DEFAULT_LCLIMPORTDIR)));
2150 llmsglit (" --- directory containing lcl standard library files "
2151 "(import with < ... >)");;
2154 ("include path = %q (set by environment variable %s and -I flags)",
2155 cppReader_getIncludePath (), INCLUDEPATH_VAR));
2157 llmsglit (" --- path used to find #include'd files");
2160 ("systemdirs = %s (set by -systemdirs or environment variable %s)", /*@i413223@*/
2161 context_getString (FLG_SYSTEMDIRS),
2164 llmsglit (" --- if file is found on this path, it is treated as a system file for error reporting");
2173 fprintf (g_errorstream, "*** Interrupt\n");
2174 llexit (LLINTERRUPT);
2179 /* Cheat when there are parse errors */
2182 fprintf (g_errorstream, "*** Segmentation Violation\n");
2184 /* Don't catch it if fileloc_unparse causes a signal */
2185 (void) signal (SIGSEGV, NULL);
2187 loc = fileloc_unparse (g_currentloc);
2189 fprintf (g_errorstream, "*** Location (not trusted): %s\n",
2190 cstring_toCharsSafe (loc));
2193 fprintf (g_errorstream, "*** Please report bug to %s\n", SPLINT_MAINTAINER);
2197 fprintf (g_errorstream, "*** Signal: %d\n", i);
2199 fprintf (g_errorstream, "*** Location (not trusted): %s\n",
2200 cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
2203 fprintf (g_errorstream, "*** Please report bug to %s ***\n", SPLINT_MAINTAINER);
2211 static bool doneCleanup = FALSE;
2213 /* make sure this is only called once! */
2215 if (doneCleanup) return;
2220 ** Close all open files
2221 ** (There should only be open files, if we exited after a fatal error.)
2224 fileTable_closeAll (context_fileTable ());
2226 if (context_getFlag (FLG_KEEP))
2228 check (fputs ("Temporary files kept:\n", g_messagestream) != EOF);
2229 fileTable_printTemps (context_fileTable ());
2234 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
2238 llbug (message ("Files unclosed: %d", nfiles));
2241 fileTable_cleanup (context_fileTable ());
2248 ** cleans up temp files (if necessary) and exits
2254 DPRINTF (("llexit: %d", status));
2257 if (status == LLFAILURE)
2265 if (status != LLFAILURE)
2267 context_destroyMod ();
2268 exprNode_destroyMod ();
2271 uentry_destroyMod ();
2272 typeIdSet_destroyMod ();
2275 dmalloc_shutdown ();
2279 exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
2282 bool readOptionsFile (cstring fname, cstringSList *passThroughArgs, bool report)
2286 if (fileTable_exists (context_fileTable (), fname))
2292 message ("Multiple attempts to read options file: %s", fname),
2298 FILE *innerf = fileTable_openReadFile (context_fileTable (), fname);
2302 fileloc fc = g_currentloc;
2303 g_currentloc = fileloc_createRc (fname);
2305 displayScan (message ("< reading options from %q >",
2306 fileloc_outputFilename (g_currentloc)));
2308 loadrc (innerf, passThroughArgs);
2309 fileloc_reallyFree (g_currentloc);
2319 message ("Cannot open options file: %s", fname),
2329 ** This shouldn't be necessary, but Apple Darwin can't handle '"''s.
2333 loadrc (/*:open:*/ FILE *rcfile, cstringSList *passThroughArgs)
2334 /*@modifies rcfile@*/
2335 /*@ensures closed rcfile@*/
2337 char *s = mstring_create (MAX_LINE_LENGTH);
2340 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2344 while (reader_readLine (rcfile, s, MAX_LINE_LENGTH) != NULL)
2351 DPRINTF (("Line: %s", s));
2352 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2354 while (*s == ' ' || *s == '\t')
2362 bool escaped = FALSE;
2363 bool quoted = FALSE;
2366 DPRINTF (("Process: %s", s));
2367 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2368 /* comment characters */
2369 if (c == '#' || c == ';' || c == '\n')
2375 if (c == '-' || c == '+')
2382 voptgenerror (FLG_BADFLAG,
2383 message ("Bad flag syntax (+ or - expected, "
2384 "+ is assumed): %s",
2385 cstring_fromChars (s)),
2396 while ((c = *s) != '\0')
2397 { /* remember to handle spaces and quotes in -D and -U ... */
2423 if (c == ' ' || c == '\t' || c == '\n')
2425 /*@innerbreak@*/ break;
2433 DPRINTF (("Nulling: %c", *s));
2436 if (mstring_isEmpty (thisflag))
2438 llfatalerror (message ("Missing flag: %s",
2439 cstring_fromChars (os)));
2442 DPRINTF (("Flag: %s", thisflag));
2444 opt = flags_identifyFlag (cstring_fromChars (thisflag));
2446 if (flagcode_isSkip (opt))
2450 else if (flagcode_isInvalid (opt))
2452 DPRINTF (("Invalid: %s", thisflag));
2454 if (isMode (cstring_fromChars (thisflag)))
2456 context_setMode (cstring_fromChars (thisflag));
2460 voptgenerror (FLG_BADFLAG,
2461 message ("Unrecognized option: %s",
2462 cstring_fromChars (thisflag)),
2468 context_userSetFlag (opt, set);
2470 if (flagcode_hasArgument (opt))
2472 if (opt == FLG_HELP)
2475 voptgenerror (FLG_BADFLAG,
2476 message ("Cannot use help in rc files"),
2479 else if (flagcode_isPassThrough (opt)) /* -D or -U */
2481 cstring arg = cstring_fromCharsNew (thisflag);
2482 cstring_markOwned (arg);
2483 *passThroughArgs = cstringSList_add (*passThroughArgs, arg);
2484 DPRINTF (("Pass through: %s",
2485 cstringSList_unparse (*passThroughArgs)));
2487 else if (opt == FLG_INCLUDEPATH
2488 || opt == FLG_SPECPATH)
2490 cstring dir = cstring_suffix (cstring_fromChars (thisflag), 1); /* skip over I/S */
2494 case FLG_INCLUDEPATH:
2495 cppAddIncludeDir (dir);
2496 /*@switchbreak@*/ break;
2499 g_localSpecPath = cstring_toCharsSafe
2500 (message ("%s:%s", cstring_fromChars (g_localSpecPath), dir));
2502 /*@switchbreak@*/ break;
2506 else if (flagcode_hasString (opt)
2507 || flagcode_hasNumber (opt)
2508 || flagcode_hasChar (opt)
2509 || opt == FLG_INIT || opt == FLG_OPTF)
2511 cstring extra = cstring_undefined;
2516 rest = mstring_copy (s);
2517 DPRINTF (("Here: rest = %s", rest));
2521 while ((rchar = *rest) != '\0'
2522 && (isspace ((int) rchar)))
2528 DPRINTF (("Yo: %s", rest));
2530 while ((rchar = *rest) != '\0'
2531 && !isspace ((int) rchar))
2533 extra = cstring_appendChar (extra, rchar);
2538 DPRINTF (("Yo: %s", extra));
2541 if (cstring_isUndefined (extra))
2547 ("Flag %s must be followed by an argument",
2548 flagcode_unparse (opt)),
2555 DPRINTF (("Here we are: %s", extra));
2557 if (flagcode_hasNumber (opt) || flagcode_hasChar (opt))
2559 DPRINTF (("Set value flag: %s", extra));
2560 setValueFlag (opt, extra);
2562 else if (opt == FLG_OPTF)
2564 (void) readOptionsFile (extra, passThroughArgs, TRUE);
2566 else if (opt == FLG_INIT)
2569 llassert (inputStream_isUndefined (initFile));
2571 initFile = inputStream_create
2572 (cstring_copy (extra),
2573 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
2577 else if (flagcode_hasString (opt))
2579 DPRINTF (("Here: %s", extra));
2582 ** If it has "'s, we need to remove them.
2585 if (cstring_firstChar (extra) == '\"')
2587 if (cstring_lastChar (extra) == '\"')
2589 cstring unquoted = cstring_copyLength
2590 (cstring_toCharsSafe (cstring_suffix (extra, 1)),
2591 cstring_length (extra) - 2);
2593 DPRINTF (("string flag: %s -> %s", extra, unquoted));
2594 setStringFlag (opt, unquoted);
2595 cstring_free (extra);
2601 message ("Unmatched \" in option string: %s",
2604 setStringFlag (opt, extra);
2609 DPRINTF (("No quotes: %s", extra));
2610 setStringFlag (opt, extra);
2613 extra = cstring_undefined;
2621 cstring_free (extra);
2631 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2632 while ((c == ' ') || (c == '\t'))
2638 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2642 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2644 check (fileTable_closeFile (context_fileTable (), rcfile));
2647 static fileIdList preprocessFiles (fileIdList fl, bool xhfiles)
2648 /*@modifies fileSystem@*/
2650 bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
2651 int skip = (fileIdList_size (fl) / 5);
2652 int filesprocessed = 0;
2653 fileIdList dfiles = fileIdList_create ();
2655 fileloc_free (g_currentloc);
2656 g_currentloc = fileloc_createBuiltin ();
2658 fileIdList_elements (fl, fid)
2660 cstring ppfname = fileTable_fileName (fid);
2662 if (!(osd_fileIsReadable (ppfname)))
2664 lldiagmsg (message ("Cannot open file: %q", osd_outputPath (ppfname)));
2665 ppfname = cstring_undefined;
2668 if (cstring_isDefined (ppfname))
2670 fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
2674 llassert (fileTable_isXHFile (context_fileTable (), dfile));
2677 llassert (cstring_isNonEmpty (ppfname));
2681 if ((filesprocessed % skip) == 0)
2683 if (filesprocessed == 0) {
2684 fprintf (g_messagestream, " ");
2687 fprintf (g_messagestream, ".");
2690 (void) fflush (g_messagestream);
2695 DPRINTF (("outfile: %s", fileTable_fileName (dfile)));
2697 if (cppProcess (ppfname, fileTable_fileName (dfile)) != 0)
2699 llfatalerror (message ("Preprocessing error for file: %s",
2700 fileTable_rootFileName (fid)));
2703 fileIdList_add (dfiles, dfile);
2705 } end_fileIdList_elements;
2710 /* This should be in an lclUtils.c file... */
2712 char *specFullName (char *specfile, /*@out@*/ char **inpath)
2714 /* extract the path and the specname associated with the given file */
2715 char *specname = (char *) dmalloc (sizeof (*specname)
2716 * (strlen (specfile) + 9));
2717 char *ospecname = specname;
2718 char *path = (char *) dmalloc (sizeof (*path) * (strlen (specfile)));
2722 /* initialized path to empty string or may have accidental garbage */
2725 /*@-mayaliasunique@*/
2726 strcpy (specname, specfile);
2727 /*@=mayaliasunique@*/
2729 /* trim off pathnames in specfile */
2730 size = strlen (specname);
2732 for (i = size_toInt (size) - 1; i >= 0; i--)
2734 if (specname[i] == CONNECTCHAR)
2736 /* strcpy (specname, (char *)specname+i+1); */
2737 for (j = 0; j <= i; j++) /* include '/' */
2739 path[j] = specname[j];
2749 ** also remove .lcl file extension, assume it's the last extension
2753 size = strlen (specname);
2755 for (i = size_toInt (size) - 1; i >= 0; i--)
2757 if (specname[i] == '.')
2767 ** If specname no longer points to the original char,
2768 ** we need to allocate a new pointer and copy the string.
2771 if (specname != ospecname) {
2772 char *rspecname = (char *) dmalloc (sizeof (*rspecname) * (strlen (specname) + 1));
2773 strcpy (rspecname, specname); /* evs 2000-05-16: Bug: was ospecname! */
2782 void warnSysFiles(fileIdList files)
2784 fileIdList_elements (files, file)
2787 if (fileTable_isSystemFile (context_fileTable (), file) )
2789 if (!context_getFlag( FLG_SYSTEMDIRERRORS ) )
2791 voptgenerror (FLG_WARNSYSFILES, message ("Warning %s is a considered a system file. No errors in this file will be reported.", fileTable_rootFileName (file) ), g_currentloc);
2795 end_fileIdList_elements;