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);
1237 else if (cstring_equal (ext, OBJECT_EXTENSION))
1239 // Make sure this is the correct default
1240 /* Ignore object files */
1244 // drl temporary measure .... //
1245 // drl // make sure this is right
1246 // on make it optional with a flag
1248 // (FLG_FILEEXTENSIONS,
1249 // message ("Unrecognized file extension: %s (assuming %s is C source code)",
1253 // addFile (cfiles, cstring_copy (current));
1255 } end_cstringSList_elements;
1263 fprintf (g_warningstream, "\n");
1265 fileIdList_free (cfiles);
1266 fileIdList_free (xfiles);
1267 fileIdList_free (lclfiles);
1276 inittime = clock ();
1278 context_resetErrors ();
1279 context_clearInCommandLine ();
1281 anylcl = !fileIdList_isEmpty (lclfiles);
1283 if (context_doMerge ())
1285 cstring m = context_getMerge ();
1287 displayScanOpen (message ("< loading %s ", m));
1289 displayScanClose ();
1291 if (!usymtab_existsType (context_getBoolName ()))
1293 usymtab_initBool ();
1298 if (!context_getFlag (FLG_NOLIB) && loadStandardState ())
1307 /* setup bool type and constants */
1308 usymtab_initBool ();
1311 fileloc_free (g_currentloc);
1312 g_currentloc = fileloc_createBuiltin ();
1315 ** Read metastate files (must happen before loading libraries)
1318 fileIdList_elements (mtfiles, mtfile)
1320 context_setFileId (mtfile);
1321 displayScan (message ("processing %s", fileTable_rootFileName (mtfile)));
1322 mtreader_readFile (cstring_copy (fileTable_fileName (mtfile)));
1323 } end_fileIdList_elements;
1330 llfatalerror (cstring_makeLiteral ("This version of Splint does not handle LCL files."));
1332 lslProcess (lclfiles);
1336 usymtab_initGlobalMarker ();
1341 ** call the pre-preprocessor and /lib/cpp to generate appropriate
1346 context_setInCommandLine ();
1348 DPRINTF (("Pass through: %s", cstringSList_unparse (passThroughArgs)));
1350 cstringSList_elements (passThroughArgs, thisarg) {
1351 handlePassThroughFlag (cstring_toCharsSafe (thisarg));
1352 } end_cstringSList_elements;
1354 cstringSList_free (passThroughArgs);
1358 DPRINTF (("Initializing cpp reader!"));
1359 cppReader_initialize ();
1360 cppReader_saveDefinitions ();
1362 context_clearInCommandLine ();
1364 if (!context_getFlag (FLG_NOPP))
1370 displayScanOpen (cstring_makeLiteral ("preprocessing"));
1374 context_setPreprocessing ();
1375 dercfiles = preprocessFiles (xfiles, TRUE);
1376 tfiles = preprocessFiles (cfiles, FALSE);
1377 warnSysFiles(cfiles);
1378 dercfiles = fileIdList_append (dercfiles, tfiles);
1379 fileIdList_free (tfiles);
1381 context_clearPreprocessing ();
1383 fileIdList_free (cfiles);
1385 displayScanClose ();
1391 dercfiles = fileIdList_append (cfiles, xfiles);
1396 ** now, check all the corresponding C files
1398 ** (for now these are just <file>.c, but after pre-processing
1399 ** will be <tmpprefix>.<file>.c)
1404 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1408 llbug (message ("Files unclosed: %d", nfiles));
1413 DPRINTF (("Initializing..."));
1415 exprNode_initMod ();
1417 DPRINTF (("Okay..."));
1419 fileIdList_elements (dercfiles, fid)
1421 sourceFile = inputStream_create (cstring_copy (fileTable_fileName (fid)), C_EXTENSION, TRUE);
1422 context_setFileId (fid);
1424 /* Open source file */
1426 if (inputStream_isUndefined (sourceFile) || (!inputStream_open (sourceFile)))
1428 /* previously, this was ignored ?! */
1429 llbug (message ("Could not open temp file: %s", fileTable_fileName (fid)));
1433 yyin = inputStream_getFile (sourceFile); /*< shared <- only */
1435 llassert (yyin != NULL);
1437 displayScan (message ("checking %q", osd_outputPath (fileTable_rootFileName (fid))));
1440 ** Every time, except the first time, through the loop,
1441 ** need to call yyrestart to clean up the parse buffer.
1446 (void) yyrestart (yyin);
1453 DPRINTF (("Entering..."));
1454 context_enterFile ();
1456 context_exitCFile ();
1458 (void) inputStream_close (sourceFile);
1460 } end_fileIdList_elements;
1464 /* process any leftover macros */
1466 context_processAllMacros ();
1468 /* check everything that was specified was defined */
1470 /* don't check if no c files were processed ?
1471 ** is this correct behaviour?
1474 displayScan (cstring_makeLiteral ("global checks"));
1478 if (context_getLinesProcessed () > 0)
1480 usymtab_allDefined ();
1483 if (context_maybeSet (FLG_TOPUNUSED))
1485 uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main"));
1487 if (uentry_isValid (ue))
1489 uentry_setUsed (ue, fileloc_observeBuiltin ());
1495 if (context_maybeSet (FLG_EXPORTLOCAL))
1497 usymtab_exportLocal ();
1501 if (context_maybeSet (FLG_EXPORTHEADER))
1503 usymtab_exportHeader ();
1506 if (context_getFlag (FLG_SHOWUSES))
1508 usymtab_displayAllUses ();
1511 context_checkSuppressCounts ();
1513 if (context_doDump ())
1515 cstring dump = context_getDump ();
1526 if (context_getFlag (FLG_SHOWSUMMARY))
1533 bool isQuiet = context_getFlag (FLG_QUIET);
1534 cstring specErrors = cstring_undefined;
1536 int nspecErrors = lclNumberErrors ();
1541 if (context_neednl ())
1542 fprintf (g_warningstream, "\n");
1545 if (nspecErrors > 0)
1547 if (nspecErrors == context_getLCLExpect ())
1550 message ("%d spec warning%&, as expected\n ",
1555 if (context_getLCLExpect () > 0)
1558 message ("%d spec warning%&, expected %d\n ",
1560 (int) context_getLCLExpect ());
1564 specErrors = message ("%d spec warning%&\n ",
1572 if (context_getLCLExpect () > 0)
1574 specErrors = message ("No spec warnings, expected %d\n ",
1575 (int) context_getLCLExpect ());
1581 if (context_anyErrors ())
1583 if (context_numErrors () == context_getExpect ())
1586 llmsg (message ("Finished checking --- "
1587 "%s%d code warning%&, as expected",
1588 specErrors, context_numErrors ()));
1593 if (context_getExpect () > 0)
1597 ("Finished checking --- "
1598 "%s%d code warning%&, expected %d",
1599 specErrors, context_numErrors (),
1600 (int) context_getExpect ()));
1610 llmsg (message ("Finished checking --- "
1611 "%s%d code warning%&",
1612 specErrors, context_numErrors ()));
1621 if (context_getExpect () > 0)
1625 ("Finished checking --- "
1626 "%sno code warnings, expected %d",
1628 (int) context_getExpect ()));
1635 if (context_getLinesProcessed () > 0)
1637 if (cstring_isEmpty (specErrors))
1641 llmsg (message ("Finished checking --- no warnings"));
1648 llmsg (message ("Finished checking --- %sno code warnings",
1656 llmsg (message ("Finished checking --- %sno code processed",
1663 cstring_free (specErrors);
1666 if (context_getFlag (FLG_STATS))
1668 clock_t ttime = clock () - before;
1669 int specLines = context_getSpecLinesProcessed ();
1675 fprintf (g_warningstream, "%d spec, ", specLines);
1678 # ifndef CLOCKS_PER_SEC
1679 fprintf (g_warningstream, "%d source lines in %ld time steps (steps/sec unknown)\n",
1680 context_getLinesProcessed (),
1683 fprintf (g_warningstream, "%d source lines in %.2f s.\n",
1684 context_getLinesProcessed (),
1685 (double) ttime / CLOCKS_PER_SEC);
1693 if (context_getFlag (FLG_TIMEDIST))
1695 clock_t ttime = clock () - before;
1699 char *msg = (char *) dmalloc (256 * sizeof (*msg));
1704 "Time distribution (percent): initialize %.2f / lcl %.2f / "
1705 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1706 (100.0 * (double) (libtime - before) / ttime),
1707 (100.0 * (double) (lcltime - libtime) / ttime),
1708 (100.0 * (double) (pptime - lcltime) / ttime),
1709 (100.0 * (double) (cptime - pptime) / ttime),
1710 (100.0 * (double) (rstime - cptime) / ttime));
1715 "Time distribution (percent): initialize %.2f / "
1716 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1717 (100.0 * (double) (libtime - before) / ttime),
1718 (100.0 * (double) (pptime - libtime) / ttime),
1719 (100.0 * (double) (cptime - pptime) / ttime),
1720 (100.0 * (double) (rstime - cptime) / ttime));
1723 llgenindentmsgnoloc (cstring_fromCharsO (msg));
1727 if (context_getFlag(FLG_FORCEEXITSUCESS))
1733 llexit (expsuccess ? LLSUCCESS : LLFAILURE);
1736 BADBRANCHRET (LLFAILURE);
1741 ** Reenable return value warnings.
1743 # pragma warning (default:4035)
1751 llmsg (message ("Source files are .c, .h and %s files. If there is no suffix,",
1753 llmsg (message (" Splint will look for <file>.c and <file>%s.", LCL_EXTENSION));
1755 llmsglit ("Use splint -help <topic or flag name> for more information");
1757 llmsglit ("Topics:");
1759 llmsglit (" annotations (describes source-code annotations)");
1760 llmsglit (" comments (describes control comments)");
1761 llmsglit (" flags (describes flag categories)");
1762 llmsglit (" flags <category> (describes flags in category)");
1763 llmsglit (" flags all (short description of all flags)");
1764 llmsglit (" flags alpha (list all flags alphabetically)");
1765 llmsglit (" flags full (full description of all flags)");
1766 llmsglit (" mail (information on mailing lists)");
1767 llmsglit (" modes (show mode settings)");
1768 llmsglit (" parseerrors (help on handling parser errors)");
1769 llmsglit (" prefixcodes (character codes in namespace prefixes)");
1770 llmsglit (" references (sources for more information)");
1771 llmsglit (" vars (environment variables)");
1772 llmsglit (" version (information on compilation, maintainer)");
1777 specialFlagsHelp (char *next)
1779 if ((next != NULL) && (*next != '-') && (*next != '+'))
1781 if (mstring_equal (next, "alpha"))
1786 else if (mstring_equal (next, "all"))
1788 printAllFlags (TRUE, FALSE);
1791 else if (mstring_equal (next, "categories")
1792 || mstring_equal (next, "cats"))
1794 listAllCategories ();
1797 else if (mstring_equal (next, "full"))
1799 printAllFlags (FALSE, TRUE);
1802 else if (mstring_equal (next, "manual"))
1804 printFlagManual (FALSE);
1807 else if (mstring_equal (next, "webmanual"))
1809 printFlagManual (TRUE);
1824 printParseErrors (void)
1826 llmsglit ("Parse Errors");
1827 llmsglit ("------------");
1829 llmsglit ("Splint will sometimes encounter a parse error for code that "
1830 "can be parsed with a local compiler. There are a few likely "
1831 "causes for this and a number of techniques that can be used "
1832 "to work around the problem.");
1834 llmsglit ("Compiler extensions --- compilers sometimes extend the C "
1835 "language with compiler-specific keywords and syntax. While "
1836 "it is not advisible to use these, oftentimes one has no choice "
1837 "when the system header files use compiler extensions. ");
1839 llmsglit ("Splint supports some of the GNU (gcc) compiler extensions, "
1840 "if the +gnuextensions flag is set. You may be able to workaround "
1841 "other compiler extensions by using a pre-processor define. "
1842 "Alternately, you can surround the unparseable code with");
1844 llmsglit (" # ifndef S_SPLINT_S");
1846 llmsglit (" # endif");
1848 /* evans 2000-12-21 fixed typo reported by Jeroen Ruigrok/Asmodai */
1849 llmsglit ("Missing type definitions --- an undefined type name will usually "
1850 "lead to a parse error. This often occurs when a standard header "
1851 "file defines some type that is not part of the standard library. ");
1852 llmsglit ("By default, Splint does not process the local files corresponding "
1853 "to standard library headers, but uses a library specification "
1854 "instead so dependencies on local system headers can be detected. "
1855 "If another system header file that does not correspond to a "
1856 "standard library header uses one of these superfluous types, "
1857 "a parse error will result.");
1859 llmsglit ("If the parse error is inside a posix standard header file, the "
1860 "first thing to try is +posixlib. This makes Splint use "
1861 "the posix library specification instead of reading the posix "
1864 llmsglit ("Otherwise, you may need to either manually define the problematic "
1865 "type (e.g., add -Dmlink_t=int to your .splintrc file) or force "
1866 "splint to process the header file that defines it. This is done "
1867 "by setting -skipisoheaders or -skipposixheaders before "
1868 "the file that defines the type is #include'd.");
1869 llmsglit ("(See splint -help "
1870 "skipisoheaders and splint -help skipposixheaders for a list of "
1871 "standard headers.) For example, if <sys/local.h> uses a type "
1872 "defined by posix header <sys/types.h> but not defined by the "
1873 "posix library, we might do: ");
1875 llmsglit (" /*@-skipposixheaders@*/");
1876 llmsglit (" # include <sys/types.h>");
1877 llmsglit (" /*@=skipposixheaders@*/");
1878 llmsglit (" # include <sys/local.h>");
1880 llmsglit ("to force Splint to process <sys/types.h>.");
1882 llmsglit ("At last resort, +trytorecover can be used to make Splint attempt "
1883 "to continue after a parse error. This is usually not successful "
1884 "and the author does not consider assertion failures when +trytorecover "
1885 "is used to be bugs.");
1889 printAnnotations (void)
1891 llmsglit ("Annotations");
1892 llmsglit ("-----------");
1894 llmsglit ("Annotations are semantic comments that document certain "
1895 "assumptions about functions, variables, parameters, and types. ");
1897 llmsglit ("They may be used to indicate where the representation of a "
1898 "user-defined type is hidden, to limit where a global variable may "
1899 "be used or modified, to constrain what a function implementation "
1900 "may do to its parameters, and to express checked assumptions about "
1901 "variables, types, structure fields, function parameters, and "
1902 "function results.");
1904 llmsglit ("Annotations are introduced by \"/*@\". The role of the @ may be "
1905 "played by any printable character, selected using -commentchar <char>.");
1907 llmsglit ("Consult the User's Guide for descriptions of checking associated with each annotation.");
1909 llmsglit ("Globals: (in function declarations)");
1910 llmsglit (" /*@globals <globitem>,+ @*/");
1911 llmsglit (" globitem is an identifier, internalState or fileSystem");
1913 llmsglit ("Modifies: (in function declarations)");
1914 llmsglit (" /*@modifies <moditem>,+ @*/");
1915 llmsglit (" moditem is an lvalue");
1916 llmsglit (" /*@modifies nothing @*/");
1917 llmsglit (" /*@*/ (Abbreviation for no globals and modifies nothing.)");
1919 llmsglit ("Iterators:");
1920 llmsglit (" /*@iter <identifier> (<parameter-type-list>) @*/ - declare an iterator");
1922 llmsglit ("Constants:");
1923 llmsglit (" /*@constant <declaration> @*/ - declares a constant");
1925 llmsglit ("Alternate Types:");
1926 llmsglit (" /*@alt <basic-type>,+ @*/");
1927 llmsglit (" (e.g., int /*@alt char@*/ is a type matching either int or char)");
1929 llmsglit ("Declarator Annotations");
1931 llmsglit ("Type Definitions:");
1932 llmsglit (" /*@abstract@*/ - representation is hidden from clients");
1933 llmsglit (" /*@concrete@*/ - representation is visible to clients");
1934 llmsglit (" /*@immutable@*/ - instances of the type cannot change value");
1935 llmsglit (" /*@mutable@*/ - instances of the type can change value");
1936 llmsglit (" /*@refcounted@*/ - reference counted type");
1938 llmsglit ("Global Variables:");
1939 llmsglit (" /*@unchecked@*/ - weakest checking for global use");
1940 llmsglit (" /*@checkmod@*/ - check modification by not use of global");
1941 llmsglit (" /*@checked@*/ - check use and modification of global");
1942 llmsglit (" /*@checkedstrict@*/ - check use of global strictly");
1944 llmsglit ("Memory Management:");
1945 llmsglit (" /*@dependent@*/ - a reference to externally-owned storage");
1946 llmsglit (" /*@keep@*/ - a parameter that is kept by the called function");
1947 llmsglit (" /*@killref@*/ - a refcounted parameter, killed by the call");
1948 llmsglit (" /*@only@*/ - an unshared reference");
1949 llmsglit (" /*@owned@*/ - owner of storage that may be shared by /*@dependent@*/ references");
1950 llmsglit (" /*@shared@*/ - shared reference that is never deallocated");
1951 llmsglit (" /*@temp@*/ - temporary parameter");
1953 llmsglit ("Aliasing:");
1954 llmsglit (" /*@unique@*/ - may not be aliased by any other visible reference");
1955 llmsglit (" /*@returned@*/ - may be aliased by the return value");
1957 llmsglit ("Exposure:");
1958 llmsglit (" /*@observer@*/ - reference that cannot be modified");
1959 llmsglit (" /*@exposed@*/ - exposed reference to storage in another object");
1961 llmsglit ("Definition State:");
1962 llmsglit (" /*@out@*/ - storage reachable from reference need not be defined");
1963 llmsglit (" /*@in@*/ - all storage reachable from reference must be defined");
1964 llmsglit (" /*@partial@*/ - partially defined, may have undefined fields");
1965 llmsglit (" /*@reldef@*/ - relax definition checking");
1967 llmsglit ("Global State: (for globals lists, no /*@, since list is already in /*@\'s)");
1968 llmsglit (" undef - variable is undefined before the call");
1969 llmsglit (" killed - variable is undefined after the call");
1971 llmsglit ("Null State:");
1972 llmsglit (" /*@null@*/ - possibly null pointer");
1973 llmsglit (" /*@notnull@*/ - definitely non-null pointer");
1974 llmsglit (" /*@relnull@*/ - relax null checking");
1976 llmsglit ("Null Predicates:");
1977 llmsglit (" /*@nullwhentrue@*/ - if result is TRUE, first parameter is NULL");
1978 llmsglit (" /*@falsewhennull@*/ - if result is TRUE, first parameter is not NULL");
1980 llmsglit ("Execution:");
1981 llmsglit (" /*@noreturn@*/ - function never returns");
1982 llmsglit (" /*@maynotreturn@*/ - function may or may not return");
1983 llmsglit (" /*@noreturnwhentrue@*/ - function does not return if first parameter is TRUE");
1984 llmsglit (" /*@noreturnwhenfalse@*/ - function does not return if first parameter if FALSE");
1985 llmsglit (" /*@alwaysreturns@*/ - function always returns");
1987 llmsglit ("Side-Effects:");
1988 llmsglit (" /*@sef@*/ - corresponding actual parameter has no side effects");
1990 llmsglit ("Declaration:");
1991 llmsglit (" /*@unused@*/ - need not be used (no unused errors reported)");
1992 llmsglit (" /*@external@*/ - defined externally (no undefined error reported)");
1995 llmsglit (" /*@fallthrough@*/ - fall-through case");
1997 llmsglit ("Break:");
1998 llmsglit (" /*@innerbreak@*/ - break is breaking an inner loop or switch");
1999 llmsglit (" /*@loopbreak@*/ - break is breaking a loop");
2000 llmsglit (" /*@switchbreak@*/ - break is breaking a switch");
2001 llmsglit (" /*@innercontinue@*/ - continue is continuing an inner loop");
2003 llmsglit ("Unreachable Code:");
2004 llmsglit (" /*@notreached@*/ - statement may be unreachable.");
2006 llmsglit ("Special Functions:");
2007 llmsglit (" /*@printflike@*/ - check variable arguments like printf");
2008 llmsglit (" /*@scanflike@*/ - check variable arguments like scanf");
2012 printComments (void)
2014 llmsglit ("Control Comments");
2015 llmsglit ("----------------");
2017 llmsglit ("Setting Flags");
2019 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.");
2021 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,");
2022 llmsglit (" /*@+boolint -modifies =showfunc@*/");
2023 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).");
2025 llmsglit ("Error Suppression");
2027 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.");
2029 llmsglit ("/*@ignore@*/ ... /*@end@*/");
2031 (cstring_makeLiteral
2032 ("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."));
2033 llmsglit ("/*@i@*/");
2035 (cstring_makeLiteral
2036 ("No errors will be reported from an /*@i@*/ comment to the end of the line."));
2037 llmsglit ("/*@i<n>@*/");
2039 (cstring_makeLiteral
2040 ("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."));
2041 llmsglit ("/*@t@*/, /*@t<n>@*/");
2043 (cstring_makeLiteral
2044 ("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."));
2046 llmsglit ("Type Access");
2048 llmsglit ("/*@access <type>@*/");
2049 llmsglit (" Allows the following code to access the representation of <type>");
2050 llmsglit ("/*@noaccess <type>@*/");
2051 llmsglit (" Hides the representation of <type>");
2053 llmsglit ("Macro Expansion");
2055 llmsglit ("/*@notfunction@*/");
2057 (cstring_makeLiteral
2058 ("Indicates that the next macro definition is not intended to be a "
2059 "function, and should be expanded in line instead of checked as a "
2060 "macro function definition."));
2067 llmsglit ("Flag Categories");
2068 llmsglit ("---------------");
2069 listAllCategories ();
2070 llmsglit ("\nTo see the flags in a flag category, do\n splint -help flags <category>");
2071 llmsglit ("To see a list of all flags in alphabetical order, do\n splint -help flags alpha");
2072 llmsglit ("To see a full description of all flags, do\n splint -help flags full");
2076 printMaintainer (void)
2078 llmsg (message ("Maintainer: %s", cstring_makeLiteralTemp (SPLINT_MAINTAINER)));
2079 llmsglit (LCL_COMPILE);
2085 llmsglit ("Mailing Lists");
2086 llmsglit ("-------------");
2088 llmsglit ("There are two mailing lists associated with Splint: ");
2090 llmsglit (" lclint-announce@virginia.edu");
2092 llmsglit (" Reserved for announcements of new releases and bug fixes.");
2093 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
2094 llmsglit (" subscribe lclint-announce");
2096 llmsglit (" lclint-interest@virginia.edu");
2098 llmsglit (" Informal discussions on the use and development of Splint.");
2099 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
2100 llmsglit (" subscribe lclint-interest");
2104 printReferences (void)
2106 llmsglit ("References");
2107 llmsglit ("----------");
2109 llmsglit ("For more information, see the Splint web site: http://www.splint.org");
2113 describePrefixCodes (void)
2115 llmsglit ("Prefix Codes");
2116 llmsglit ("------------");
2118 llmsglit ("These characters have special meaning in name prefixes:");
2120 llmsg (message (" %h Any uppercase letter [A-Z]", PFX_UPPERCASE));
2121 llmsg (message (" %h Any lowercase letter [a-z]", PFX_LOWERCASE));
2122 llmsg (message (" %h Any character (valid in a C identifier)", PFX_ANY));
2123 llmsg (message (" %h Any digit [0-9]", PFX_DIGIT));
2124 llmsg (message (" %h Any non-uppercase letter [a-z0-9_]", PFX_NOTUPPER));
2125 llmsg (message (" %h Any non-lowercase letter [A-Z0-9_]", PFX_NOTLOWER));
2126 llmsg (message (" %h Any letter [A-Za-z]", PFX_ANYLETTER));
2127 llmsg (message (" %h Any letter or digit [A-Za-z0-9]", PFX_ANYLETTERDIGIT));
2128 llmsglit (" * Zero or more repetitions of the previous character class until the end of the name");
2137 eval = context_getLarchPath ();
2138 def = osd_getEnvironmentVariable (LARCH_PATH);
2140 if (cstring_isDefined (def) ||
2141 !cstring_equal (eval, cstring_fromChars (DEFAULT_LARCHPATH)))
2143 llmsg (message ("LARCH_PATH = %s", eval));
2147 llmsg (message ("LARCH_PATH = <not set> (default = %s)",
2148 cstring_fromChars (DEFAULT_LARCHPATH)));
2151 llmsglit (" --- path used to find larch initialization files and LSL traits");
2153 eval = context_getLCLImportDir ();
2154 def = osd_getEnvironmentVariable (cstring_makeLiteralTemp (LCLIMPORTDIR));
2156 if (cstring_isDefined (def) ||
2157 !cstring_equal (eval, cstring_fromChars (DEFAULT_LCLIMPORTDIR)))
2159 llmsg (message ("%q = %s", cstring_makeLiteral (LCLIMPORTDIR), eval));
2163 llmsg (message ("%s = <not set, default: %s>", cstring_makeLiteralTemp (LCLIMPORTDIR),
2164 cstring_makeLiteralTemp (DEFAULT_LCLIMPORTDIR)));
2167 llmsglit (" --- directory containing lcl standard library files "
2168 "(import with < ... >)");;
2171 ("include path = %q (set by environment variable %s and -I flags)",
2172 cppReader_getIncludePath (), INCLUDEPATH_VAR));
2174 llmsglit (" --- path used to find #include'd files");
2177 ("systemdirs = %s (set by -systemdirs or environment variable %s)", /*@i413223@*/
2178 context_getString (FLG_SYSTEMDIRS),
2181 llmsglit (" --- if file is found on this path, it is treated as a system file for error reporting");
2190 fprintf (g_errorstream, "*** Interrupt\n");
2191 llexit (LLINTERRUPT);
2196 /* Cheat when there are parse errors */
2199 fprintf (g_errorstream, "*** Segmentation Violation\n");
2201 /* Don't catch it if fileloc_unparse causes a signal */
2202 (void) signal (SIGSEGV, NULL);
2204 loc = fileloc_unparse (g_currentloc);
2206 fprintf (g_errorstream, "*** Location (not trusted): %s\n",
2207 cstring_toCharsSafe (loc));
2210 fprintf (g_errorstream, "*** Please report bug to %s\n", SPLINT_MAINTAINER);
2214 fprintf (g_errorstream, "*** Signal: %d\n", i);
2216 fprintf (g_errorstream, "*** Location (not trusted): %s\n",
2217 cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
2220 fprintf (g_errorstream, "*** Please report bug to %s ***\n", SPLINT_MAINTAINER);
2228 static bool doneCleanup = FALSE;
2230 /* make sure this is only called once! */
2232 if (doneCleanup) return;
2237 ** Close all open files
2238 ** (There should only be open files, if we exited after a fatal error.)
2241 fileTable_closeAll (context_fileTable ());
2243 if (context_getFlag (FLG_KEEP))
2245 check (fputs ("Temporary files kept:\n", g_messagestream) != EOF);
2246 fileTable_printTemps (context_fileTable ());
2251 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
2255 llbug (message ("Files unclosed: %d", nfiles));
2258 fileTable_cleanup (context_fileTable ());
2265 ** cleans up temp files (if necessary) and exits
2271 DPRINTF (("llexit: %d", status));
2274 if (status == LLFAILURE)
2282 if (status != LLFAILURE)
2284 context_destroyMod ();
2285 exprNode_destroyMod ();
2288 uentry_destroyMod ();
2289 typeIdSet_destroyMod ();
2292 dmalloc_shutdown ();
2296 exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
2299 bool readOptionsFile (cstring fname, cstringSList *passThroughArgs, bool report)
2303 if (fileTable_exists (context_fileTable (), fname))
2309 message ("Multiple attempts to read options file: %s", fname),
2315 FILE *innerf = fileTable_openReadFile (context_fileTable (), fname);
2319 fileloc fc = g_currentloc;
2320 g_currentloc = fileloc_createRc (fname);
2322 displayScan (message ("< reading options from %q >",
2323 fileloc_outputFilename (g_currentloc)));
2325 loadrc (innerf, passThroughArgs);
2326 fileloc_reallyFree (g_currentloc);
2336 message ("Cannot open options file: %s", fname),
2346 ** This shouldn't be necessary, but Apple Darwin can't handle '"''s.
2350 loadrc (/*:open:*/ FILE *rcfile, cstringSList *passThroughArgs)
2351 /*@modifies rcfile@*/
2352 /*@ensures closed rcfile@*/
2354 char *s = mstring_create (MAX_LINE_LENGTH);
2357 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2361 while (reader_readLine (rcfile, s, MAX_LINE_LENGTH) != NULL)
2368 DPRINTF (("Line: %s", s));
2369 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2371 while (*s == ' ' || *s == '\t')
2379 bool escaped = FALSE;
2380 bool quoted = FALSE;
2383 DPRINTF (("Process: %s", s));
2384 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2385 /* comment characters */
2386 if (c == '#' || c == ';' || c == '\n')
2392 if (c == '-' || c == '+')
2399 voptgenerror (FLG_BADFLAG,
2400 message ("Bad flag syntax (+ or - expected, "
2401 "+ is assumed): %s",
2402 cstring_fromChars (s)),
2413 while ((c = *s) != '\0')
2414 { /* remember to handle spaces and quotes in -D and -U ... */
2440 if (c == ' ' || c == '\t' || c == '\n')
2442 /*@innerbreak@*/ break;
2450 DPRINTF (("Nulling: %c", *s));
2453 if (mstring_isEmpty (thisflag))
2455 llfatalerror (message ("Missing flag: %s",
2456 cstring_fromChars (os)));
2459 DPRINTF (("Flag: %s", thisflag));
2461 opt = flags_identifyFlag (cstring_fromChars (thisflag));
2463 if (flagcode_isSkip (opt))
2467 else if (flagcode_isInvalid (opt))
2469 DPRINTF (("Invalid: %s", thisflag));
2471 if (isMode (cstring_fromChars (thisflag)))
2473 context_setMode (cstring_fromChars (thisflag));
2477 voptgenerror (FLG_BADFLAG,
2478 message ("Unrecognized option: %s",
2479 cstring_fromChars (thisflag)),
2485 context_userSetFlag (opt, set);
2487 if (flagcode_hasArgument (opt))
2489 if (opt == FLG_HELP)
2492 voptgenerror (FLG_BADFLAG,
2493 message ("Cannot use help in rc files"),
2496 else if (flagcode_isPassThrough (opt)) /* -D or -U */
2498 cstring arg = cstring_fromCharsNew (thisflag);
2499 cstring_markOwned (arg);
2500 *passThroughArgs = cstringSList_add (*passThroughArgs, arg);
2501 DPRINTF (("Pass through: %s",
2502 cstringSList_unparse (*passThroughArgs)));
2504 else if (opt == FLG_INCLUDEPATH
2505 || opt == FLG_SPECPATH)
2507 cstring dir = cstring_suffix (cstring_fromChars (thisflag), 1); /* skip over I/S */
2511 case FLG_INCLUDEPATH:
2512 cppAddIncludeDir (dir);
2513 /*@switchbreak@*/ break;
2516 g_localSpecPath = cstring_toCharsSafe
2517 (message ("%s:%s", cstring_fromChars (g_localSpecPath), dir));
2519 /*@switchbreak@*/ break;
2523 else if (flagcode_hasString (opt)
2524 || flagcode_hasNumber (opt)
2525 || flagcode_hasChar (opt)
2526 || opt == FLG_INIT || opt == FLG_OPTF)
2528 cstring extra = cstring_undefined;
2533 rest = mstring_copy (s);
2534 DPRINTF (("Here: rest = %s", rest));
2538 while ((rchar = *rest) != '\0'
2539 && (isspace ((int) rchar)))
2545 DPRINTF (("Yo: %s", rest));
2547 while ((rchar = *rest) != '\0'
2548 && !isspace ((int) rchar))
2550 extra = cstring_appendChar (extra, rchar);
2555 DPRINTF (("Yo: %s", extra));
2558 if (cstring_isUndefined (extra))
2564 ("Flag %s must be followed by an argument",
2565 flagcode_unparse (opt)),
2572 DPRINTF (("Here we are: %s", extra));
2574 if (flagcode_hasNumber (opt) || flagcode_hasChar (opt))
2576 DPRINTF (("Set value flag: %s", extra));
2577 setValueFlag (opt, extra);
2579 else if (opt == FLG_OPTF)
2581 (void) readOptionsFile (extra, passThroughArgs, TRUE);
2583 else if (opt == FLG_INIT)
2586 llassert (inputStream_isUndefined (initFile));
2588 initFile = inputStream_create
2589 (cstring_copy (extra),
2590 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
2594 else if (flagcode_hasString (opt))
2596 DPRINTF (("Here: %s", extra));
2599 ** If it has "'s, we need to remove them.
2602 if (cstring_firstChar (extra) == '\"')
2604 if (cstring_lastChar (extra) == '\"')
2606 cstring unquoted = cstring_copyLength
2607 (cstring_toCharsSafe (cstring_suffix (extra, 1)),
2608 cstring_length (extra) - 2);
2610 DPRINTF (("string flag: %s -> %s", extra, unquoted));
2611 setStringFlag (opt, unquoted);
2612 cstring_free (extra);
2618 message ("Unmatched \" in option string: %s",
2621 setStringFlag (opt, extra);
2626 DPRINTF (("No quotes: %s", extra));
2627 setStringFlag (opt, extra);
2630 extra = cstring_undefined;
2638 cstring_free (extra);
2648 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2649 while ((c == ' ') || (c == '\t'))
2655 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2659 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2661 check (fileTable_closeFile (context_fileTable (), rcfile));
2664 static fileIdList preprocessFiles (fileIdList fl, bool xhfiles)
2665 /*@modifies fileSystem@*/
2667 bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
2668 int skip = (fileIdList_size (fl) / 5);
2669 int filesprocessed = 0;
2670 fileIdList dfiles = fileIdList_create ();
2672 fileloc_free (g_currentloc);
2673 g_currentloc = fileloc_createBuiltin ();
2675 fileIdList_elements (fl, fid)
2677 cstring ppfname = fileTable_fileName (fid);
2679 if (!(osd_fileIsReadable (ppfname)))
2681 lldiagmsg (message ("Cannot open file: %q", osd_outputPath (ppfname)));
2682 ppfname = cstring_undefined;
2685 if (cstring_isDefined (ppfname))
2687 fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
2691 llassert (fileTable_isXHFile (context_fileTable (), dfile));
2694 llassert (cstring_isNonEmpty (ppfname));
2698 if ((filesprocessed % skip) == 0)
2700 if (filesprocessed == 0) {
2701 fprintf (g_messagestream, " ");
2704 fprintf (g_messagestream, ".");
2707 (void) fflush (g_messagestream);
2712 DPRINTF (("outfile: %s", fileTable_fileName (dfile)));
2714 if (cppProcess (ppfname, fileTable_fileName (dfile)) != 0)
2716 llfatalerror (message ("Preprocessing error for file: %s",
2717 fileTable_rootFileName (fid)));
2720 fileIdList_add (dfiles, dfile);
2722 } end_fileIdList_elements;
2727 /* This should be in an lclUtils.c file... */
2729 char *specFullName (char *specfile, /*@out@*/ char **inpath)
2731 /* extract the path and the specname associated with the given file */
2732 char *specname = (char *) dmalloc (sizeof (*specname)
2733 * (strlen (specfile) + 9));
2734 char *ospecname = specname;
2735 char *path = (char *) dmalloc (sizeof (*path) * (strlen (specfile)));
2739 /* initialized path to empty string or may have accidental garbage */
2742 /*@-mayaliasunique@*/
2743 strcpy (specname, specfile);
2744 /*@=mayaliasunique@*/
2746 /* trim off pathnames in specfile */
2747 size = strlen (specname);
2749 for (i = size_toInt (size) - 1; i >= 0; i--)
2751 if (specname[i] == CONNECTCHAR)
2753 /* strcpy (specname, (char *)specname+i+1); */
2754 for (j = 0; j <= i; j++) /* include '/' */
2756 path[j] = specname[j];
2766 ** also remove .lcl file extension, assume it's the last extension
2770 size = strlen (specname);
2772 for (i = size_toInt (size) - 1; i >= 0; i--)
2774 if (specname[i] == '.')
2784 ** If specname no longer points to the original char,
2785 ** we need to allocate a new pointer and copy the string.
2788 if (specname != ospecname) {
2789 char *rspecname = (char *) dmalloc (sizeof (*rspecname) * (strlen (specname) + 1));
2790 strcpy (rspecname, specname); /* evs 2000-05-16: Bug: was ospecname! */
2799 void warnSysFiles(fileIdList files)
2801 fileIdList_elements (files, file)
2804 if (fileTable_isSystemFile (context_fileTable (), file) )
2806 if (!context_getFlag( FLG_SYSTEMDIRERRORS ) )
2808 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);
2812 end_fileIdList_elements;