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 void warnSysFiles(fileIdList files) /*@*/;
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 if (context_getFlag (FLG_SHOWSCAN))
371 lldiagmsg (message ("< reading spec %s >", g_currentSpec));
374 /* Open the source file */
376 if (!inputStream_open (specFile))
378 lldiagmsg (message ("Cannot open file: %q",
379 osd_outputPath (inputStream_fileName (specFile))));
380 inputStream_free (specFile);
384 scopeInfo dummy_scope = (scopeInfo) dmalloc (sizeof (*dummy_scope));
385 dummy_scope->kind = SPE_INVALID;
388 LCLScanReset (specFile);
391 ** Minor hacks to allow more than one LCL file to
392 ** be scanned, while keeping initializations
395 symtable_enterScope (g_symtab, dummy_scope);
396 resetImports (cstring_fromChars (g_currentSpecName));
397 context_enterLCLfile ();
398 (void) lclHadNewError ();
400 parser_status = (ylparse () != 0);
401 context_exitLCLfile ();
403 overallStatus = parser_status || lclHadNewError ();
405 if (context_getFlag (FLG_DOLCS))
409 outputLCSFile (path, "%FAILED Output from ",
414 outputLCSFile (path, "%PASSED Output from ",
419 (void) inputStream_close (specFile);
420 inputStream_free (specFile);
422 symtable_exitScope (g_symtab);
425 cstring_free (actualName);
426 } end_fileIdList_elements;
428 /* Can cleanup lsl stuff right away */
432 g_currentSpec = cstring_undefined;
433 g_currentSpecName = NULL;
437 static void handlePassThroughFlag (char *arg)
440 char *quotechar = strchr (curarg, '\"');
443 char *freearg = NULL;
445 while (quotechar != NULL)
447 if (*(quotechar - 1) == '\\')
449 char *tp = quotechar - 2;
460 curarg = quotechar + 1;
461 quotechar = strchr (curarg, '\"');
466 llassert (quotechar != NULL);
468 offset = (quotechar - arg) + 2;
472 arg = cstring_toCharsSafe
473 (message ("%s\"\'%s",
474 cstring_fromChars (arg),
475 cstring_fromChars (quotechar + 1)));
481 arg = cstring_toCharsSafe
482 (message ("%s\'\"%s",
483 cstring_fromChars (arg),
484 cstring_fromChars (quotechar + 1)));
489 curarg = arg + offset;
490 quotechar = strchr (curarg, '\"');
496 voptgenerror (FLG_BADFLAG,
497 message ("Unclosed quote in flag: %s",
498 cstring_fromChars (arg)),
507 ** If the value is surrounded by single quotes ('), remove
508 ** them. This is an artifact of UNIX command line?
511 def = osd_fixDefine (cstring_fromChars (arg + 1));
512 DPRINTF (("Do define: %s", def));
514 DPRINTF (("After define"));
516 } else if (arg[0] == 'U') {
517 cppDoUndefine (cstring_fromChars (arg + 1));
526 void showHerald (void)
528 if (hasShownHerald || context_getFlag (FLG_QUIET)) return;
532 fprintf (g_msgstream, "%s\n\n", SPLINT_VERSION);
533 hasShownHerald = TRUE;
538 static cstring findLarchPathFile (/*@temp@*/ cstring s)
543 status = osd_getPath (context_getLarchPath (), s, &pathName);
545 if (status == OSD_FILEFOUND)
549 else if (status == OSD_FILENOTFOUND)
552 lldiagmsg (message ("Cannot find file on LARCH_PATH: %s", s));
554 else if (status == OSD_PATHTOOLONG)
556 /* Directory and filename are too long. Report error. */
557 llbuglit ("soure_getPath: Filename plus directory from search path too long");
564 return cstring_undefined;
567 static void addLarchPathFile (fileIdList files, /*@temp@*/ cstring s)
569 cstring pathName = findLarchPathFile (s);
571 if (cstring_isDefined (pathName))
573 if (fileTable_exists (context_fileTable (), pathName))
576 lldiagmsg (message ("File listed multiple times: %s", pathName));
577 cstring_free (pathName);
581 fileIdList_add (files, fileTable_addFileOnly (context_fileTable (), pathName));
586 static void addFile (fileIdList files, /*@only@*/ cstring s)
588 if (fileTable_exists (context_fileTable (), s))
591 lldiagmsg (message ("File listed multiple times: %s", s));
596 fileIdList_add (files, fileTable_addFileOnly (context_fileTable (), s));
600 static void addXHFile (fileIdList files, /*@temp@*/ cstring s)
602 cstring pathName = findLarchPathFile (s);
604 if (cstring_isDefined (pathName))
606 if (fileTable_exists (context_fileTable (), pathName))
609 lldiagmsg (message ("File listed multiple times: %s", s));
613 fileIdList_add (files, fileTable_addXHFile (context_fileTable (), pathName));
617 cstring_free (pathName);
621 ** Disable MSVC++ warning about return value. Methinks humbly splint control
622 ** comments are a mite more legible.
626 # pragma warning (disable:4035)
629 int main (int argc, char *argv[])
631 /*@globals killed undef g_currentloc,
635 /*@modifies g_currentloc, fileSystem,
639 /*@globals killed undef g_currentloc,
640 killed undef initFile,
641 killed g_localSpecPath,
642 killed undef g_currentSpec,
643 killed undef g_currentSpecName,
647 /*@modifies g_currentloc, initFile,
648 g_localSpecPath, g_currentSpec, g_currentSpecName, fileSystem,
653 bool first_time = TRUE;
654 bool showhelp = FALSE;
657 inputStream sourceFile = inputStream_undefined;
659 fileIdList dercfiles;
660 cstringSList fl = cstringSList_undefined;
661 cstringSList passThroughArgs = cstringSList_undefined;
662 fileIdList cfiles, xfiles, lclfiles, mtfiles;
663 clock_t before, lcltime, libtime, pptime, cptime, rstime;
667 _wildcard (&argc, &argv);
670 g_msgstream = stdout;
672 (void) signal (SIGINT, interrupt);
673 (void) signal (SIGSEGV, interrupt);
675 cfiles = fileIdList_create ();
676 xfiles = fileIdList_create ();
677 lclfiles = fileIdList_create ();
678 mtfiles = fileIdList_create ();
681 clabstract_initMod ();
682 typeIdSet_initMod ();
683 cppReader_initMod ();
688 g_currentloc = fileloc_createBuiltin ();
693 context_setInCommandLine ();
705 ** Add include directories from environment.
709 cstring incval = cstring_copy (osd_getEnvironmentVariable (INCLUDEPATH_VAR));
710 cstring oincval = incval;
712 if (cstring_isDefined (incval))
715 ** Each directory on the include path is a system include directory.
718 DPRINTF (("include: %s", incval));
719 context_setString (FLG_SYSTEMDIRS, cstring_copy (incval));
721 while (cstring_isDefined (incval))
724 char *nextsep = strchr (incval, PATH_SEPARATOR);
730 dir = cstring_copy (incval);
732 if (cstring_length (dir) == 0
733 || !isalpha ((int) cstring_firstChar (dir)))
736 ** win32 environment values can have special values,
742 cppAddIncludeDir (dir);
745 *nextsep = PATH_SEPARATOR;
746 incval = cstring_fromChars (nextsep + 1);
754 /*@noaccess cstring@*/
757 else /* 2001-09-09: herbert */
759 /* Put C_INCLUDE_PATH directories in sysdirs */
760 cstring cincval = osd_getEnvironmentVariable (cstring_makeLiteralTemp ("C_INCLUDE_PATH"));
761 if (cstring_isDefined (cincval))
763 context_setString (FLG_SYSTEMDIRS, cstring_copy (cincval));
768 cstring_free (oincval);
772 ** check RCFILE for default flags
776 cstring home = osd_getHomeDir ();
777 cstring fname = cstring_undefined;
778 bool defaultf = TRUE;
781 for (i = 1; i < argc; i++)
786 if (*thisarg == '-' || *thisarg == '+')
788 bool set = (*thisarg == '+');
794 ** Don't report warnings this time
797 opt = flags_identifyFlagQuiet (cstring_fromChars (thisarg));
803 else if (opt == FLG_SHOWSCAN || opt == FLG_WARNRC || opt == FLG_PARENFILEFORMAT)
806 ** Need to set it immediately, so rc file scan is displayed
809 context_userSetFlag (opt, set);
811 else if (opt == FLG_OPTF)
816 fname = cstring_fromChars (argv[i]);
817 (void) readOptionsFile (fname, &passThroughArgs, TRUE);
821 (cstring_makeLiteral ("Flag f to select options file "
822 "requires an argument"));
826 ; /* wait to process later */
833 if (!nof && defaultf)
836 ** No explicit rc file, first try reading ~/.splintrc
839 if (cstring_isUndefined (fname))
841 if (!cstring_isEmpty (home))
843 bool readhomerc, readaltrc;
844 cstring homename, altname;
846 homename = message ("%s%h%s", home, CONNECTCHAR,
847 cstring_fromChars (RCFILE));
848 readhomerc = readOptionsFile (homename, &passThroughArgs, FALSE);
851 ** Try ~/.splintrc also for historical accuracy
854 altname = message ("%s%h%s", home, CONNECTCHAR,
855 cstring_fromChars (ALTRCFILE));
856 readaltrc = readOptionsFile (altname, &passThroughArgs, FALSE);
858 if (readhomerc && readaltrc)
863 message ("Found both %s and %s files. Using both files, "
864 "but recommend using only %s to avoid confusion.",
865 homename, altname, homename),
869 cstring_free (homename);
870 cstring_free (altname);
875 ** Next, read .splintrc in the current working directory
879 cstring rcname = message ("%s%s",osd_getCurrentDirectory (), cstring_fromChars (RCFILE));
880 cstring altname = message ("%s%s",osd_getCurrentDirectory (), cstring_fromChars (ALTRCFILE));
881 bool readrc, readaltrc;
883 readrc = readOptionsFile (rcname, &passThroughArgs, FALSE);
884 readaltrc = readOptionsFile (altname, &passThroughArgs, FALSE);
886 if (readrc && readaltrc)
888 voptgenerror (FLG_WARNRC,
889 message ("Found both %s and %s files. Using both files, "
890 "but recommend using only %s to avoid confusion.",
891 rcname, altname, rcname),
896 cstring_free (rcname);
897 cstring_free (altname);
904 for (i = 1; i < argc; i++)
920 if (*thisarg == '-' || *thisarg == '+')
922 thisarg++; /* skip '-' */
924 if (mstring_equal (thisarg, "modes"))
926 llmsg (describeModes ());
928 else if (mstring_equal (thisarg, "vars")
929 || mstring_equal (thisarg, "env"))
933 else if (mstring_equal (thisarg, "annotations"))
937 else if (mstring_equal (thisarg, "parseerrors"))
941 else if (mstring_equal (thisarg, "comments"))
945 else if (mstring_equal (thisarg, "prefixcodes"))
947 describePrefixCodes ();
949 else if (mstring_equal (thisarg, "references")
950 || mstring_equal (thisarg, "refs"))
954 else if (mstring_equal (thisarg, "mail"))
958 else if (mstring_equal (thisarg, "maintainer")
959 || mstring_equal (thisarg, "version"))
963 else if (mstring_equal (thisarg, "flags"))
967 char *next = argv[i + 1];
969 if (specialFlagsHelp (next))
975 flagkind k = identifyCategory (cstring_fromChars (next));
991 cstring s = describeFlag (cstring_fromChars (thisarg));
993 if (cstring_isDefined (s))
1001 if (*thisarg == '-' || *thisarg == '+')
1003 bool set = (*thisarg == '+');
1006 thisarg++; /* skip '-' */
1007 flagname = cstring_fromChars (thisarg);
1009 DPRINTF (("Flag: %s", flagname));
1010 opt = flags_identifyFlag (flagname);
1011 DPRINTF (("Flag: %s", flagcode_unparse (opt)));
1013 if (flagcode_isSkip (opt) || opt == FLG_SHOWSCAN || opt == FLG_WARNRC || opt == FLG_PARENFILEFORMAT)
1015 /* showscan already processed */
1016 DPRINTF (("Skipping!"));
1018 else if (flagcode_isInvalid (opt))
1020 DPRINTF (("Invalid: %s", flagname));
1022 if (isMode (flagname))
1024 context_setMode (flagname);
1028 DPRINTF (("Error!"));
1029 voptgenerror (FLG_BADFLAG,
1030 message ("Unrecognized option: %s",
1031 cstring_fromChars (thisarg)),
1037 context_userSetFlag (opt, set);
1039 if (flagcode_hasArgument (opt))
1041 if (opt == FLG_HELP)
1045 else if (flagcode_isPassThrough (opt)) /* -D or -U */
1047 passThroughArgs = cstringSList_add
1048 (passThroughArgs, cstring_fromChars (thisarg));
1050 else if (flagcode_hasNumber (opt))
1054 setValueFlag (opt, cstring_fromChars (argv[i]));
1060 ("Flag %s must be followed by a number",
1061 flagcode_unparse (opt)));
1064 else if (flagcode_hasChar (opt))
1068 setValueFlag (opt, cstring_fromChars (argv[i]));
1074 ("Flag %s must be followed by a character",
1075 flagcode_unparse (opt)));
1078 else if (opt == FLG_INCLUDEPATH || opt == FLG_SPECPATH)
1080 cstring dir = cstring_suffix (cstring_fromChars (thisarg), 1); /* skip over I */
1084 case FLG_INCLUDEPATH:
1085 cppAddIncludeDir (dir);
1086 /*@switchbreak@*/ break;
1089 g_localSpecPath = cstring_toCharsSafe
1091 cstring_fromChars (g_localSpecPath),
1095 /*@switchbreak@*/ break;
1099 else if (flagcode_hasString (opt)
1100 || opt == FLG_INIT || opt == FLG_OPTF)
1104 cstring arg = cstring_fromChars (argv[i]);
1106 if (opt == FLG_OPTF)
1108 ; /* -f already processed */
1110 else if (opt == FLG_INIT)
1113 initFile = inputStream_create
1115 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
1122 DPRINTF (("String flag: %s / %s",
1123 flagcode_unparse (opt), arg));
1124 if (opt == FLG_MTSFILE)
1127 ** arg identifies mts files
1129 cstring tmp = message ("%s%s", arg, MTS_EXTENSION);
1130 addLarchPathFile (mtfiles, tmp);
1132 tmp = message ("%s%s", arg, XH_EXTENSION);
1133 addXHFile (xfiles, tmp);
1138 setStringFlag (opt, cstring_copy (arg));
1146 ("Flag %s must be followed by a string",
1147 flagcode_unparse (opt)));
1157 else /* its a filename */
1159 DPRINTF (("Adding filename: %s", thisarg));
1160 fl = cstringSList_add (fl, cstring_fromChars (thisarg));
1169 ** create lists of C and LCL files
1172 cstringSList_elements (fl, current)
1174 cstring ext = fileLib_getExtension (current);
1176 if (cstring_isUndefined (ext))
1178 /* no extension --- both C and LCL with default extensions */
1180 addFile (cfiles, message ("%s%s", current, C_EXTENSION));
1181 addFile (lclfiles, message ("%s%s", current, LCL_EXTENSION));
1183 else if (cstring_equal (ext, XH_EXTENSION))
1185 addXHFile (xfiles, current);
1187 else if (cstring_equal (ext, PP_EXTENSION))
1189 if (!context_getFlag (FLG_NOPP))
1192 (FLG_FILEEXTENSIONS,
1193 message ("File extension %s used without +nopp flag (will be processed as C source code): %s",
1198 addFile (cfiles, cstring_copy (current));
1200 else if (cstring_equal (ext, LCL_EXTENSION))
1202 addFile (lclfiles, cstring_copy (current));
1204 else if (fileLib_isCExtension (ext))
1206 addFile (cfiles, cstring_copy (current));
1208 else if (cstring_equal (ext, MTS_EXTENSION))
1210 addLarchPathFile (mtfiles, current);
1215 (FLG_FILEEXTENSIONS,
1216 message ("Unrecognized file extension: %s (assuming %s is C source code)",
1220 addFile (cfiles, cstring_copy (current));
1222 } end_cstringSList_elements;
1230 fprintf (g_msgstream, "\n");
1232 fileIdList_free (cfiles);
1233 fileIdList_free (xfiles);
1234 fileIdList_free (lclfiles);
1243 inittime = clock ();
1245 context_resetErrors ();
1246 context_clearInCommandLine ();
1248 anylcl = !fileIdList_isEmpty (lclfiles);
1250 if (context_doMerge ())
1252 cstring m = context_getMerge ();
1254 if (context_getFlag (FLG_SHOWSCAN))
1256 fprintf (g_msgstream, "< loading %s ", cstring_toCharsSafe (m));
1261 if (context_getFlag (FLG_SHOWSCAN))
1263 fprintf (g_msgstream, " >\n");
1266 if (!usymtab_existsType (context_getBoolName ()))
1268 usymtab_initBool ();
1273 if (!context_getFlag (FLG_NOLIB) && loadStandardState ())
1282 /* setup bool type and constants */
1283 usymtab_initBool ();
1286 fileloc_free (g_currentloc);
1287 g_currentloc = fileloc_createBuiltin ();
1290 ** Read metastate files (must happen before loading libraries)
1293 fileIdList_elements (mtfiles, mtfile)
1295 context_setFileId (mtfile);
1297 if (context_getFlag (FLG_SHOWSCAN))
1299 lldiagmsg (message ("< processing %s >", fileTable_rootFileName (mtfile)));
1302 mtreader_readFile (cstring_copy (fileTable_fileName (mtfile)));
1303 } end_fileIdList_elements;
1310 llfatalerror (cstring_makeLiteral ("This version of Splint does not handle LCL files."));
1312 lslProcess (lclfiles);
1316 usymtab_initGlobalMarker ();
1321 ** call the pre-preprocessor and /lib/cpp to generate appropriate
1326 context_setInCommandLine ();
1328 DPRINTF (("Pass through: %s", cstringSList_unparse (passThroughArgs)));
1330 cstringSList_elements (passThroughArgs, thisarg) {
1331 handlePassThroughFlag (cstring_toCharsSafe (thisarg));
1332 } end_cstringSList_elements;
1334 cstringSList_free (passThroughArgs);
1338 DPRINTF (("Initializing cpp reader!"));
1339 cppReader_initialize ();
1340 cppReader_saveDefinitions ();
1342 context_clearInCommandLine ();
1344 if (!context_getFlag (FLG_NOPP))
1350 if (context_getFlag (FLG_SHOWSCAN))
1352 fprintf (stderr, "< preprocessing");
1357 context_setPreprocessing ();
1358 dercfiles = preprocessFiles (xfiles, TRUE);
1359 tfiles = preprocessFiles (cfiles, FALSE);
1360 warnSysFiles(cfiles);
1361 dercfiles = fileIdList_append (dercfiles, tfiles);
1362 fileIdList_free (tfiles);
1364 context_clearPreprocessing ();
1366 fileIdList_free (cfiles);
1368 if (context_getFlag (FLG_SHOWSCAN))
1370 fprintf (stderr, " >\n");
1378 dercfiles = fileIdList_append (cfiles, xfiles);
1383 ** now, check all the corresponding C files
1385 ** (for now these are just <file>.c, but after pre-processing
1386 ** will be <tmpprefix>.<file>.c)
1391 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1395 llbug (message ("Files unclosed: %d", nfiles));
1400 DPRINTF (("Initializing..."));
1402 exprNode_initMod ();
1404 DPRINTF (("Okay..."));
1406 fileIdList_elements (dercfiles, fid)
1408 sourceFile = inputStream_create (cstring_copy (fileTable_fileName (fid)), C_EXTENSION, TRUE);
1409 context_setFileId (fid);
1411 /* Open source file */
1413 if (inputStream_isUndefined (sourceFile) || (!inputStream_open (sourceFile)))
1415 /* previously, this was ignored ?! */
1416 llbug (message ("Could not open temp file: %s", fileTable_fileName (fid)));
1420 yyin = inputStream_getFile (sourceFile); /*< shared <- only */
1422 llassert (yyin != NULL);
1424 if (context_getFlag (FLG_SHOWSCAN))
1426 lldiagmsg (message ("< checking %q >", osd_outputPath (fileTable_rootFileName (fid))));
1430 ** Every time, except the first time, through the loop,
1431 ** need to call yyrestart to clean up the parse buffer.
1436 (void) yyrestart (yyin);
1443 DPRINTF (("Entering..."));
1444 context_enterFile ();
1446 context_exitCFile ();
1448 (void) inputStream_close (sourceFile);
1450 } end_fileIdList_elements;
1454 /* process any leftover macros */
1456 context_processAllMacros ();
1458 /* check everything that was specified was defined */
1460 /* don't check if no c files were processed ?
1461 ** is this correct behaviour?
1464 if (context_getFlag (FLG_SHOWSCAN))
1466 lldiagmsg (cstring_makeLiteral ("< global checks >"));
1471 if (context_getLinesProcessed () > 0)
1473 usymtab_allDefined ();
1476 if (context_maybeSet (FLG_TOPUNUSED))
1478 uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main"));
1480 if (uentry_isValid (ue))
1482 uentry_setUsed (ue, fileloc_observeBuiltin ());
1488 if (context_maybeSet (FLG_EXPORTLOCAL))
1490 usymtab_exportLocal ();
1494 if (context_maybeSet (FLG_EXPORTHEADER))
1496 usymtab_exportHeader ();
1499 if (context_getFlag (FLG_SHOWUSES))
1501 usymtab_displayAllUses ();
1504 context_checkSuppressCounts ();
1506 if (context_doDump ())
1508 cstring dump = context_getDump ();
1519 if (context_getFlag (FLG_SHOWSUMMARY))
1526 bool isQuiet = context_getFlag (FLG_QUIET);
1527 cstring specErrors = cstring_undefined;
1529 int nspecErrors = lclNumberErrors ();
1534 if (context_neednl ())
1535 fprintf (g_msgstream, "\n");
1538 if (nspecErrors > 0)
1540 if (nspecErrors == context_getLCLExpect ())
1543 message ("%d spec warning%&, as expected\n ",
1548 if (context_getLCLExpect () > 0)
1551 message ("%d spec warning%&, expected %d\n ",
1553 (int) context_getLCLExpect ());
1557 specErrors = message ("%d spec warning%&\n ",
1565 if (context_getLCLExpect () > 0)
1567 specErrors = message ("No spec warnings, expected %d\n ",
1568 (int) context_getLCLExpect ());
1574 if (context_anyErrors ())
1576 if (context_numErrors () == context_getExpect ())
1579 llmsg (message ("Finished checking --- "
1580 "%s%d code warning%&, as expected",
1581 specErrors, context_numErrors ()));
1586 if (context_getExpect () > 0)
1590 ("Finished checking --- "
1591 "%s%d code warning%&, expected %d",
1592 specErrors, context_numErrors (),
1593 (int) context_getExpect ()));
1603 llmsg (message ("Finished checking --- "
1604 "%s%d code warning%&",
1605 specErrors, context_numErrors ()));
1614 if (context_getExpect () > 0)
1618 ("Finished checking --- "
1619 "%sno code warnings, expected %d",
1621 (int) context_getExpect ()));
1628 if (context_getLinesProcessed () > 0)
1630 if (cstring_isEmpty (specErrors))
1634 llmsg (message ("Finished checking --- no warnings"));
1641 llmsg (message ("Finished checking --- %sno code warnings",
1649 llmsg (message ("Finished checking --- %sno code processed",
1656 cstring_free (specErrors);
1659 if (context_getFlag (FLG_STATS))
1661 clock_t ttime = clock () - before;
1662 int specLines = context_getSpecLinesProcessed ();
1668 fprintf (g_msgstream, "%d spec, ", specLines);
1671 # ifndef CLOCKS_PER_SEC
1672 fprintf (g_msgstream, "%d source lines in %ld time steps (steps/sec unknown)\n",
1673 context_getLinesProcessed (),
1676 fprintf (g_msgstream, "%d source lines in %.2f s.\n",
1677 context_getLinesProcessed (),
1678 (double) ttime / CLOCKS_PER_SEC);
1686 if (context_getFlag (FLG_TIMEDIST))
1688 clock_t ttime = clock () - before;
1692 char *msg = (char *) dmalloc (256 * sizeof (*msg));
1697 "Time distribution (percent): initialize %.2f / lcl %.2f / "
1698 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1699 (100.0 * (double) (libtime - before) / ttime),
1700 (100.0 * (double) (lcltime - libtime) / ttime),
1701 (100.0 * (double) (pptime - lcltime) / ttime),
1702 (100.0 * (double) (cptime - pptime) / ttime),
1703 (100.0 * (double) (rstime - cptime) / ttime));
1708 "Time distribution (percent): initialize %.2f / "
1709 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1710 (100.0 * (double) (libtime - before) / ttime),
1711 (100.0 * (double) (pptime - libtime) / ttime),
1712 (100.0 * (double) (cptime - pptime) / ttime),
1713 (100.0 * (double) (rstime - cptime) / ttime));
1716 llgenindentmsgnoloc (cstring_fromCharsO (msg));
1720 llexit (expsuccess ? LLSUCCESS : LLFAILURE);
1721 BADBRANCHRET (LLFAILURE);
1726 ** Reenable return value warnings.
1728 # pragma warning (default:4035)
1736 llmsg (message ("Source files are .c, .h and %s files. If there is no suffix,",
1738 llmsg (message (" Splint will look for <file>.c and <file>%s.", LCL_EXTENSION));
1740 llmsglit ("Use splint -help <topic or flag name> for more information");
1742 llmsglit ("Topics:");
1744 llmsglit (" annotations (describes source-code annotations)");
1745 llmsglit (" comments (describes control comments)");
1746 llmsglit (" flags (describes flag categories)");
1747 llmsglit (" flags <category> (describes flags in category)");
1748 llmsglit (" flags all (short description of all flags)");
1749 llmsglit (" flags alpha (list all flags alphabetically)");
1750 llmsglit (" flags full (full description of all flags)");
1751 llmsglit (" mail (information on mailing lists)");
1752 llmsglit (" modes (show mode settings)");
1753 llmsglit (" parseerrors (help on handling parser errors)");
1754 llmsglit (" prefixcodes (character codes in namespace prefixes)");
1755 llmsglit (" references (sources for more information)");
1756 llmsglit (" vars (environment variables)");
1757 llmsglit (" version (information on compilation, maintainer)");
1762 specialFlagsHelp (char *next)
1764 if ((next != NULL) && (*next != '-') && (*next != '+'))
1766 if (mstring_equal (next, "alpha"))
1771 else if (mstring_equal (next, "all"))
1773 printAllFlags (TRUE, FALSE);
1776 else if (mstring_equal (next, "categories")
1777 || mstring_equal (next, "cats"))
1779 listAllCategories ();
1782 else if (mstring_equal (next, "full"))
1784 printAllFlags (FALSE, TRUE);
1787 else if (mstring_equal (next, "manual"))
1789 printFlagManual (FALSE);
1792 else if (mstring_equal (next, "webmanual"))
1794 printFlagManual (TRUE);
1809 printParseErrors (void)
1811 llmsglit ("Parse Errors");
1812 llmsglit ("------------");
1814 llmsglit ("Splint will sometimes encounter a parse error for code that "
1815 "can be parsed with a local compiler. There are a few likely "
1816 "causes for this and a number of techniques that can be used "
1817 "to work around the problem.");
1819 llmsglit ("Compiler extensions --- compilers sometimes extend the C "
1820 "language with compiler-specific keywords and syntax. While "
1821 "it is not advisible to use these, oftentimes one has no choice "
1822 "when the system header files use compiler extensions. ");
1824 llmsglit ("Splint supports some of the GNU (gcc) compiler extensions, "
1825 "if the +gnuextensions flag is set. You may be able to workaround "
1826 "other compiler extensions by using a pre-processor define. "
1827 "Alternately, you can surround the unparseable code with");
1829 llmsglit (" # ifndef S_SPLINT_S");
1831 llmsglit (" # endif");
1833 /* evans 2000-12-21 fixed typo reported by Jeroen Ruigrok/Asmodai */
1834 llmsglit ("Missing type definitions --- an undefined type name will usually "
1835 "lead to a parse error. This often occurs when a standard header "
1836 "file defines some type that is not part of the standard library. ");
1837 llmsglit ("By default, Splint does not process the local files corresponding "
1838 "to standard library headers, but uses a library specification "
1839 "instead so dependencies on local system headers can be detected. "
1840 "If another system header file that does not correspond to a "
1841 "standard library header uses one of these superfluous types, "
1842 "a parse error will result.");
1844 llmsglit ("If the parse error is inside a posix standard header file, the "
1845 "first thing to try is +posixlib. This makes Splint use "
1846 "the posix library specification instead of reading the posix "
1849 llmsglit ("Otherwise, you may need to either manually define the problematic "
1850 "type (e.g., add -Dmlink_t=int to your .splintrc file) or force "
1851 "splint to process the header file that defines it. This is done "
1852 "by setting -skipisoheaders or -skipposixheaders before "
1853 "the file that defines the type is #include'd.");
1854 llmsglit ("(See splint -help "
1855 "skipisoheaders and splint -help skipposixheaders for a list of "
1856 "standard headers.) For example, if <sys/local.h> uses a type "
1857 "defined by posix header <sys/types.h> but not defined by the "
1858 "posix library, we might do: ");
1860 llmsglit (" /*@-skipposixheaders@*/");
1861 llmsglit (" # include <sys/types.h>");
1862 llmsglit (" /*@=skipposixheaders@*/");
1863 llmsglit (" # include <sys/local.h>");
1865 llmsglit ("to force Splint to process <sys/types.h>.");
1867 llmsglit ("At last resort, +trytorecover can be used to make Splint attempt "
1868 "to continue after a parse error. This is usually not successful "
1869 "and the author does not consider assertion failures when +trytorecover "
1870 "is used to be bugs.");
1874 printAnnotations (void)
1876 llmsglit ("Annotations");
1877 llmsglit ("-----------");
1879 llmsglit ("Annotations are semantic comments that document certain "
1880 "assumptions about functions, variables, parameters, and types. ");
1882 llmsglit ("They may be used to indicate where the representation of a "
1883 "user-defined type is hidden, to limit where a global variable may "
1884 "be used or modified, to constrain what a function implementation "
1885 "may do to its parameters, and to express checked assumptions about "
1886 "variables, types, structure fields, function parameters, and "
1887 "function results.");
1889 llmsglit ("Annotations are introduced by \"/*@\". The role of the @ may be "
1890 "played by any printable character, selected using -commentchar <char>.");
1892 llmsglit ("Consult the User's Guide for descriptions of checking associated with each annotation.");
1894 llmsglit ("Globals: (in function declarations)");
1895 llmsglit (" /*@globals <globitem>,+ @*/");
1896 llmsglit (" globitem is an identifier, internalState or fileSystem");
1898 llmsglit ("Modifies: (in function declarations)");
1899 llmsglit (" /*@modifies <moditem>,+ @*/");
1900 llmsglit (" moditem is an lvalue");
1901 llmsglit (" /*@modifies nothing @*/");
1902 llmsglit (" /*@*/ (Abbreviation for no globals and modifies nothing.)");
1904 llmsglit ("Iterators:");
1905 llmsglit (" /*@iter <identifier> (<parameter-type-list>) @*/ - declare an iterator");
1907 llmsglit ("Constants:");
1908 llmsglit (" /*@constant <declaration> @*/ - declares a constant");
1910 llmsglit ("Alternate Types:");
1911 llmsglit (" /*@alt <basic-type>,+ @*/");
1912 llmsglit (" (e.g., int /*@alt char@*/ is a type matching either int or char)");
1914 llmsglit ("Declarator Annotations");
1916 llmsglit ("Type Definitions:");
1917 llmsglit (" /*@abstract@*/ - representation is hidden from clients");
1918 llmsglit (" /*@concrete@*/ - representation is visible to clients");
1919 llmsglit (" /*@immutable@*/ - instances of the type cannot change value");
1920 llmsglit (" /*@mutable@*/ - instances of the type can change value");
1921 llmsglit (" /*@refcounted@*/ - reference counted type");
1923 llmsglit ("Global Variables:");
1924 llmsglit (" /*@unchecked@*/ - weakest checking for global use");
1925 llmsglit (" /*@checkmod@*/ - check modification by not use of global");
1926 llmsglit (" /*@checked@*/ - check use and modification of global");
1927 llmsglit (" /*@checkedstrict@*/ - check use of global strictly");
1929 llmsglit ("Memory Management:");
1930 llmsglit (" /*@dependent@*/ - a reference to externally-owned storage");
1931 llmsglit (" /*@keep@*/ - a parameter that is kept by the called function");
1932 llmsglit (" /*@killref@*/ - a refcounted parameter, killed by the call");
1933 llmsglit (" /*@only@*/ - an unshared reference");
1934 llmsglit (" /*@owned@*/ - owner of storage that may be shared by /*@dependent@*/ references");
1935 llmsglit (" /*@shared@*/ - shared reference that is never deallocated");
1936 llmsglit (" /*@temp@*/ - temporary parameter");
1938 llmsglit ("Aliasing:");
1939 llmsglit (" /*@unique@*/ - may not be aliased by any other visible reference");
1940 llmsglit (" /*@returned@*/ - may be aliased by the return value");
1942 llmsglit ("Exposure:");
1943 llmsglit (" /*@observer@*/ - reference that cannot be modified");
1944 llmsglit (" /*@exposed@*/ - exposed reference to storage in another object");
1946 llmsglit ("Definition State:");
1947 llmsglit (" /*@out@*/ - storage reachable from reference need not be defined");
1948 llmsglit (" /*@in@*/ - all storage reachable from reference must be defined");
1949 llmsglit (" /*@partial@*/ - partially defined, may have undefined fields");
1950 llmsglit (" /*@reldef@*/ - relax definition checking");
1952 llmsglit ("Global State: (for globals lists, no /*@, since list is already in /*@\'s)");
1953 llmsglit (" undef - variable is undefined before the call");
1954 llmsglit (" killed - variable is undefined after the call");
1956 llmsglit ("Null State:");
1957 llmsglit (" /*@null@*/ - possibly null pointer");
1958 llmsglit (" /*@notnull@*/ - definitely non-null pointer");
1959 llmsglit (" /*@relnull@*/ - relax null checking");
1961 llmsglit ("Null Predicates:");
1962 llmsglit (" /*@nullwhentrue@*/ - if result is TRUE, first parameter is NULL");
1963 llmsglit (" /*@falsewhennull@*/ - if result is TRUE, first parameter is not NULL");
1965 llmsglit ("Execution:");
1966 llmsglit (" /*@noreturn@*/ - function never returns");
1967 llmsglit (" /*@maynotreturn@*/ - function may or may not return");
1968 llmsglit (" /*@noreturnwhentrue@*/ - function does not return if first parameter is TRUE");
1969 llmsglit (" /*@noreturnwhenfalse@*/ - function does not return if first parameter if FALSE");
1970 llmsglit (" /*@alwaysreturns@*/ - function always returns");
1972 llmsglit ("Side-Effects:");
1973 llmsglit (" /*@sef@*/ - corresponding actual parameter has no side effects");
1975 llmsglit ("Declaration:");
1976 llmsglit (" /*@unused@*/ - need not be used (no unused errors reported)");
1977 llmsglit (" /*@external@*/ - defined externally (no undefined error reported)");
1980 llmsglit (" /*@fallthrough@*/ - fall-through case");
1982 llmsglit ("Break:");
1983 llmsglit (" /*@innerbreak@*/ - break is breaking an inner loop or switch");
1984 llmsglit (" /*@loopbreak@*/ - break is breaking a loop");
1985 llmsglit (" /*@switchbreak@*/ - break is breaking a switch");
1986 llmsglit (" /*@innercontinue@*/ - continue is continuing an inner loop");
1988 llmsglit ("Unreachable Code:");
1989 llmsglit (" /*@notreached@*/ - statement may be unreachable.");
1991 llmsglit ("Special Functions:");
1992 llmsglit (" /*@printflike@*/ - check variable arguments like printf");
1993 llmsglit (" /*@scanflike@*/ - check variable arguments like scanf");
1997 printComments (void)
1999 llmsglit ("Control Comments");
2000 llmsglit ("----------------");
2002 llmsglit ("Setting Flags");
2004 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.");
2006 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,");
2007 llmsglit (" /*@+boolint -modifies =showfunc@*/");
2008 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).");
2010 llmsglit ("Error Suppression");
2012 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.");
2014 llmsglit ("/*@ignore@*/ ... /*@end@*/");
2016 (cstring_makeLiteral
2017 ("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."));
2018 llmsglit ("/*@i@*/");
2020 (cstring_makeLiteral
2021 ("No errors will be reported from an /*@i@*/ comment to the end of the line."));
2022 llmsglit ("/*@i<n>@*/");
2024 (cstring_makeLiteral
2025 ("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."));
2026 llmsglit ("/*@t@*/, /*@t<n>@*/");
2028 (cstring_makeLiteral
2029 ("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."));
2031 llmsglit ("Type Access");
2033 llmsglit ("/*@access <type>@*/");
2034 llmsglit (" Allows the following code to access the representation of <type>");
2035 llmsglit ("/*@noaccess <type>@*/");
2036 llmsglit (" Hides the representation of <type>");
2038 llmsglit ("Macro Expansion");
2040 llmsglit ("/*@notfunction@*/");
2042 (cstring_makeLiteral
2043 ("Indicates that the next macro definition is not intended to be a "
2044 "function, and should be expanded in line instead of checked as a "
2045 "macro function definition."));
2052 llmsglit ("Flag Categories");
2053 llmsglit ("---------------");
2054 listAllCategories ();
2055 llmsglit ("\nTo see the flags in a flag category, do\n splint -help flags <category>");
2056 llmsglit ("To see a list of all flags in alphabetical order, do\n splint -help flags alpha");
2057 llmsglit ("To see a full description of all flags, do\n splint -help flags full");
2061 printMaintainer (void)
2063 llmsg (message ("Maintainer: %s", cstring_makeLiteralTemp (SPLINT_MAINTAINER)));
2064 llmsglit (LCL_COMPILE);
2070 llmsglit ("Mailing Lists");
2071 llmsglit ("-------------");
2073 llmsglit ("There are two mailing lists associated with Splint: ");
2075 llmsglit (" lclint-announce@virginia.edu");
2077 llmsglit (" Reserved for announcements of new releases and bug fixes.");
2078 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
2079 llmsglit (" subscribe lclint-announce");
2081 llmsglit (" lclint-interest@virginia.edu");
2083 llmsglit (" Informal discussions on the use and development of Splint.");
2084 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
2085 llmsglit (" subscribe lclint-interest");
2089 printReferences (void)
2091 llmsglit ("References");
2092 llmsglit ("----------");
2094 llmsglit ("For more information, see the Splint web site: http://www.splint.org");
2098 describePrefixCodes (void)
2100 llmsglit ("Prefix Codes");
2101 llmsglit ("------------");
2103 llmsglit ("These characters have special meaning in name prefixes:");
2105 llmsg (message (" %h Any uppercase letter [A-Z]", PFX_UPPERCASE));
2106 llmsg (message (" %h Any lowercase letter [a-z]", PFX_LOWERCASE));
2107 llmsg (message (" %h Any character (valid in a C identifier)", PFX_ANY));
2108 llmsg (message (" %h Any digit [0-9]", PFX_DIGIT));
2109 llmsg (message (" %h Any non-uppercase letter [a-z0-9_]", PFX_NOTUPPER));
2110 llmsg (message (" %h Any non-lowercase letter [A-Z0-9_]", PFX_NOTLOWER));
2111 llmsg (message (" %h Any letter [A-Za-z]", PFX_ANYLETTER));
2112 llmsg (message (" %h Any letter or digit [A-Za-z0-9]", PFX_ANYLETTERDIGIT));
2113 llmsglit (" * Zero or more repetitions of the previous character class until the end of the name");
2122 eval = context_getLarchPath ();
2123 def = osd_getEnvironmentVariable (LARCH_PATH);
2125 if (cstring_isDefined (def) ||
2126 !cstring_equal (eval, cstring_fromChars (DEFAULT_LARCHPATH)))
2128 llmsg (message ("LARCH_PATH = %s", eval));
2132 llmsg (message ("LARCH_PATH = <not set> (default = %s)",
2133 cstring_fromChars (DEFAULT_LARCHPATH)));
2136 llmsglit (" --- path used to find larch initialization files and LSL traits");
2138 eval = context_getLCLImportDir ();
2139 def = osd_getEnvironmentVariable (cstring_makeLiteralTemp (LCLIMPORTDIR));
2141 if (cstring_isDefined (def) ||
2142 !cstring_equal (eval, cstring_fromChars (DEFAULT_LCLIMPORTDIR)))
2144 llmsg (message ("%q = %s", cstring_makeLiteral (LCLIMPORTDIR), eval));
2148 llmsg (message ("%s = <not set, default: %s>", cstring_makeLiteralTemp (LCLIMPORTDIR),
2149 cstring_makeLiteralTemp (DEFAULT_LCLIMPORTDIR)));
2152 llmsglit (" --- directory containing lcl standard library files "
2153 "(import with < ... >)");;
2156 ("include path = %q (set by environment variable %s and -I flags)",
2157 cppReader_getIncludePath (), INCLUDEPATH_VAR));
2159 llmsglit (" --- path used to find #include'd files");
2162 ("systemdirs = %s (set by -systemdirs or environment variable %s)", /*@i413223@*/
2163 context_getString (FLG_SYSTEMDIRS),
2166 llmsglit (" --- if file is found on this path, it is treated as a system file for error reporting");
2175 fprintf (stderr, "*** Interrupt\n");
2176 llexit (LLINTERRUPT);
2181 /* Cheat when there are parse errors */
2184 fprintf (stderr, "*** Segmentation Violation\n");
2186 /* Don't catch it if fileloc_unparse causes a signal */
2187 (void) signal (SIGSEGV, NULL);
2189 loc = fileloc_unparse (g_currentloc);
2191 fprintf (stderr, "*** Location (not trusted): %s\n",
2192 cstring_toCharsSafe (loc));
2195 fprintf (stderr, "*** Please report bug to %s\n", SPLINT_MAINTAINER);
2199 fprintf (stderr, "*** Signal: %d\n", i);
2201 fprintf (stderr, "*** Location (not trusted): %s\n",
2202 cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
2205 fprintf (stderr, "*** Please report bug to %s ***\n", SPLINT_MAINTAINER);
2213 static bool doneCleanup = FALSE;
2215 /* make sure this is only called once! */
2217 if (doneCleanup) return;
2222 ** Close all open files
2223 ** (There should only be open files, if we exited after a fatal error.)
2226 fileTable_closeAll (context_fileTable ());
2228 if (context_getFlag (FLG_KEEP))
2230 check (fputs ("Temporary files kept:\n", stderr) != EOF);
2231 fileTable_printTemps (context_fileTable ());
2236 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
2240 llbug (message ("Files unclosed: %d", nfiles));
2243 fileTable_cleanup (context_fileTable ());
2250 ** cleans up temp files (if necessary) and exits
2256 DPRINTF (("llexit: %d", status));
2259 if (status == LLFAILURE)
2267 if (status != LLFAILURE)
2269 context_destroyMod ();
2270 exprNode_destroyMod ();
2273 uentry_destroyMod ();
2274 typeIdSet_destroyMod ();
2277 dmalloc_shutdown ();
2281 exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
2284 bool readOptionsFile (cstring fname, cstringSList *passThroughArgs, bool report)
2288 if (fileTable_exists (context_fileTable (), fname))
2294 message ("Multiple attempts to read options file: %s", fname),
2300 FILE *innerf = fileTable_openFile (context_fileTable (), fname, "r");
2304 fileloc fc = g_currentloc;
2305 g_currentloc = fileloc_createRc (fname);
2307 if (context_getFlag (FLG_SHOWSCAN))
2309 lldiagmsg (message ("< reading options from %q >",
2310 fileloc_outputFilename (g_currentloc)));
2313 loadrc (innerf, passThroughArgs);
2314 fileloc_reallyFree (g_currentloc);
2324 message ("Cannot open options file: %s", fname),
2334 ** This shouldn't be necessary, but Apple Darwin can't handle '"''s.
2338 loadrc (/*:open:*/ FILE *rcfile, cstringSList *passThroughArgs)
2339 /*@modifies rcfile@*/
2340 /*@ensures closed rcfile@*/
2342 char *s = mstring_create (MAX_LINE_LENGTH);
2345 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2349 while (reader_readLine (rcfile, s, MAX_LINE_LENGTH) != NULL)
2356 DPRINTF (("Line: %s", s));
2357 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2359 while (*s == ' ' || *s == '\t')
2367 bool escaped = FALSE;
2368 bool quoted = FALSE;
2371 DPRINTF (("Process: %s", s));
2372 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2373 /* comment characters */
2374 if (c == '#' || c == ';' || c == '\n')
2380 if (c == '-' || c == '+')
2387 voptgenerror (FLG_BADFLAG,
2388 message ("Bad flag syntax (+ or - expected, "
2389 "+ is assumed): %s",
2390 cstring_fromChars (s)),
2401 while ((c = *s) != '\0')
2402 { /* remember to handle spaces and quotes in -D and -U ... */
2428 if (c == ' ' || c == '\t' || c == '\n')
2430 /*@innerbreak@*/ break;
2438 DPRINTF (("Nulling: %c", *s));
2441 if (mstring_isEmpty (thisflag))
2443 llfatalerror (message ("Missing flag: %s",
2444 cstring_fromChars (os)));
2447 DPRINTF (("Flag: %s", thisflag));
2449 opt = flags_identifyFlag (cstring_fromChars (thisflag));
2451 if (flagcode_isSkip (opt))
2455 else if (flagcode_isInvalid (opt))
2457 DPRINTF (("Invalid: %s", thisflag));
2459 if (isMode (cstring_fromChars (thisflag)))
2461 context_setMode (cstring_fromChars (thisflag));
2465 voptgenerror (FLG_BADFLAG,
2466 message ("Unrecognized option: %s",
2467 cstring_fromChars (thisflag)),
2473 context_userSetFlag (opt, set);
2475 if (flagcode_hasArgument (opt))
2477 if (opt == FLG_HELP)
2480 voptgenerror (FLG_BADFLAG,
2481 message ("Cannot use help in rc files"),
2484 else if (flagcode_isPassThrough (opt)) /* -D or -U */
2486 cstring arg = cstring_fromCharsNew (thisflag);
2487 cstring_markOwned (arg);
2488 *passThroughArgs = cstringSList_add (*passThroughArgs, arg);
2489 DPRINTF (("Pass through: %s",
2490 cstringSList_unparse (*passThroughArgs)));
2492 else if (opt == FLG_INCLUDEPATH
2493 || opt == FLG_SPECPATH)
2495 cstring dir = cstring_suffix (cstring_fromChars (thisflag), 1); /* skip over I/S */
2499 case FLG_INCLUDEPATH:
2500 cppAddIncludeDir (dir);
2501 /*@switchbreak@*/ break;
2504 g_localSpecPath = cstring_toCharsSafe
2505 (message ("%s:%s", cstring_fromChars (g_localSpecPath), dir));
2507 /*@switchbreak@*/ break;
2511 else if (flagcode_hasString (opt)
2512 || flagcode_hasNumber (opt)
2513 || flagcode_hasChar (opt)
2514 || opt == FLG_INIT || opt == FLG_OPTF)
2516 cstring extra = cstring_undefined;
2521 rest = mstring_copy (s);
2522 DPRINTF (("Here: rest = %s", rest));
2526 while ((rchar = *rest) != '\0'
2527 && (isspace ((int) rchar)))
2533 DPRINTF (("Yo: %s", rest));
2535 while ((rchar = *rest) != '\0'
2536 && !isspace ((int) rchar))
2538 extra = cstring_appendChar (extra, rchar);
2543 DPRINTF (("Yo: %s", extra));
2546 if (cstring_isUndefined (extra))
2552 ("Flag %s must be followed by an argument",
2553 flagcode_unparse (opt)),
2560 DPRINTF (("Here we are: %s", extra));
2562 if (flagcode_hasNumber (opt) || flagcode_hasChar (opt))
2564 DPRINTF (("Set value flag: %s", extra));
2565 setValueFlag (opt, extra);
2567 else if (opt == FLG_OPTF)
2569 (void) readOptionsFile (extra, passThroughArgs, TRUE);
2571 else if (opt == FLG_INIT)
2574 llassert (inputStream_isUndefined (initFile));
2576 initFile = inputStream_create
2577 (cstring_copy (extra),
2578 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
2582 else if (flagcode_hasString (opt))
2584 DPRINTF (("Here: %s", extra));
2587 ** If it has "'s, we need to remove them.
2590 if (cstring_firstChar (extra) == '\"')
2592 if (cstring_lastChar (extra) == '\"')
2594 cstring unquoted = cstring_copyLength
2595 (cstring_toCharsSafe (cstring_suffix (extra, 1)),
2596 cstring_length (extra) - 2);
2598 DPRINTF (("string flag: %s -> %s", extra, unquoted));
2599 setStringFlag (opt, unquoted);
2600 cstring_free (extra);
2606 message ("Unmatched \" in option string: %s",
2609 setStringFlag (opt, extra);
2614 DPRINTF (("No quotes: %s", extra));
2615 setStringFlag (opt, extra);
2618 extra = cstring_undefined;
2626 cstring_free (extra);
2636 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2637 while ((c == ' ') || (c == '\t'))
2643 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2647 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2649 check (fileTable_closeFile (context_fileTable (), rcfile));
2652 static fileIdList preprocessFiles (fileIdList fl, bool xhfiles)
2653 /*@modifies fileSystem@*/
2655 bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
2656 int skip = (fileIdList_size (fl) / 5);
2657 int filesprocessed = 0;
2658 fileIdList dfiles = fileIdList_create ();
2660 fileloc_free (g_currentloc);
2661 g_currentloc = fileloc_createBuiltin ();
2663 fileIdList_elements (fl, fid)
2665 cstring ppfname = fileTable_fileName (fid);
2667 if (!(osd_fileIsReadable (ppfname)))
2669 lldiagmsg (message ("Cannot open file: %q", osd_outputPath (ppfname)));
2670 ppfname = cstring_undefined;
2673 if (cstring_isDefined (ppfname))
2675 fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
2679 llassert (fileTable_isXHFile (context_fileTable (), dfile));
2682 llassert (cstring_isNonEmpty (ppfname));
2686 if ((filesprocessed % skip) == 0)
2688 if (filesprocessed == 0) {
2689 fprintf (stderr, " ");
2692 fprintf (stderr, ".");
2695 (void) fflush (stderr);
2700 DPRINTF (("outfile: %s", fileTable_fileName (dfile)));
2702 if (cppProcess (ppfname, fileTable_fileName (dfile)) != 0)
2704 llfatalerror (message ("Preprocessing error for file: %s",
2705 fileTable_rootFileName (fid)));
2708 fileIdList_add (dfiles, dfile);
2710 } end_fileIdList_elements;
2715 /* This should be in an lclUtils.c file... */
2717 char *specFullName (char *specfile, /*@out@*/ char **inpath)
2719 /* extract the path and the specname associated with the given file */
2720 char *specname = (char *) dmalloc (sizeof (*specname)
2721 * (strlen (specfile) + 9));
2722 char *ospecname = specname;
2723 char *path = (char *) dmalloc (sizeof (*path) * (strlen (specfile)));
2727 /* initialized path to empty string or may have accidental garbage */
2730 /*@-mayaliasunique@*/
2731 strcpy (specname, specfile);
2732 /*@=mayaliasunique@*/
2734 /* trim off pathnames in specfile */
2735 size = strlen (specname);
2737 for (i = size_toInt (size) - 1; i >= 0; i--)
2739 if (specname[i] == CONNECTCHAR)
2741 /* strcpy (specname, (char *)specname+i+1); */
2742 for (j = 0; j <= i; j++) /* include '/' */
2744 path[j] = specname[j];
2754 ** also remove .lcl file extension, assume it's the last extension
2758 size = strlen (specname);
2760 for (i = size_toInt (size) - 1; i >= 0; i--)
2762 if (specname[i] == '.')
2772 ** If specname no longer points to the original char,
2773 ** we need to allocate a new pointer and copy the string.
2776 if (specname != ospecname) {
2777 char *rspecname = (char *) dmalloc (sizeof (*rspecname) * (strlen (specname) + 1));
2778 strcpy (rspecname, specname); /* evs 2000-05-16: Bug: was ospecname! */
2787 void warnSysFiles(fileIdList files)
2789 fileIdList_elements (files, file)
2792 if (fileTable_isSystemFile (context_fileTable (), file) )
2794 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);
2797 end_fileIdList_elements;