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));
1194 ** create lists of C and LCL files
1197 cstringSList_elements (fl, current)
1199 cstring ext = fileLib_getExtension (current);
1201 if (cstring_isUndefined (ext))
1203 /* no extension --- both C and LCL with default extensions */
1205 addFile (cfiles, message ("%s%s", current, C_EXTENSION));
1206 addFile (lclfiles, message ("%s%s", current, LCL_EXTENSION));
1208 else if (cstring_equal (ext, XH_EXTENSION))
1210 addXHFile (xfiles, current);
1212 else if (cstring_equal (ext, PP_EXTENSION))
1214 if (!context_getFlag (FLG_NOPP))
1217 (FLG_FILEEXTENSIONS,
1218 message ("File extension %s used without +nopp flag (will be processed as C source code): %s",
1223 addFile (cfiles, cstring_copy (current));
1225 else if (cstring_equal (ext, LCL_EXTENSION))
1227 addFile (lclfiles, cstring_copy (current));
1229 else if (fileLib_isCExtension (ext))
1231 addFile (cfiles, cstring_copy (current));
1233 else if (cstring_equal (ext, MTS_EXTENSION))
1235 addLarchPathFile (mtfiles, current);
1240 (FLG_FILEEXTENSIONS,
1241 message ("Unrecognized file extension: %s (assuming %s is C source code)",
1245 addFile (cfiles, cstring_copy (current));
1247 } end_cstringSList_elements;
1255 fprintf (g_warningstream, "\n");
1257 fileIdList_free (cfiles);
1258 fileIdList_free (xfiles);
1259 fileIdList_free (lclfiles);
1268 inittime = clock ();
1270 context_resetErrors ();
1271 context_clearInCommandLine ();
1273 anylcl = !fileIdList_isEmpty (lclfiles);
1275 if (context_doMerge ())
1277 cstring m = context_getMerge ();
1279 displayScanOpen (message ("< loading %s ", m));
1281 displayScanClose ();
1283 if (!usymtab_existsType (context_getBoolName ()))
1285 usymtab_initBool ();
1290 if (!context_getFlag (FLG_NOLIB) && loadStandardState ())
1299 /* setup bool type and constants */
1300 usymtab_initBool ();
1303 fileloc_free (g_currentloc);
1304 g_currentloc = fileloc_createBuiltin ();
1307 ** Read metastate files (must happen before loading libraries)
1310 fileIdList_elements (mtfiles, mtfile)
1312 context_setFileId (mtfile);
1313 displayScan (message ("processing %s", fileTable_rootFileName (mtfile)));
1314 mtreader_readFile (cstring_copy (fileTable_fileName (mtfile)));
1315 } end_fileIdList_elements;
1322 llfatalerror (cstring_makeLiteral ("This version of Splint does not handle LCL files."));
1324 lslProcess (lclfiles);
1328 usymtab_initGlobalMarker ();
1333 ** call the pre-preprocessor and /lib/cpp to generate appropriate
1338 context_setInCommandLine ();
1340 DPRINTF (("Pass through: %s", cstringSList_unparse (passThroughArgs)));
1342 cstringSList_elements (passThroughArgs, thisarg) {
1343 handlePassThroughFlag (cstring_toCharsSafe (thisarg));
1344 } end_cstringSList_elements;
1346 cstringSList_free (passThroughArgs);
1350 DPRINTF (("Initializing cpp reader!"));
1351 cppReader_initialize ();
1352 cppReader_saveDefinitions ();
1354 context_clearInCommandLine ();
1356 if (!context_getFlag (FLG_NOPP))
1362 displayScanOpen (cstring_makeLiteral ("preprocessing"));
1366 context_setPreprocessing ();
1367 dercfiles = preprocessFiles (xfiles, TRUE);
1368 tfiles = preprocessFiles (cfiles, FALSE);
1369 warnSysFiles(cfiles);
1370 dercfiles = fileIdList_append (dercfiles, tfiles);
1371 fileIdList_free (tfiles);
1373 context_clearPreprocessing ();
1375 fileIdList_free (cfiles);
1377 displayScanClose ();
1383 dercfiles = fileIdList_append (cfiles, xfiles);
1388 ** now, check all the corresponding C files
1390 ** (for now these are just <file>.c, but after pre-processing
1391 ** will be <tmpprefix>.<file>.c)
1396 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1400 llbug (message ("Files unclosed: %d", nfiles));
1405 DPRINTF (("Initializing..."));
1407 exprNode_initMod ();
1409 DPRINTF (("Okay..."));
1411 fileIdList_elements (dercfiles, fid)
1413 sourceFile = inputStream_create (cstring_copy (fileTable_fileName (fid)), C_EXTENSION, TRUE);
1414 context_setFileId (fid);
1416 /* Open source file */
1418 if (inputStream_isUndefined (sourceFile) || (!inputStream_open (sourceFile)))
1420 /* previously, this was ignored ?! */
1421 llbug (message ("Could not open temp file: %s", fileTable_fileName (fid)));
1425 yyin = inputStream_getFile (sourceFile); /*< shared <- only */
1427 llassert (yyin != NULL);
1429 displayScan (message ("checking %q", osd_outputPath (fileTable_rootFileName (fid))));
1432 ** Every time, except the first time, through the loop,
1433 ** need to call yyrestart to clean up the parse buffer.
1438 (void) yyrestart (yyin);
1445 DPRINTF (("Entering..."));
1446 context_enterFile ();
1448 context_exitCFile ();
1450 (void) inputStream_close (sourceFile);
1452 } end_fileIdList_elements;
1456 /* process any leftover macros */
1458 context_processAllMacros ();
1460 /* check everything that was specified was defined */
1462 /* don't check if no c files were processed ?
1463 ** is this correct behaviour?
1466 displayScan (cstring_makeLiteral ("global checks"));
1470 if (context_getLinesProcessed () > 0)
1472 usymtab_allDefined ();
1475 if (context_maybeSet (FLG_TOPUNUSED))
1477 uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main"));
1479 if (uentry_isValid (ue))
1481 uentry_setUsed (ue, fileloc_observeBuiltin ());
1487 if (context_maybeSet (FLG_EXPORTLOCAL))
1489 usymtab_exportLocal ();
1493 if (context_maybeSet (FLG_EXPORTHEADER))
1495 usymtab_exportHeader ();
1498 if (context_getFlag (FLG_SHOWUSES))
1500 usymtab_displayAllUses ();
1503 context_checkSuppressCounts ();
1505 if (context_doDump ())
1507 cstring dump = context_getDump ();
1518 if (context_getFlag (FLG_SHOWSUMMARY))
1525 bool isQuiet = context_getFlag (FLG_QUIET);
1526 cstring specErrors = cstring_undefined;
1528 int nspecErrors = lclNumberErrors ();
1533 if (context_neednl ())
1534 fprintf (g_warningstream, "\n");
1537 if (nspecErrors > 0)
1539 if (nspecErrors == context_getLCLExpect ())
1542 message ("%d spec warning%&, as expected\n ",
1547 if (context_getLCLExpect () > 0)
1550 message ("%d spec warning%&, expected %d\n ",
1552 (int) context_getLCLExpect ());
1556 specErrors = message ("%d spec warning%&\n ",
1564 if (context_getLCLExpect () > 0)
1566 specErrors = message ("No spec warnings, expected %d\n ",
1567 (int) context_getLCLExpect ());
1573 if (context_anyErrors ())
1575 if (context_numErrors () == context_getExpect ())
1578 llmsg (message ("Finished checking --- "
1579 "%s%d code warning%&, as expected",
1580 specErrors, context_numErrors ()));
1585 if (context_getExpect () > 0)
1589 ("Finished checking --- "
1590 "%s%d code warning%&, expected %d",
1591 specErrors, context_numErrors (),
1592 (int) context_getExpect ()));
1602 llmsg (message ("Finished checking --- "
1603 "%s%d code warning%&",
1604 specErrors, context_numErrors ()));
1613 if (context_getExpect () > 0)
1617 ("Finished checking --- "
1618 "%sno code warnings, expected %d",
1620 (int) context_getExpect ()));
1627 if (context_getLinesProcessed () > 0)
1629 if (cstring_isEmpty (specErrors))
1633 llmsg (message ("Finished checking --- no warnings"));
1640 llmsg (message ("Finished checking --- %sno code warnings",
1648 llmsg (message ("Finished checking --- %sno code processed",
1655 cstring_free (specErrors);
1658 if (context_getFlag (FLG_STATS))
1660 clock_t ttime = clock () - before;
1661 int specLines = context_getSpecLinesProcessed ();
1667 fprintf (g_warningstream, "%d spec, ", specLines);
1670 # ifndef CLOCKS_PER_SEC
1671 fprintf (g_warningstream, "%d source lines in %ld time steps (steps/sec unknown)\n",
1672 context_getLinesProcessed (),
1675 fprintf (g_warningstream, "%d source lines in %.2f s.\n",
1676 context_getLinesProcessed (),
1677 (double) ttime / CLOCKS_PER_SEC);
1685 if (context_getFlag (FLG_TIMEDIST))
1687 clock_t ttime = clock () - before;
1691 char *msg = (char *) dmalloc (256 * sizeof (*msg));
1696 "Time distribution (percent): initialize %.2f / lcl %.2f / "
1697 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1698 (100.0 * (double) (libtime - before) / ttime),
1699 (100.0 * (double) (lcltime - libtime) / ttime),
1700 (100.0 * (double) (pptime - lcltime) / ttime),
1701 (100.0 * (double) (cptime - pptime) / ttime),
1702 (100.0 * (double) (rstime - cptime) / ttime));
1707 "Time distribution (percent): initialize %.2f / "
1708 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1709 (100.0 * (double) (libtime - before) / ttime),
1710 (100.0 * (double) (pptime - libtime) / ttime),
1711 (100.0 * (double) (cptime - pptime) / ttime),
1712 (100.0 * (double) (rstime - cptime) / ttime));
1715 llgenindentmsgnoloc (cstring_fromCharsO (msg));
1719 llexit (expsuccess ? LLSUCCESS : LLFAILURE);
1720 BADBRANCHRET (LLFAILURE);
1725 ** Reenable return value warnings.
1727 # pragma warning (default:4035)
1735 llmsg (message ("Source files are .c, .h and %s files. If there is no suffix,",
1737 llmsg (message (" Splint will look for <file>.c and <file>%s.", LCL_EXTENSION));
1739 llmsglit ("Use splint -help <topic or flag name> for more information");
1741 llmsglit ("Topics:");
1743 llmsglit (" annotations (describes source-code annotations)");
1744 llmsglit (" comments (describes control comments)");
1745 llmsglit (" flags (describes flag categories)");
1746 llmsglit (" flags <category> (describes flags in category)");
1747 llmsglit (" flags all (short description of all flags)");
1748 llmsglit (" flags alpha (list all flags alphabetically)");
1749 llmsglit (" flags full (full description of all flags)");
1750 llmsglit (" mail (information on mailing lists)");
1751 llmsglit (" modes (show mode settings)");
1752 llmsglit (" parseerrors (help on handling parser errors)");
1753 llmsglit (" prefixcodes (character codes in namespace prefixes)");
1754 llmsglit (" references (sources for more information)");
1755 llmsglit (" vars (environment variables)");
1756 llmsglit (" version (information on compilation, maintainer)");
1761 specialFlagsHelp (char *next)
1763 if ((next != NULL) && (*next != '-') && (*next != '+'))
1765 if (mstring_equal (next, "alpha"))
1770 else if (mstring_equal (next, "all"))
1772 printAllFlags (TRUE, FALSE);
1775 else if (mstring_equal (next, "categories")
1776 || mstring_equal (next, "cats"))
1778 listAllCategories ();
1781 else if (mstring_equal (next, "full"))
1783 printAllFlags (FALSE, TRUE);
1786 else if (mstring_equal (next, "manual"))
1788 printFlagManual (FALSE);
1791 else if (mstring_equal (next, "webmanual"))
1793 printFlagManual (TRUE);
1808 printParseErrors (void)
1810 llmsglit ("Parse Errors");
1811 llmsglit ("------------");
1813 llmsglit ("Splint will sometimes encounter a parse error for code that "
1814 "can be parsed with a local compiler. There are a few likely "
1815 "causes for this and a number of techniques that can be used "
1816 "to work around the problem.");
1818 llmsglit ("Compiler extensions --- compilers sometimes extend the C "
1819 "language with compiler-specific keywords and syntax. While "
1820 "it is not advisible to use these, oftentimes one has no choice "
1821 "when the system header files use compiler extensions. ");
1823 llmsglit ("Splint supports some of the GNU (gcc) compiler extensions, "
1824 "if the +gnuextensions flag is set. You may be able to workaround "
1825 "other compiler extensions by using a pre-processor define. "
1826 "Alternately, you can surround the unparseable code with");
1828 llmsglit (" # ifndef S_SPLINT_S");
1830 llmsglit (" # endif");
1832 /* evans 2000-12-21 fixed typo reported by Jeroen Ruigrok/Asmodai */
1833 llmsglit ("Missing type definitions --- an undefined type name will usually "
1834 "lead to a parse error. This often occurs when a standard header "
1835 "file defines some type that is not part of the standard library. ");
1836 llmsglit ("By default, Splint does not process the local files corresponding "
1837 "to standard library headers, but uses a library specification "
1838 "instead so dependencies on local system headers can be detected. "
1839 "If another system header file that does not correspond to a "
1840 "standard library header uses one of these superfluous types, "
1841 "a parse error will result.");
1843 llmsglit ("If the parse error is inside a posix standard header file, the "
1844 "first thing to try is +posixlib. This makes Splint use "
1845 "the posix library specification instead of reading the posix "
1848 llmsglit ("Otherwise, you may need to either manually define the problematic "
1849 "type (e.g., add -Dmlink_t=int to your .splintrc file) or force "
1850 "splint to process the header file that defines it. This is done "
1851 "by setting -skipisoheaders or -skipposixheaders before "
1852 "the file that defines the type is #include'd.");
1853 llmsglit ("(See splint -help "
1854 "skipisoheaders and splint -help skipposixheaders for a list of "
1855 "standard headers.) For example, if <sys/local.h> uses a type "
1856 "defined by posix header <sys/types.h> but not defined by the "
1857 "posix library, we might do: ");
1859 llmsglit (" /*@-skipposixheaders@*/");
1860 llmsglit (" # include <sys/types.h>");
1861 llmsglit (" /*@=skipposixheaders@*/");
1862 llmsglit (" # include <sys/local.h>");
1864 llmsglit ("to force Splint to process <sys/types.h>.");
1866 llmsglit ("At last resort, +trytorecover can be used to make Splint attempt "
1867 "to continue after a parse error. This is usually not successful "
1868 "and the author does not consider assertion failures when +trytorecover "
1869 "is used to be bugs.");
1873 printAnnotations (void)
1875 llmsglit ("Annotations");
1876 llmsglit ("-----------");
1878 llmsglit ("Annotations are semantic comments that document certain "
1879 "assumptions about functions, variables, parameters, and types. ");
1881 llmsglit ("They may be used to indicate where the representation of a "
1882 "user-defined type is hidden, to limit where a global variable may "
1883 "be used or modified, to constrain what a function implementation "
1884 "may do to its parameters, and to express checked assumptions about "
1885 "variables, types, structure fields, function parameters, and "
1886 "function results.");
1888 llmsglit ("Annotations are introduced by \"/*@\". The role of the @ may be "
1889 "played by any printable character, selected using -commentchar <char>.");
1891 llmsglit ("Consult the User's Guide for descriptions of checking associated with each annotation.");
1893 llmsglit ("Globals: (in function declarations)");
1894 llmsglit (" /*@globals <globitem>,+ @*/");
1895 llmsglit (" globitem is an identifier, internalState or fileSystem");
1897 llmsglit ("Modifies: (in function declarations)");
1898 llmsglit (" /*@modifies <moditem>,+ @*/");
1899 llmsglit (" moditem is an lvalue");
1900 llmsglit (" /*@modifies nothing @*/");
1901 llmsglit (" /*@*/ (Abbreviation for no globals and modifies nothing.)");
1903 llmsglit ("Iterators:");
1904 llmsglit (" /*@iter <identifier> (<parameter-type-list>) @*/ - declare an iterator");
1906 llmsglit ("Constants:");
1907 llmsglit (" /*@constant <declaration> @*/ - declares a constant");
1909 llmsglit ("Alternate Types:");
1910 llmsglit (" /*@alt <basic-type>,+ @*/");
1911 llmsglit (" (e.g., int /*@alt char@*/ is a type matching either int or char)");
1913 llmsglit ("Declarator Annotations");
1915 llmsglit ("Type Definitions:");
1916 llmsglit (" /*@abstract@*/ - representation is hidden from clients");
1917 llmsglit (" /*@concrete@*/ - representation is visible to clients");
1918 llmsglit (" /*@immutable@*/ - instances of the type cannot change value");
1919 llmsglit (" /*@mutable@*/ - instances of the type can change value");
1920 llmsglit (" /*@refcounted@*/ - reference counted type");
1922 llmsglit ("Global Variables:");
1923 llmsglit (" /*@unchecked@*/ - weakest checking for global use");
1924 llmsglit (" /*@checkmod@*/ - check modification by not use of global");
1925 llmsglit (" /*@checked@*/ - check use and modification of global");
1926 llmsglit (" /*@checkedstrict@*/ - check use of global strictly");
1928 llmsglit ("Memory Management:");
1929 llmsglit (" /*@dependent@*/ - a reference to externally-owned storage");
1930 llmsglit (" /*@keep@*/ - a parameter that is kept by the called function");
1931 llmsglit (" /*@killref@*/ - a refcounted parameter, killed by the call");
1932 llmsglit (" /*@only@*/ - an unshared reference");
1933 llmsglit (" /*@owned@*/ - owner of storage that may be shared by /*@dependent@*/ references");
1934 llmsglit (" /*@shared@*/ - shared reference that is never deallocated");
1935 llmsglit (" /*@temp@*/ - temporary parameter");
1937 llmsglit ("Aliasing:");
1938 llmsglit (" /*@unique@*/ - may not be aliased by any other visible reference");
1939 llmsglit (" /*@returned@*/ - may be aliased by the return value");
1941 llmsglit ("Exposure:");
1942 llmsglit (" /*@observer@*/ - reference that cannot be modified");
1943 llmsglit (" /*@exposed@*/ - exposed reference to storage in another object");
1945 llmsglit ("Definition State:");
1946 llmsglit (" /*@out@*/ - storage reachable from reference need not be defined");
1947 llmsglit (" /*@in@*/ - all storage reachable from reference must be defined");
1948 llmsglit (" /*@partial@*/ - partially defined, may have undefined fields");
1949 llmsglit (" /*@reldef@*/ - relax definition checking");
1951 llmsglit ("Global State: (for globals lists, no /*@, since list is already in /*@\'s)");
1952 llmsglit (" undef - variable is undefined before the call");
1953 llmsglit (" killed - variable is undefined after the call");
1955 llmsglit ("Null State:");
1956 llmsglit (" /*@null@*/ - possibly null pointer");
1957 llmsglit (" /*@notnull@*/ - definitely non-null pointer");
1958 llmsglit (" /*@relnull@*/ - relax null checking");
1960 llmsglit ("Null Predicates:");
1961 llmsglit (" /*@nullwhentrue@*/ - if result is TRUE, first parameter is NULL");
1962 llmsglit (" /*@falsewhennull@*/ - if result is TRUE, first parameter is not NULL");
1964 llmsglit ("Execution:");
1965 llmsglit (" /*@noreturn@*/ - function never returns");
1966 llmsglit (" /*@maynotreturn@*/ - function may or may not return");
1967 llmsglit (" /*@noreturnwhentrue@*/ - function does not return if first parameter is TRUE");
1968 llmsglit (" /*@noreturnwhenfalse@*/ - function does not return if first parameter if FALSE");
1969 llmsglit (" /*@alwaysreturns@*/ - function always returns");
1971 llmsglit ("Side-Effects:");
1972 llmsglit (" /*@sef@*/ - corresponding actual parameter has no side effects");
1974 llmsglit ("Declaration:");
1975 llmsglit (" /*@unused@*/ - need not be used (no unused errors reported)");
1976 llmsglit (" /*@external@*/ - defined externally (no undefined error reported)");
1979 llmsglit (" /*@fallthrough@*/ - fall-through case");
1981 llmsglit ("Break:");
1982 llmsglit (" /*@innerbreak@*/ - break is breaking an inner loop or switch");
1983 llmsglit (" /*@loopbreak@*/ - break is breaking a loop");
1984 llmsglit (" /*@switchbreak@*/ - break is breaking a switch");
1985 llmsglit (" /*@innercontinue@*/ - continue is continuing an inner loop");
1987 llmsglit ("Unreachable Code:");
1988 llmsglit (" /*@notreached@*/ - statement may be unreachable.");
1990 llmsglit ("Special Functions:");
1991 llmsglit (" /*@printflike@*/ - check variable arguments like printf");
1992 llmsglit (" /*@scanflike@*/ - check variable arguments like scanf");
1996 printComments (void)
1998 llmsglit ("Control Comments");
1999 llmsglit ("----------------");
2001 llmsglit ("Setting Flags");
2003 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.");
2005 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,");
2006 llmsglit (" /*@+boolint -modifies =showfunc@*/");
2007 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).");
2009 llmsglit ("Error Suppression");
2011 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.");
2013 llmsglit ("/*@ignore@*/ ... /*@end@*/");
2015 (cstring_makeLiteral
2016 ("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."));
2017 llmsglit ("/*@i@*/");
2019 (cstring_makeLiteral
2020 ("No errors will be reported from an /*@i@*/ comment to the end of the line."));
2021 llmsglit ("/*@i<n>@*/");
2023 (cstring_makeLiteral
2024 ("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."));
2025 llmsglit ("/*@t@*/, /*@t<n>@*/");
2027 (cstring_makeLiteral
2028 ("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."));
2030 llmsglit ("Type Access");
2032 llmsglit ("/*@access <type>@*/");
2033 llmsglit (" Allows the following code to access the representation of <type>");
2034 llmsglit ("/*@noaccess <type>@*/");
2035 llmsglit (" Hides the representation of <type>");
2037 llmsglit ("Macro Expansion");
2039 llmsglit ("/*@notfunction@*/");
2041 (cstring_makeLiteral
2042 ("Indicates that the next macro definition is not intended to be a "
2043 "function, and should be expanded in line instead of checked as a "
2044 "macro function definition."));
2051 llmsglit ("Flag Categories");
2052 llmsglit ("---------------");
2053 listAllCategories ();
2054 llmsglit ("\nTo see the flags in a flag category, do\n splint -help flags <category>");
2055 llmsglit ("To see a list of all flags in alphabetical order, do\n splint -help flags alpha");
2056 llmsglit ("To see a full description of all flags, do\n splint -help flags full");
2060 printMaintainer (void)
2062 llmsg (message ("Maintainer: %s", cstring_makeLiteralTemp (SPLINT_MAINTAINER)));
2063 llmsglit (LCL_COMPILE);
2069 llmsglit ("Mailing Lists");
2070 llmsglit ("-------------");
2072 llmsglit ("There are two mailing lists associated with Splint: ");
2074 llmsglit (" lclint-announce@virginia.edu");
2076 llmsglit (" Reserved for announcements of new releases and bug fixes.");
2077 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
2078 llmsglit (" subscribe lclint-announce");
2080 llmsglit (" lclint-interest@virginia.edu");
2082 llmsglit (" Informal discussions on the use and development of Splint.");
2083 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
2084 llmsglit (" subscribe lclint-interest");
2088 printReferences (void)
2090 llmsglit ("References");
2091 llmsglit ("----------");
2093 llmsglit ("For more information, see the Splint web site: http://www.splint.org");
2097 describePrefixCodes (void)
2099 llmsglit ("Prefix Codes");
2100 llmsglit ("------------");
2102 llmsglit ("These characters have special meaning in name prefixes:");
2104 llmsg (message (" %h Any uppercase letter [A-Z]", PFX_UPPERCASE));
2105 llmsg (message (" %h Any lowercase letter [a-z]", PFX_LOWERCASE));
2106 llmsg (message (" %h Any character (valid in a C identifier)", PFX_ANY));
2107 llmsg (message (" %h Any digit [0-9]", PFX_DIGIT));
2108 llmsg (message (" %h Any non-uppercase letter [a-z0-9_]", PFX_NOTUPPER));
2109 llmsg (message (" %h Any non-lowercase letter [A-Z0-9_]", PFX_NOTLOWER));
2110 llmsg (message (" %h Any letter [A-Za-z]", PFX_ANYLETTER));
2111 llmsg (message (" %h Any letter or digit [A-Za-z0-9]", PFX_ANYLETTERDIGIT));
2112 llmsglit (" * Zero or more repetitions of the previous character class until the end of the name");
2121 eval = context_getLarchPath ();
2122 def = osd_getEnvironmentVariable (LARCH_PATH);
2124 if (cstring_isDefined (def) ||
2125 !cstring_equal (eval, cstring_fromChars (DEFAULT_LARCHPATH)))
2127 llmsg (message ("LARCH_PATH = %s", eval));
2131 llmsg (message ("LARCH_PATH = <not set> (default = %s)",
2132 cstring_fromChars (DEFAULT_LARCHPATH)));
2135 llmsglit (" --- path used to find larch initialization files and LSL traits");
2137 eval = context_getLCLImportDir ();
2138 def = osd_getEnvironmentVariable (cstring_makeLiteralTemp (LCLIMPORTDIR));
2140 if (cstring_isDefined (def) ||
2141 !cstring_equal (eval, cstring_fromChars (DEFAULT_LCLIMPORTDIR)))
2143 llmsg (message ("%q = %s", cstring_makeLiteral (LCLIMPORTDIR), eval));
2147 llmsg (message ("%s = <not set, default: %s>", cstring_makeLiteralTemp (LCLIMPORTDIR),
2148 cstring_makeLiteralTemp (DEFAULT_LCLIMPORTDIR)));
2151 llmsglit (" --- directory containing lcl standard library files "
2152 "(import with < ... >)");;
2155 ("include path = %q (set by environment variable %s and -I flags)",
2156 cppReader_getIncludePath (), INCLUDEPATH_VAR));
2158 llmsglit (" --- path used to find #include'd files");
2161 ("systemdirs = %s (set by -systemdirs or environment variable %s)", /*@i413223@*/
2162 context_getString (FLG_SYSTEMDIRS),
2165 llmsglit (" --- if file is found on this path, it is treated as a system file for error reporting");
2174 fprintf (g_errorstream, "*** Interrupt\n");
2175 llexit (LLINTERRUPT);
2180 /* Cheat when there are parse errors */
2183 fprintf (g_errorstream, "*** Segmentation Violation\n");
2185 /* Don't catch it if fileloc_unparse causes a signal */
2186 (void) signal (SIGSEGV, NULL);
2188 loc = fileloc_unparse (g_currentloc);
2190 fprintf (g_errorstream, "*** Location (not trusted): %s\n",
2191 cstring_toCharsSafe (loc));
2194 fprintf (g_errorstream, "*** Please report bug to %s\n", SPLINT_MAINTAINER);
2198 fprintf (g_errorstream, "*** Signal: %d\n", i);
2200 fprintf (g_errorstream, "*** Location (not trusted): %s\n",
2201 cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
2204 fprintf (g_errorstream, "*** Please report bug to %s ***\n", SPLINT_MAINTAINER);
2212 static bool doneCleanup = FALSE;
2214 /* make sure this is only called once! */
2216 if (doneCleanup) return;
2221 ** Close all open files
2222 ** (There should only be open files, if we exited after a fatal error.)
2225 fileTable_closeAll (context_fileTable ());
2227 if (context_getFlag (FLG_KEEP))
2229 check (fputs ("Temporary files kept:\n", g_messagestream) != EOF);
2230 fileTable_printTemps (context_fileTable ());
2235 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
2239 llbug (message ("Files unclosed: %d", nfiles));
2242 fileTable_cleanup (context_fileTable ());
2249 ** cleans up temp files (if necessary) and exits
2255 DPRINTF (("llexit: %d", status));
2258 if (status == LLFAILURE)
2266 if (status != LLFAILURE)
2268 context_destroyMod ();
2269 exprNode_destroyMod ();
2272 uentry_destroyMod ();
2273 typeIdSet_destroyMod ();
2276 dmalloc_shutdown ();
2280 exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
2283 bool readOptionsFile (cstring fname, cstringSList *passThroughArgs, bool report)
2287 if (fileTable_exists (context_fileTable (), fname))
2293 message ("Multiple attempts to read options file: %s", fname),
2299 FILE *innerf = fileTable_openFile (context_fileTable (), fname, "r");
2303 fileloc fc = g_currentloc;
2304 g_currentloc = fileloc_createRc (fname);
2306 displayScan (message ("< reading options from %q >",
2307 fileloc_outputFilename (g_currentloc)));
2309 loadrc (innerf, passThroughArgs);
2310 fileloc_reallyFree (g_currentloc);
2320 message ("Cannot open options file: %s", fname),
2330 ** This shouldn't be necessary, but Apple Darwin can't handle '"''s.
2334 loadrc (/*:open:*/ FILE *rcfile, cstringSList *passThroughArgs)
2335 /*@modifies rcfile@*/
2336 /*@ensures closed rcfile@*/
2338 char *s = mstring_create (MAX_LINE_LENGTH);
2341 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2345 while (reader_readLine (rcfile, s, MAX_LINE_LENGTH) != NULL)
2352 DPRINTF (("Line: %s", s));
2353 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2355 while (*s == ' ' || *s == '\t')
2363 bool escaped = FALSE;
2364 bool quoted = FALSE;
2367 DPRINTF (("Process: %s", s));
2368 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2369 /* comment characters */
2370 if (c == '#' || c == ';' || c == '\n')
2376 if (c == '-' || c == '+')
2383 voptgenerror (FLG_BADFLAG,
2384 message ("Bad flag syntax (+ or - expected, "
2385 "+ is assumed): %s",
2386 cstring_fromChars (s)),
2397 while ((c = *s) != '\0')
2398 { /* remember to handle spaces and quotes in -D and -U ... */
2424 if (c == ' ' || c == '\t' || c == '\n')
2426 /*@innerbreak@*/ break;
2434 DPRINTF (("Nulling: %c", *s));
2437 if (mstring_isEmpty (thisflag))
2439 llfatalerror (message ("Missing flag: %s",
2440 cstring_fromChars (os)));
2443 DPRINTF (("Flag: %s", thisflag));
2445 opt = flags_identifyFlag (cstring_fromChars (thisflag));
2447 if (flagcode_isSkip (opt))
2451 else if (flagcode_isInvalid (opt))
2453 DPRINTF (("Invalid: %s", thisflag));
2455 if (isMode (cstring_fromChars (thisflag)))
2457 context_setMode (cstring_fromChars (thisflag));
2461 voptgenerror (FLG_BADFLAG,
2462 message ("Unrecognized option: %s",
2463 cstring_fromChars (thisflag)),
2469 context_userSetFlag (opt, set);
2471 if (flagcode_hasArgument (opt))
2473 if (opt == FLG_HELP)
2476 voptgenerror (FLG_BADFLAG,
2477 message ("Cannot use help in rc files"),
2480 else if (flagcode_isPassThrough (opt)) /* -D or -U */
2482 cstring arg = cstring_fromCharsNew (thisflag);
2483 cstring_markOwned (arg);
2484 *passThroughArgs = cstringSList_add (*passThroughArgs, arg);
2485 DPRINTF (("Pass through: %s",
2486 cstringSList_unparse (*passThroughArgs)));
2488 else if (opt == FLG_INCLUDEPATH
2489 || opt == FLG_SPECPATH)
2491 cstring dir = cstring_suffix (cstring_fromChars (thisflag), 1); /* skip over I/S */
2495 case FLG_INCLUDEPATH:
2496 cppAddIncludeDir (dir);
2497 /*@switchbreak@*/ break;
2500 g_localSpecPath = cstring_toCharsSafe
2501 (message ("%s:%s", cstring_fromChars (g_localSpecPath), dir));
2503 /*@switchbreak@*/ break;
2507 else if (flagcode_hasString (opt)
2508 || flagcode_hasNumber (opt)
2509 || flagcode_hasChar (opt)
2510 || opt == FLG_INIT || opt == FLG_OPTF)
2512 cstring extra = cstring_undefined;
2517 rest = mstring_copy (s);
2518 DPRINTF (("Here: rest = %s", rest));
2522 while ((rchar = *rest) != '\0'
2523 && (isspace ((int) rchar)))
2529 DPRINTF (("Yo: %s", rest));
2531 while ((rchar = *rest) != '\0'
2532 && !isspace ((int) rchar))
2534 extra = cstring_appendChar (extra, rchar);
2539 DPRINTF (("Yo: %s", extra));
2542 if (cstring_isUndefined (extra))
2548 ("Flag %s must be followed by an argument",
2549 flagcode_unparse (opt)),
2556 DPRINTF (("Here we are: %s", extra));
2558 if (flagcode_hasNumber (opt) || flagcode_hasChar (opt))
2560 DPRINTF (("Set value flag: %s", extra));
2561 setValueFlag (opt, extra);
2563 else if (opt == FLG_OPTF)
2565 (void) readOptionsFile (extra, passThroughArgs, TRUE);
2567 else if (opt == FLG_INIT)
2570 llassert (inputStream_isUndefined (initFile));
2572 initFile = inputStream_create
2573 (cstring_copy (extra),
2574 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
2578 else if (flagcode_hasString (opt))
2580 DPRINTF (("Here: %s", extra));
2583 ** If it has "'s, we need to remove them.
2586 if (cstring_firstChar (extra) == '\"')
2588 if (cstring_lastChar (extra) == '\"')
2590 cstring unquoted = cstring_copyLength
2591 (cstring_toCharsSafe (cstring_suffix (extra, 1)),
2592 cstring_length (extra) - 2);
2594 DPRINTF (("string flag: %s -> %s", extra, unquoted));
2595 setStringFlag (opt, unquoted);
2596 cstring_free (extra);
2602 message ("Unmatched \" in option string: %s",
2605 setStringFlag (opt, extra);
2610 DPRINTF (("No quotes: %s", extra));
2611 setStringFlag (opt, extra);
2614 extra = cstring_undefined;
2622 cstring_free (extra);
2632 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2633 while ((c == ' ') || (c == '\t'))
2639 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2643 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2645 check (fileTable_closeFile (context_fileTable (), rcfile));
2648 static fileIdList preprocessFiles (fileIdList fl, bool xhfiles)
2649 /*@modifies fileSystem@*/
2651 bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
2652 int skip = (fileIdList_size (fl) / 5);
2653 int filesprocessed = 0;
2654 fileIdList dfiles = fileIdList_create ();
2656 fileloc_free (g_currentloc);
2657 g_currentloc = fileloc_createBuiltin ();
2659 fileIdList_elements (fl, fid)
2661 cstring ppfname = fileTable_fileName (fid);
2663 if (!(osd_fileIsReadable (ppfname)))
2665 lldiagmsg (message ("Cannot open file: %q", osd_outputPath (ppfname)));
2666 ppfname = cstring_undefined;
2669 if (cstring_isDefined (ppfname))
2671 fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
2675 llassert (fileTable_isXHFile (context_fileTable (), dfile));
2678 llassert (cstring_isNonEmpty (ppfname));
2682 if ((filesprocessed % skip) == 0)
2684 if (filesprocessed == 0) {
2685 fprintf (g_messagestream, " ");
2688 fprintf (g_messagestream, ".");
2691 (void) fflush (g_messagestream);
2696 DPRINTF (("outfile: %s", fileTable_fileName (dfile)));
2698 if (cppProcess (ppfname, fileTable_fileName (dfile)) != 0)
2700 llfatalerror (message ("Preprocessing error for file: %s",
2701 fileTable_rootFileName (fid)));
2704 fileIdList_add (dfiles, dfile);
2706 } end_fileIdList_elements;
2711 /* This should be in an lclUtils.c file... */
2713 char *specFullName (char *specfile, /*@out@*/ char **inpath)
2715 /* extract the path and the specname associated with the given file */
2716 char *specname = (char *) dmalloc (sizeof (*specname)
2717 * (strlen (specfile) + 9));
2718 char *ospecname = specname;
2719 char *path = (char *) dmalloc (sizeof (*path) * (strlen (specfile)));
2723 /* initialized path to empty string or may have accidental garbage */
2726 /*@-mayaliasunique@*/
2727 strcpy (specname, specfile);
2728 /*@=mayaliasunique@*/
2730 /* trim off pathnames in specfile */
2731 size = strlen (specname);
2733 for (i = size_toInt (size) - 1; i >= 0; i--)
2735 if (specname[i] == CONNECTCHAR)
2737 /* strcpy (specname, (char *)specname+i+1); */
2738 for (j = 0; j <= i; j++) /* include '/' */
2740 path[j] = specname[j];
2750 ** also remove .lcl file extension, assume it's the last extension
2754 size = strlen (specname);
2756 for (i = size_toInt (size) - 1; i >= 0; i--)
2758 if (specname[i] == '.')
2768 ** If specname no longer points to the original char,
2769 ** we need to allocate a new pointer and copy the string.
2772 if (specname != ospecname) {
2773 char *rspecname = (char *) dmalloc (sizeof (*rspecname) * (strlen (specname) + 1));
2774 strcpy (rspecname, specname); /* evs 2000-05-16: Bug: was ospecname! */
2783 void warnSysFiles(fileIdList files)
2785 fileIdList_elements (files, file)
2788 if (fileTable_isSystemFile (context_fileTable (), file) )
2790 if (!context_getFlag( FLG_SYSTEMDIRERRORS ) )
2792 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);
2796 end_fileIdList_elements;