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: splint@cs.virginia.edu
21 ** To report a bug: splint-bug@cs.virginia.edu
22 ** For more information: http://www.splint.org
27 ** Main module for Splint annotation-assisted program checker
33 ** Ensure that WIN32 and _WIN32 are both defined or both undefined.
38 # error "Inconsistent definitions."
42 # error "Inconsistent definitions."
51 # include "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@*/ ;
120 void lslCleanup (void)
121 /*@globals killed g_symtab@*/
122 /*@modifies internalState, g_symtab@*/
125 ** Cleanup all the LCL/LSL.
128 static bool didCleanup = FALSE;
130 llassert (!didCleanup);
135 lsymbol_destroyMod ();
136 LCLSynTableCleanup ();
137 LCLTokenTableCleanup ();
138 LCLScanLineCleanup ();
141 /* clean up LSL parsing */
144 ltokenTableCleanup ();
148 symtable_free (g_symtab);
154 /*@globals undef g_symtab; @*/
155 /*@modifies g_symtab, internalState, fileSystem; @*/
158 ** Open init file provided by user, or use the default LCL init file
161 cstring larchpath = context_getLarchPath ();
162 inputStream LSLinitFile = inputStream_undefined;
166 if (inputStream_isUndefined (initFile))
168 initFile = inputStream_create (cstring_makeLiteral (INITFILENAME),
169 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
172 if (!inputStream_getPath (larchpath, initFile))
174 lldiagmsg (message ("Continuing without LCL init file: %s",
175 inputStream_fileName (initFile)));
179 if (!inputStream_open (initFile))
181 lldiagmsg (message ("Continuing without LCL init file: %s",
182 inputStream_fileName (initFile)));
188 if (!inputStream_open (initFile))
190 lldiagmsg (message ("Continuing without LCL init file: %s",
191 inputStream_fileName (initFile)));
195 /* Initialize checker */
203 LCLTokenTableInit ();
215 /* need this to initialize LCL checker */
217 llassert (inputStream_isDefined (initFile));
218 if (inputStream_isOpen (initFile))
222 LCLScanReset (initFile);
223 LCLProcessInitFileInit ();
224 LCLProcessInitFileReset ();
227 LCLProcessInitFile ();
228 LCLProcessInitFileCleanup ();
231 check (inputStream_close (initFile));
234 /* Initialize LSL init files, for parsing LSL signatures from LSL */
236 LSLinitFile = inputStream_create (cstring_makeLiteral ("lslinit.lsi"),
237 cstring_makeLiteralTemp (".lsi"),
240 if (!inputStream_getPath (larchpath, LSLinitFile))
242 lldiagmsg (message ("Continuing without LSL init file: %s",
243 inputStream_fileName (LSLinitFile)));
247 if (!inputStream_open (LSLinitFile))
249 lldiagmsg (message ("Continuing without LSL init file: %s",
250 inputStream_fileName (LSLinitFile)));
266 if (inputStream_isOpen (LSLinitFile))
269 LSLScanReset (LSLinitFile);
270 LSLProcessInitFileInit ();
272 LSLProcessInitFile ();
274 check (inputStream_close (LSLinitFile));
277 inputStream_free (LSLinitFile);
282 (cstring_makeLiteral ("LSL init file error. Attempting to continue."));
286 g_symtab = symtable_new ();
289 ** sort_init must come after symtab has been initialized
298 ** Equivalent to importing old spec_csupport.lcl
299 ** define immutable LCL type "bool" and bool constants TRUE and FALSE
300 ** and initialized them to be equal to LSL's "true" and "false".
302 ** Reads in CTrait.syms (derived from CTrait.lsl) on LARCH_PATH.
306 LCLReportEolTokens (FALSE);
310 lslProcess (fileIdList lclfiles)
311 /*@globals undef g_currentSpec, undef g_currentSpecName, g_currentloc,
312 undef killed g_symtab; @*/
313 /*@modifies g_currentSpec, g_currentSpecName, g_currentloc, internalState, fileSystem; @*/
316 bool parser_status = FALSE;
317 bool overallStatus = FALSE;
321 context_resetSpecLines ();
323 fileIdList_elements (lclfiles, fid)
325 cstring actualName = cstring_undefined;
326 cstring fname = fileTable_fileName (fid);
328 if (osd_getPath (cstring_fromChars (g_localSpecPath),
329 fname, &actualName) == OSD_FILENOTFOUND)
331 if (mstring_equal (g_localSpecPath, "."))
333 lldiagmsg (message ("Spec file not found: %q", osd_outputPath (fname)));
337 lldiagmsg (message ("Spec file not found: %q (on %s)",
338 osd_outputPath (fname),
339 cstring_fromChars (g_localSpecPath)));
344 inputStream specFile;
346 char *namePtr = actualName;
348 while (*namePtr == '.' && *(namePtr + 1) == CONNECTCHAR)
352 /*@noaccess cstring@*/
354 g_currentSpec = cstring_fromCharsNew (namePtr);
356 specFile = inputStream_create (cstring_copy (g_currentSpec),
357 LCL_EXTENSION, TRUE);
359 llassert (inputStream_isDefined (specFile));
361 g_currentSpecName = specFullName
362 (cstring_toCharsSafe (g_currentSpec),
367 if (context_getFlag (FLG_SHOWSCAN))
369 lldiagmsg (message ("< reading spec %s >", g_currentSpec));
372 /* Open source file */
374 if (!inputStream_open (specFile))
376 lldiagmsg (message ("Cannot open file: %q",
377 osd_outputPath (inputStream_fileName (specFile))));
378 inputStream_free (specFile);
382 scopeInfo dummy_scope = (scopeInfo) dmalloc (sizeof (*dummy_scope));
383 dummy_scope->kind = SPE_INVALID;
386 LCLScanReset (specFile);
389 ** Minor hacks to allow more than one LCL file to
390 ** be scanned, while keeping initializations
393 symtable_enterScope (g_symtab, dummy_scope);
394 resetImports (cstring_fromChars (g_currentSpecName));
395 context_enterLCLfile ();
396 (void) lclHadNewError ();
398 parser_status = (ylparse () != 0);
399 context_exitLCLfile ();
401 overallStatus = parser_status || lclHadNewError ();
403 if (context_getFlag (FLG_DOLCS))
407 outputLCSFile (path, "%FAILED Output from ",
412 outputLCSFile (path, "%PASSED Output from ",
417 (void) inputStream_close (specFile);
418 inputStream_free (specFile);
420 symtable_exitScope (g_symtab);
423 cstring_free (actualName);
424 } end_fileIdList_elements;
426 /* Can cleanup lsl stuff right away */
430 g_currentSpec = cstring_undefined;
431 g_currentSpecName = NULL;
435 static void handlePassThroughFlag (char *arg)
438 char *quotechar = strchr (curarg, '\"');
441 char *freearg = NULL;
443 while (quotechar != NULL)
445 if (*(quotechar - 1) == '\\')
447 char *tp = quotechar - 2;
458 curarg = quotechar + 1;
459 quotechar = strchr (curarg, '\"');
464 llassert (quotechar != NULL);
466 offset = (quotechar - arg) + 2;
470 arg = cstring_toCharsSafe
471 (message ("%s\"\'%s",
472 cstring_fromChars (arg),
473 cstring_fromChars (quotechar + 1)));
479 arg = cstring_toCharsSafe
480 (message ("%s\'\"%s",
481 cstring_fromChars (arg),
482 cstring_fromChars (quotechar + 1)));
487 curarg = arg + offset;
488 quotechar = strchr (curarg, '\"');
494 voptgenerror (FLG_BADFLAG,
495 message ("Unclosed quote in flag: %s",
496 cstring_fromChars (arg)),
505 ** If the value is surrounded by single quotes ('), remove
506 ** them. This is an artifact of UNIX command line?
509 def = osd_fixDefine (cstring_fromChars (arg + 1));
510 DPRINTF (("Do define: %s", def));
512 DPRINTF (("After define"));
514 } else if (arg[0] == 'U') {
515 cppDoUndefine (cstring_fromChars (arg + 1));
524 void showHerald (void)
526 if (hasShownHerald || context_getFlag (FLG_QUIET)) return;
530 fprintf (g_msgstream, "%s\n\n", SPLINT_VERSION);
531 hasShownHerald = TRUE;
536 static cstring findLarchPathFile (/*@temp@*/ cstring s)
541 status = osd_getPath (context_getLarchPath (), s, &pathName);
543 if (status == OSD_FILEFOUND)
547 else if (status == OSD_FILENOTFOUND)
550 lldiagmsg (message ("Cannot find file on LARCH_PATH: %s", s));
552 else if (status == OSD_PATHTOOLONG)
554 /* Directory and filename are too long. Report error. */
555 llbuglit ("soure_getPath: Filename plus directory from search path too long");
562 return cstring_undefined;
565 static void addLarchPathFile (fileIdList files, /*@temp@*/ cstring s)
567 cstring pathName = findLarchPathFile (s);
569 if (cstring_isDefined (pathName))
571 if (fileTable_exists (context_fileTable (), pathName))
574 lldiagmsg (message ("File listed multiple times: %s", pathName));
575 cstring_free (pathName);
579 fileIdList_add (files, fileTable_addFileOnly (context_fileTable (), pathName));
584 static void addFile (fileIdList files, /*@only@*/ cstring s)
586 if (fileTable_exists (context_fileTable (), s))
589 lldiagmsg (message ("File listed multiple times: %s", s));
594 fileIdList_add (files, fileTable_addFileOnly (context_fileTable (), s));
598 static void addXHFile (fileIdList files, /*@temp@*/ cstring s)
600 cstring pathName = findLarchPathFile (s);
602 if (cstring_isDefined (pathName))
604 if (fileTable_exists (context_fileTable (), pathName))
607 lldiagmsg (message ("File listed multiple times: %s", s));
611 fileIdList_add (files, fileTable_addXHFile (context_fileTable (), pathName));
615 cstring_free (pathName);
619 ** Disable MSVC++ warning about return value. Methinks humbly splint control
620 ** comments are a mite more legible.
624 # pragma warning (disable:4035)
627 int main (int argc, char *argv[])
629 /*@globals killed undef g_currentloc,
633 /*@modifies g_currentloc, fileSystem,
637 /*@globals killed undef g_currentloc,
638 killed undef initFile,
639 killed g_localSpecPath,
640 killed undef g_currentSpec,
641 killed undef g_currentSpecName,
645 /*@modifies g_currentloc, initFile,
646 g_localSpecPath, g_currentSpec, g_currentSpecName, fileSystem,
651 bool first_time = TRUE;
652 bool showhelp = FALSE;
655 inputStream sourceFile = inputStream_undefined;
657 fileIdList dercfiles;
658 cstringSList fl = cstringSList_undefined;
659 cstringSList passThroughArgs = cstringSList_undefined;
660 fileIdList cfiles, xfiles, lclfiles, mtfiles;
661 clock_t before, lcltime, libtime, pptime, cptime, rstime;
665 _wildcard (&argc, &argv);
668 g_msgstream = stdout;
670 (void) signal (SIGINT, interrupt);
671 (void) signal (SIGSEGV, interrupt);
673 cfiles = fileIdList_create ();
674 xfiles = fileIdList_create ();
675 lclfiles = fileIdList_create ();
676 mtfiles = fileIdList_create ();
679 clabstract_initMod ();
680 typeIdSet_initMod ();
681 cppReader_initMod ();
686 g_currentloc = fileloc_createBuiltin ();
691 context_setInCommandLine ();
703 ** Add include directories from environment.
707 cstring incval = cstring_copy (osd_getEnvironmentVariable (INCLUDEPATH_VAR));
708 cstring oincval = incval;
710 if (cstring_isDefined (incval))
713 ** Each directory on the include path is a system include directory.
716 DPRINTF (("include: %s", incval));
717 context_setString (FLG_SYSTEMDIRS, cstring_copy (incval));
719 while (cstring_isDefined (incval))
722 char *nextsep = strchr (incval, PATH_SEPARATOR);
728 dir = cstring_copy (incval);
730 if (cstring_length (dir) == 0
731 || !isalpha ((int) cstring_firstChar (dir)))
734 ** win32 environment values can have special values,
740 cppAddIncludeDir (dir);
743 *nextsep = PATH_SEPARATOR;
744 incval = cstring_fromChars (nextsep + 1);
752 /*@noaccess cstring@*/
755 else /* 2001-09-09: herbert */
757 /* Put C_INCLUDE_PATH directories in sysdirs */
758 cstring cincval = osd_getEnvironmentVariable (cstring_makeLiteralTemp ("C_INCLUDE_PATH"));
759 if (cstring_isDefined (cincval))
761 context_setString (FLG_SYSTEMDIRS, cstring_copy (cincval));
766 cstring_free (oincval);
770 ** check RCFILE for default flags
774 cstring home = osd_getHomeDir ();
775 cstring fname = cstring_undefined;
776 bool defaultf = TRUE;
779 for (i = 1; i < argc; i++)
784 if (*thisarg == '-' || *thisarg == '+')
786 bool set = (*thisarg == '+');
792 ** Don't report warnings this time
795 opt = flags_identifyFlagQuiet (cstring_fromChars (thisarg));
801 else if (opt == FLG_SHOWSCAN || opt == FLG_WARNRC || opt == FLG_PARENFILEFORMAT)
804 ** Need to set it immediately, so rc file scan is displayed
807 context_userSetFlag (opt, set);
809 else if (opt == FLG_OPTF)
814 fname = cstring_fromChars (argv[i]);
815 (void) readOptionsFile (fname, &passThroughArgs, TRUE);
819 (cstring_makeLiteral ("Flag f to select options file "
820 "requires an argument"));
824 ; /* wait to process later */
831 if (!nof && defaultf)
834 ** No explicit rc file, first try reading ~/.splintrc
837 if (cstring_isUndefined (fname))
839 if (!cstring_isEmpty (home))
841 bool readhomerc, readaltrc;
842 cstring homename, altname;
844 homename = message ("%s%h%s", home, CONNECTCHAR,
845 cstring_fromChars (RCFILE));
846 readhomerc = readOptionsFile (homename, &passThroughArgs, FALSE);
849 ** Try ~/.splintrc also for historical accuracy
852 altname = message ("%s%h%s", home, CONNECTCHAR,
853 cstring_fromChars (ALTRCFILE));
854 readaltrc = readOptionsFile (altname, &passThroughArgs, FALSE);
856 if (readhomerc && readaltrc)
861 message ("Found both %s and %s files. Using both files, "
862 "but recommend using only %s to avoid confusion.",
863 homename, altname, homename),
867 cstring_free (homename);
868 cstring_free (altname);
873 ** Next, read .splintrc in the current working directory
877 cstring rcname = message ("%s%s",osd_getCurrentDirectory (), cstring_fromChars (RCFILE));
878 cstring altname = message ("%s%s",osd_getCurrentDirectory (), cstring_fromChars (ALTRCFILE));
879 bool readrc, readaltrc;
881 readrc = readOptionsFile (rcname, &passThroughArgs, FALSE);
882 readaltrc = readOptionsFile (altname, &passThroughArgs, FALSE);
884 if (readrc && readaltrc)
886 voptgenerror (FLG_WARNRC,
887 message ("Found both %s and %s files. Using both files, "
888 "but recommend using only %s to avoid confusion.",
889 rcname, altname, rcname),
894 cstring_free (rcname);
895 cstring_free (altname);
902 for (i = 1; i < argc; i++)
918 if (*thisarg == '-' || *thisarg == '+')
920 thisarg++; /* skip '-' */
922 if (mstring_equal (thisarg, "modes"))
924 llmsg (describeModes ());
926 else if (mstring_equal (thisarg, "vars")
927 || mstring_equal (thisarg, "env"))
931 else if (mstring_equal (thisarg, "annotations"))
935 else if (mstring_equal (thisarg, "parseerrors"))
939 else if (mstring_equal (thisarg, "comments"))
943 else if (mstring_equal (thisarg, "prefixcodes"))
945 describePrefixCodes ();
947 else if (mstring_equal (thisarg, "references")
948 || mstring_equal (thisarg, "refs"))
952 else if (mstring_equal (thisarg, "mail"))
956 else if (mstring_equal (thisarg, "maintainer")
957 || mstring_equal (thisarg, "version"))
961 else if (mstring_equal (thisarg, "flags"))
965 char *next = argv[i + 1];
967 if (specialFlagsHelp (next))
973 flagkind k = identifyCategory (cstring_fromChars (next));
989 cstring s = describeFlag (cstring_fromChars (thisarg));
991 if (cstring_isDefined (s))
999 if (*thisarg == '-' || *thisarg == '+')
1001 bool set = (*thisarg == '+');
1004 thisarg++; /* skip '-' */
1005 flagname = cstring_fromChars (thisarg);
1007 DPRINTF (("Flag: %s", flagname));
1008 opt = flags_identifyFlag (flagname);
1009 DPRINTF (("Flag: %s", flagcode_unparse (opt)));
1011 if (flagcode_isSkip (opt) || opt == FLG_SHOWSCAN || opt == FLG_WARNRC || opt == FLG_PARENFILEFORMAT)
1013 /* showscan already processed */
1014 DPRINTF (("Skipping!"));
1016 else if (flagcode_isInvalid (opt))
1018 DPRINTF (("Invalid: %s", flagname));
1020 if (isMode (flagname))
1022 context_setMode (flagname);
1026 DPRINTF (("Error!"));
1027 voptgenerror (FLG_BADFLAG,
1028 message ("Unrecognized option: %s",
1029 cstring_fromChars (thisarg)),
1035 context_userSetFlag (opt, set);
1037 if (flagcode_hasArgument (opt))
1039 if (opt == FLG_HELP)
1043 else if (flagcode_isPassThrough (opt)) /* -D or -U */
1045 passThroughArgs = cstringSList_add
1046 (passThroughArgs, cstring_fromChars (thisarg));
1048 else if (flagcode_hasNumber (opt))
1052 setValueFlag (opt, cstring_fromChars (argv[i]));
1058 ("Flag %s must be followed by a number",
1059 flagcode_unparse (opt)));
1062 else if (flagcode_hasChar (opt))
1066 setValueFlag (opt, cstring_fromChars (argv[i]));
1072 ("Flag %s must be followed by a character",
1073 flagcode_unparse (opt)));
1076 else if (opt == FLG_INCLUDEPATH || opt == FLG_SPECPATH)
1078 cstring dir = cstring_suffix (cstring_fromChars (thisarg), 1); /* skip over I */
1082 case FLG_INCLUDEPATH:
1083 cppAddIncludeDir (dir);
1084 /*@switchbreak@*/ break;
1087 g_localSpecPath = cstring_toCharsSafe
1089 cstring_fromChars (g_localSpecPath),
1093 /*@switchbreak@*/ break;
1097 else if (flagcode_hasString (opt)
1098 || opt == FLG_INIT || opt == FLG_OPTF)
1102 cstring arg = cstring_fromChars (argv[i]);
1104 if (opt == FLG_OPTF)
1106 ; /* -f already processed */
1108 else if (opt == FLG_INIT)
1111 initFile = inputStream_create
1113 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
1120 DPRINTF (("String flag: %s / %s",
1121 flagcode_unparse (opt), arg));
1122 if (opt == FLG_MTSFILE)
1125 ** arg identifies mts files
1127 cstring tmp = message ("%s%s", arg, MTS_EXTENSION);
1128 addLarchPathFile (mtfiles, tmp);
1130 tmp = message ("%s%s", arg, XH_EXTENSION);
1131 addXHFile (xfiles, tmp);
1136 setStringFlag (opt, cstring_copy (arg));
1144 ("Flag %s must be followed by a string",
1145 flagcode_unparse (opt)));
1155 else /* its a filename */
1157 DPRINTF (("Adding filename: %s", thisarg));
1158 fl = cstringSList_add (fl, cstring_fromChars (thisarg));
1167 ** create lists of C and LCL files
1170 cstringSList_elements (fl, current)
1172 cstring ext = fileLib_getExtension (current);
1174 if (cstring_isUndefined (ext))
1176 /* no extension --- both C and LCL with default extensions */
1178 addFile (cfiles, message ("%s%s", current, C_EXTENSION));
1179 addFile (lclfiles, message ("%s%s", current, LCL_EXTENSION));
1181 else if (cstring_equal (ext, XH_EXTENSION))
1183 addXHFile (xfiles, current);
1185 else if (cstring_equal (ext, PP_EXTENSION))
1187 if (!context_getFlag (FLG_NOPP))
1190 (FLG_FILEEXTENSIONS,
1191 message ("File extension %s used without +nopp flag (will be processed as C source code): %s",
1196 addFile (cfiles, cstring_copy (current));
1198 else if (cstring_equal (ext, LCL_EXTENSION))
1200 addFile (lclfiles, cstring_copy (current));
1202 else if (fileLib_isCExtension (ext))
1204 addFile (cfiles, cstring_copy (current));
1206 else if (cstring_equal (ext, MTS_EXTENSION))
1208 addLarchPathFile (mtfiles, current);
1213 (FLG_FILEEXTENSIONS,
1214 message ("Unrecognized file extension: %s (assuming %s is C source code)",
1218 addFile (cfiles, cstring_copy (current));
1220 } end_cstringSList_elements;
1228 fprintf (g_msgstream, "\n");
1230 fileIdList_free (cfiles);
1231 fileIdList_free (xfiles);
1232 fileIdList_free (lclfiles);
1241 inittime = clock ();
1243 context_resetErrors ();
1244 context_clearInCommandLine ();
1246 anylcl = !fileIdList_isEmpty (lclfiles);
1248 if (context_doMerge ())
1250 cstring m = context_getMerge ();
1252 if (context_getFlag (FLG_SHOWSCAN))
1254 fprintf (g_msgstream, "< loading %s ", cstring_toCharsSafe (m));
1259 if (context_getFlag (FLG_SHOWSCAN))
1261 fprintf (g_msgstream, " >\n");
1264 if (!usymtab_existsType (context_getBoolName ()))
1266 usymtab_initBool ();
1271 if (!context_getFlag (FLG_NOLIB) && loadStandardState ())
1280 /* setup bool type and constants */
1281 usymtab_initBool ();
1284 fileloc_free (g_currentloc);
1285 g_currentloc = fileloc_createBuiltin ();
1288 ** Read metastate files (must happen before loading libraries)
1291 fileIdList_elements (mtfiles, mtfile)
1293 context_setFileId (mtfile);
1295 if (context_getFlag (FLG_SHOWSCAN))
1297 lldiagmsg (message ("< processing %s >", fileTable_rootFileName (mtfile)));
1300 mtreader_readFile (cstring_copy (fileTable_fileName (mtfile)));
1301 } end_fileIdList_elements;
1308 llfatalerror (cstring_makeLiteral ("This version of Splint does not handle LCL files."));
1310 lslProcess (lclfiles);
1314 usymtab_initGlobalMarker ();
1319 ** call the pre-preprocessor and /lib/cpp to generate appropriate
1324 context_setInCommandLine ();
1326 DPRINTF (("Pass through: %s", cstringSList_unparse (passThroughArgs)));
1328 cstringSList_elements (passThroughArgs, thisarg) {
1329 handlePassThroughFlag (cstring_toCharsSafe (thisarg));
1330 } end_cstringSList_elements;
1332 cstringSList_free (passThroughArgs);
1336 DPRINTF (("Initializing cpp reader!"));
1337 cppReader_initialize ();
1338 cppReader_saveDefinitions ();
1340 context_clearInCommandLine ();
1342 if (!context_getFlag (FLG_NOPP))
1348 if (context_getFlag (FLG_SHOWSCAN))
1350 fprintf (stderr, "< preprocessing");
1355 context_setPreprocessing ();
1356 dercfiles = preprocessFiles (xfiles, TRUE);
1357 tfiles = preprocessFiles (cfiles, FALSE);
1358 dercfiles = fileIdList_append (dercfiles, tfiles);
1359 fileIdList_free (tfiles);
1361 context_clearPreprocessing ();
1363 fileIdList_free (cfiles);
1365 if (context_getFlag (FLG_SHOWSCAN))
1367 fprintf (stderr, " >\n");
1375 dercfiles = fileIdList_append (cfiles, xfiles);
1380 ** now, check all the corresponding C files
1382 ** (for now these are just <file>.c, but after pre-processing
1383 ** will be <tmpprefix>.<file>.c)
1388 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1392 llbug (message ("Files unclosed: %d", nfiles));
1397 DPRINTF (("Initializing..."));
1399 exprNode_initMod ();
1401 DPRINTF (("Okay..."));
1403 fileIdList_elements (dercfiles, fid)
1405 sourceFile = inputStream_create (cstring_copy (fileTable_fileName (fid)), C_EXTENSION, TRUE);
1406 context_setFileId (fid);
1408 /* Open source file */
1410 if (inputStream_isUndefined (sourceFile) || (!inputStream_open (sourceFile)))
1412 /* previously, this was ignored ?! */
1413 llbug (message ("Could not open temp file: %s", fileTable_fileName (fid)));
1417 yyin = inputStream_getFile (sourceFile); /*< shared <- only */
1419 llassert (yyin != NULL);
1421 if (context_getFlag (FLG_SHOWSCAN))
1423 lldiagmsg (message ("< checking %q >", osd_outputPath (fileTable_rootFileName (fid))));
1427 ** Every time, except the first time, through the loop,
1428 ** need to call yyrestart to clean up the parse buffer.
1433 (void) yyrestart (yyin);
1440 DPRINTF (("Entering..."));
1441 context_enterFile ();
1443 context_exitCFile ();
1445 (void) inputStream_close (sourceFile);
1447 } end_fileIdList_elements;
1451 /* process any leftover macros */
1453 context_processAllMacros ();
1455 /* check everything that was specified was defined */
1457 /* don't check if no c files were processed ?
1458 ** is this correct behaviour?
1461 if (context_getFlag (FLG_SHOWSCAN))
1463 lldiagmsg (cstring_makeLiteral ("< global checks >"));
1468 if (context_getLinesProcessed () > 0)
1470 usymtab_allDefined ();
1473 if (context_maybeSet (FLG_TOPUNUSED))
1475 uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main"));
1477 if (uentry_isValid (ue))
1479 uentry_setUsed (ue, fileloc_observeBuiltin ());
1485 if (context_maybeSet (FLG_EXPORTLOCAL))
1487 usymtab_exportLocal ();
1491 if (context_maybeSet (FLG_EXPORTHEADER))
1493 usymtab_exportHeader ();
1496 if (context_getFlag (FLG_SHOWUSES))
1498 usymtab_displayAllUses ();
1501 context_checkSuppressCounts ();
1503 if (context_doDump ())
1505 cstring dump = context_getDump ();
1516 if (context_getFlag (FLG_SHOWSUMMARY))
1523 bool isQuiet = context_getFlag (FLG_QUIET);
1524 cstring specErrors = cstring_undefined;
1526 int nspecErrors = lclNumberErrors ();
1531 if (context_neednl ())
1532 fprintf (g_msgstream, "\n");
1535 if (nspecErrors > 0)
1537 if (nspecErrors == context_getLCLExpect ())
1540 message ("%d spec warning%&, as expected\n ",
1545 if (context_getLCLExpect () > 0)
1548 message ("%d spec warning%&, expected %d\n ",
1550 (int) context_getLCLExpect ());
1554 specErrors = message ("%d spec warning%&\n ",
1562 if (context_getLCLExpect () > 0)
1564 specErrors = message ("No spec warnings, expected %d\n ",
1565 (int) context_getLCLExpect ());
1571 if (context_anyErrors ())
1573 if (context_numErrors () == context_getExpect ())
1576 llmsg (message ("Finished checking --- "
1577 "%s%d code warning%&, as expected",
1578 specErrors, context_numErrors ()));
1583 if (context_getExpect () > 0)
1587 ("Finished checking --- "
1588 "%s%d code warning%&, expected %d",
1589 specErrors, context_numErrors (),
1590 (int) context_getExpect ()));
1600 llmsg (message ("Finished checking --- "
1601 "%s%d code warning%&",
1602 specErrors, context_numErrors ()));
1611 if (context_getExpect () > 0)
1615 ("Finished checking --- "
1616 "%sno code warnings, expected %d",
1618 (int) context_getExpect ()));
1625 if (context_getLinesProcessed () > 0)
1627 if (cstring_isEmpty (specErrors))
1631 llmsg (message ("Finished checking --- no warnings"));
1638 llmsg (message ("Finished checking --- %sno code warnings",
1646 llmsg (message ("Finished checking --- %sno code processed",
1653 cstring_free (specErrors);
1656 if (context_getFlag (FLG_STATS))
1658 clock_t ttime = clock () - before;
1659 int specLines = context_getSpecLinesProcessed ();
1665 fprintf (g_msgstream, "%d spec, ", specLines);
1668 # ifndef CLOCKS_PER_SEC
1669 fprintf (g_msgstream, "%d source lines in %ld time steps (steps/sec unknown)\n",
1670 context_getLinesProcessed (),
1673 fprintf (g_msgstream, "%d source lines in %.2f s.\n",
1674 context_getLinesProcessed (),
1675 (double) ttime / CLOCKS_PER_SEC);
1683 if (context_getFlag (FLG_TIMEDIST))
1685 clock_t ttime = clock () - before;
1689 char *msg = (char *) dmalloc (256 * sizeof (*msg));
1694 "Time distribution (percent): initialize %.2f / lcl %.2f / "
1695 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1696 (100.0 * (double) (libtime - before) / ttime),
1697 (100.0 * (double) (lcltime - libtime) / ttime),
1698 (100.0 * (double) (pptime - lcltime) / ttime),
1699 (100.0 * (double) (cptime - pptime) / ttime),
1700 (100.0 * (double) (rstime - cptime) / ttime));
1705 "Time distribution (percent): initialize %.2f / "
1706 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1707 (100.0 * (double) (libtime - before) / ttime),
1708 (100.0 * (double) (pptime - libtime) / ttime),
1709 (100.0 * (double) (cptime - pptime) / ttime),
1710 (100.0 * (double) (rstime - cptime) / ttime));
1713 llgenindentmsgnoloc (cstring_fromCharsO (msg));
1717 llexit (expsuccess ? LLSUCCESS : LLFAILURE);
1718 BADBRANCHRET (LLFAILURE);
1723 ** Reenable return value warnings.
1725 # pragma warning (default:4035)
1733 llmsg (message ("Source files are .c, .h and %s files. If there is no suffix,",
1735 llmsg (message (" Splint will look for <file>.c and <file>%s.", LCL_EXTENSION));
1737 llmsglit ("Use splint -help <topic or flag name> for more information");
1739 llmsglit ("Topics:");
1741 llmsglit (" annotations (describes source-code annotations)");
1742 llmsglit (" comments (describes control comments)");
1743 llmsglit (" flags (describes flag categories)");
1744 llmsglit (" flags <category> (describes flags in category)");
1745 llmsglit (" flags all (short description of all flags)");
1746 llmsglit (" flags alpha (list all flags alphabetically)");
1747 llmsglit (" flags full (full description of all flags)");
1748 llmsglit (" mail (information on mailing lists)");
1749 llmsglit (" modes (show mode settings)");
1750 llmsglit (" parseerrors (help on handling parser errors)");
1751 llmsglit (" prefixcodes (character codes in namespace prefixes)");
1752 llmsglit (" references (sources for more information)");
1753 llmsglit (" vars (environment variables)");
1754 llmsglit (" version (information on compilation, maintainer)");
1759 specialFlagsHelp (char *next)
1761 if ((next != NULL) && (*next != '-') && (*next != '+'))
1763 if (mstring_equal (next, "alpha"))
1768 else if (mstring_equal (next, "all"))
1770 printAllFlags (TRUE, FALSE);
1773 else if (mstring_equal (next, "categories")
1774 || mstring_equal (next, "cats"))
1776 listAllCategories ();
1779 else if (mstring_equal (next, "full"))
1781 printAllFlags (FALSE, TRUE);
1784 else if (mstring_equal (next, "manual"))
1786 printFlagManual (FALSE);
1789 else if (mstring_equal (next, "webmanual"))
1791 printFlagManual (TRUE);
1806 printParseErrors (void)
1808 llmsglit ("Parse Errors");
1809 llmsglit ("------------");
1811 llmsglit ("Splint will sometimes encounter a parse error for code that "
1812 "can be parsed with a local compiler. There are a few likely "
1813 "causes for this and a number of techniques that can be used "
1814 "to work around the problem.");
1816 llmsglit ("Compiler extensions --- compilers sometimes extend the C "
1817 "language with compiler-specific keywords and syntax. While "
1818 "it is not advisible to use these, oftentimes one has no choice "
1819 "when the system header files use compiler extensions. ");
1821 llmsglit ("Splint supports some of the GNU (gcc) compiler extensions, "
1822 "if the +gnuextensions flag is set. You may be able to workaround "
1823 "other compiler extensions by using a pre-processor define. "
1824 "Alternately, you can surround the unparseable code with");
1826 llmsglit (" # ifndef S_SPLINT_S");
1828 llmsglit (" # endif");
1830 /* evans 2000-12-21 fixed typo reported by Jeroen Ruigrok/Asmodai */
1831 llmsglit ("Missing type definitions --- an undefined type name will usually "
1832 "lead to a parse error. This often occurs when a standard header "
1833 "file defines some type that is not part of the standard library. ");
1834 llmsglit ("By default, Splint does not process the local files corresponding "
1835 "to standard library headers, but uses a library specification "
1836 "instead so dependencies on local system headers can be detected. "
1837 "If another system header file that does not correspond to a "
1838 "standard library header uses one of these superfluous types, "
1839 "a parse error will result.");
1841 llmsglit ("If the parse error is inside a posix standard header file, the "
1842 "first thing to try is +posixlib. This makes Splint use "
1843 "the posix library specification instead of reading the posix "
1846 llmsglit ("Otherwise, you may need to either manually define the problematic "
1847 "type (e.g., add -Dmlink_t=int to your .splintrc file) or force "
1848 "splint to process the header file that defines it. This is done "
1849 "by setting -skipisoheaders or -skipposixheaders before "
1850 "the file that defines the type is #include'd.");
1851 llmsglit ("(See splint -help "
1852 "skipisoheaders and splint -help skipposixheaders for a list of "
1853 "standard headers.) For example, if <sys/local.h> uses a type "
1854 "defined by posix header <sys/types.h> but not defined by the "
1855 "posix library, we might do: ");
1857 llmsglit (" /*@-skipposixheaders@*/");
1858 llmsglit (" # include <sys/types.h>");
1859 llmsglit (" /*@=skipposixheaders@*/");
1860 llmsglit (" # include <sys/local.h>");
1862 llmsglit ("to force Splint to process <sys/types.h>.");
1864 llmsglit ("At last resort, +trytorecover can be used to make Splint attempt "
1865 "to continue after a parse error. This is usually not successful "
1866 "and the author does not consider assertion failures when +trytorecover "
1867 "is used to be bugs.");
1871 printAnnotations (void)
1873 llmsglit ("Annotations");
1874 llmsglit ("-----------");
1876 llmsglit ("Annotations are semantic comments that document certain "
1877 "assumptions about functions, variables, parameters, and types. ");
1879 llmsglit ("They may be used to indicate where the representation of a "
1880 "user-defined type is hidden, to limit where a global variable may "
1881 "be used or modified, to constrain what a function implementation "
1882 "may do to its parameters, and to express checked assumptions about "
1883 "variables, types, structure fields, function parameters, and "
1884 "function results.");
1886 llmsglit ("Annotations are introduced by \"/*@\". The role of the @ may be "
1887 "played by any printable character, selected using -commentchar <char>.");
1889 llmsglit ("Consult the User's Guide for descriptions of checking associated with each annotation.");
1891 llmsglit ("Globals: (in function declarations)");
1892 llmsglit (" /*@globals <globitem>,+ @*/");
1893 llmsglit (" globitem is an identifier, internalState or fileSystem");
1895 llmsglit ("Modifies: (in function declarations)");
1896 llmsglit (" /*@modifies <moditem>,+ @*/");
1897 llmsglit (" moditem is an lvalue");
1898 llmsglit (" /*@modifies nothing @*/");
1899 llmsglit (" /*@*/ (Abbreviation for no globals and modifies nothing.)");
1901 llmsglit ("Iterators:");
1902 llmsglit (" /*@iter <identifier> (<parameter-type-list>) @*/ - declare an iterator");
1904 llmsglit ("Constants:");
1905 llmsglit (" /*@constant <declaration> @*/ - declares a constant");
1907 llmsglit ("Alternate Types:");
1908 llmsglit (" /*@alt <basic-type>,+ @*/");
1909 llmsglit (" (e.g., int /*@alt char@*/ is a type matching either int or char)");
1911 llmsglit ("Declarator Annotations");
1913 llmsglit ("Type Definitions:");
1914 llmsglit (" /*@abstract@*/ - representation is hidden from clients");
1915 llmsglit (" /*@concrete@*/ - representation is visible to clients");
1916 llmsglit (" /*@immutable@*/ - instances of the type cannot change value");
1917 llmsglit (" /*@mutable@*/ - instances of the type can change value");
1918 llmsglit (" /*@refcounted@*/ - reference counted type");
1920 llmsglit ("Global Variables:");
1921 llmsglit (" /*@unchecked@*/ - weakest checking for global use");
1922 llmsglit (" /*@checkmod@*/ - check modification by not use of global");
1923 llmsglit (" /*@checked@*/ - check use and modification of global");
1924 llmsglit (" /*@checkedstrict@*/ - check use of global strictly");
1926 llmsglit ("Memory Management:");
1927 llmsglit (" /*@dependent@*/ - a reference to externally-owned storage");
1928 llmsglit (" /*@keep@*/ - a parameter that is kept by the called function");
1929 llmsglit (" /*@killref@*/ - a refcounted parameter, killed by the call");
1930 llmsglit (" /*@only@*/ - an unshared reference");
1931 llmsglit (" /*@owned@*/ - owner of storage that may be shared by /*@dependent@*/ references");
1932 llmsglit (" /*@shared@*/ - shared reference that is never deallocated");
1933 llmsglit (" /*@temp@*/ - temporary parameter");
1935 llmsglit ("Aliasing:");
1936 llmsglit (" /*@unique@*/ - may not be aliased by any other visible reference");
1937 llmsglit (" /*@returned@*/ - may be aliased by the return value");
1939 llmsglit ("Exposure:");
1940 llmsglit (" /*@observer@*/ - reference that cannot be modified");
1941 llmsglit (" /*@exposed@*/ - exposed reference to storage in another object");
1943 llmsglit ("Definition State:");
1944 llmsglit (" /*@out@*/ - storage reachable from reference need not be defined");
1945 llmsglit (" /*@in@*/ - all storage reachable from reference must be defined");
1946 llmsglit (" /*@partial@*/ - partially defined, may have undefined fields");
1947 llmsglit (" /*@reldef@*/ - relax definition checking");
1949 llmsglit ("Global State: (for globals lists, no /*@, since list is already in /*@\'s)");
1950 llmsglit (" undef - variable is undefined before the call");
1951 llmsglit (" killed - variable is undefined after the call");
1953 llmsglit ("Null State:");
1954 llmsglit (" /*@null@*/ - possibly null pointer");
1955 llmsglit (" /*@notnull@*/ - definitely non-null pointer");
1956 llmsglit (" /*@relnull@*/ - relax null checking");
1958 llmsglit ("Null Predicates:");
1959 llmsglit (" /*@nullwhentrue@*/ - if result is TRUE, first parameter is NULL");
1960 llmsglit (" /*@falsewhennull@*/ - if result is TRUE, first parameter is not NULL");
1962 llmsglit ("Execution:");
1963 llmsglit (" /*@noreturn@*/ - function never returns");
1964 llmsglit (" /*@maynotreturn@*/ - function may or may not return");
1965 llmsglit (" /*@noreturnwhentrue@*/ - function does not return if first parameter is TRUE");
1966 llmsglit (" /*@noreturnwhenfalse@*/ - function does not return if first parameter if FALSE");
1967 llmsglit (" /*@alwaysreturns@*/ - function always returns");
1969 llmsglit ("Side-Effects:");
1970 llmsglit (" /*@sef@*/ - corresponding actual parameter has no side effects");
1972 llmsglit ("Declaration:");
1973 llmsglit (" /*@unused@*/ - need not be used (no unused errors reported)");
1974 llmsglit (" /*@external@*/ - defined externally (no undefined error reported)");
1977 llmsglit (" /*@fallthrough@*/ - fall-through case");
1979 llmsglit ("Break:");
1980 llmsglit (" /*@innerbreak@*/ - break is breaking an inner loop or switch");
1981 llmsglit (" /*@loopbreak@*/ - break is breaking a loop");
1982 llmsglit (" /*@switchbreak@*/ - break is breaking a switch");
1983 llmsglit (" /*@innercontinue@*/ - continue is continuing an inner loop");
1985 llmsglit ("Unreachable Code:");
1986 llmsglit (" /*@notreached@*/ - statement may be unreachable.");
1988 llmsglit ("Special Functions:");
1989 llmsglit (" /*@printflike@*/ - check variable arguments like printf");
1990 llmsglit (" /*@scanflike@*/ - check variable arguments like scanf");
1994 printComments (void)
1996 llmsglit ("Control Comments");
1997 llmsglit ("----------------");
1999 llmsglit ("Setting Flags");
2001 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.");
2003 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,");
2004 llmsglit (" /*@+boolint -modifies =showfunc@*/");
2005 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).");
2007 llmsglit ("Error Suppression");
2009 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.");
2011 llmsglit ("/*@ignore@*/ ... /*@end@*/");
2013 (cstring_makeLiteral
2014 ("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."));
2015 llmsglit ("/*@i@*/");
2017 (cstring_makeLiteral
2018 ("No errors will be reported from an /*@i@*/ comment to the end of the line."));
2019 llmsglit ("/*@i<n>@*/");
2021 (cstring_makeLiteral
2022 ("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."));
2023 llmsglit ("/*@t@*/, /*@t<n>@*/");
2025 (cstring_makeLiteral
2026 ("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."));
2028 llmsglit ("Type Access");
2030 llmsglit ("/*@access <type>@*/");
2031 llmsglit (" Allows the following code to access the representation of <type>");
2032 llmsglit ("/*@noaccess <type>@*/");
2033 llmsglit (" Hides the representation of <type>");
2035 llmsglit ("Macro Expansion");
2037 llmsglit ("/*@notfunction@*/");
2039 (cstring_makeLiteral
2040 ("Indicates that the next macro definition is not intended to be a "
2041 "function, and should be expanded in line instead of checked as a "
2042 "macro function definition."));
2049 llmsglit ("Flag Categories");
2050 llmsglit ("---------------");
2051 listAllCategories ();
2052 llmsglit ("\nTo see the flags in a flag category, do\n splint -help flags <category>");
2053 llmsglit ("To see a list of all flags in alphabetical order, do\n splint -help flags alpha");
2054 llmsglit ("To see a full description of all flags, do\n splint -help flags full");
2058 printMaintainer (void)
2060 llmsg (message ("Maintainer: %s", cstring_makeLiteralTemp (SPLINT_MAINTAINER)));
2061 llmsglit (LCL_COMPILE);
2067 llmsglit ("Mailing Lists");
2068 llmsglit ("-------------");
2070 llmsglit ("There are two mailing lists associated with Splint: ");
2072 llmsglit (" lclint-announce@virginia.edu");
2074 llmsglit (" Reserved for announcements of new releases and bug fixes.");
2075 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
2076 llmsglit (" subscribe lclint-announce");
2078 llmsglit (" lclint-interest@virginia.edu");
2080 llmsglit (" Informal discussions on the use and development of Splint.");
2081 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
2082 llmsglit (" subscribe lclint-interest");
2086 printReferences (void)
2088 llmsglit ("References");
2089 llmsglit ("----------");
2091 llmsglit ("For more information, see the Splint web site: http://www.splint.org");
2095 describePrefixCodes (void)
2097 llmsglit ("Prefix Codes");
2098 llmsglit ("------------");
2100 llmsglit ("These characters have special meaning in name prefixes:");
2102 llmsg (message (" %h Any uppercase letter [A-Z]", PFX_UPPERCASE));
2103 llmsg (message (" %h Any lowercase letter [a-z]", PFX_LOWERCASE));
2104 llmsg (message (" %h Any character (valid in a C identifier)", PFX_ANY));
2105 llmsg (message (" %h Any digit [0-9]", PFX_DIGIT));
2106 llmsg (message (" %h Any non-uppercase letter [a-z0-9_]", PFX_NOTUPPER));
2107 llmsg (message (" %h Any non-lowercase letter [A-Z0-9_]", PFX_NOTLOWER));
2108 llmsg (message (" %h Any letter [A-Za-z]", PFX_ANYLETTER));
2109 llmsg (message (" %h Any letter or digit [A-Za-z0-9]", PFX_ANYLETTERDIGIT));
2110 llmsglit (" * Zero or more repetitions of the previous character class until the end of the name");
2119 eval = context_getLarchPath ();
2120 def = osd_getEnvironmentVariable (LARCH_PATH);
2122 if (cstring_isDefined (def) ||
2123 !cstring_equal (eval, cstring_fromChars (DEFAULT_LARCHPATH)))
2125 llmsg (message ("LARCH_PATH = %s", eval));
2129 llmsg (message ("LARCH_PATH = <not set> (default = %s)",
2130 cstring_fromChars (DEFAULT_LARCHPATH)));
2133 llmsglit (" --- path used to find larch initialization files and LSL traits");
2135 eval = context_getLCLImportDir ();
2136 def = osd_getEnvironmentVariable (cstring_makeLiteralTemp (LCLIMPORTDIR));
2138 if (cstring_isDefined (def) ||
2139 !cstring_equal (eval, cstring_fromChars (DEFAULT_LCLIMPORTDIR)))
2141 llmsg (message ("%q = %s", cstring_makeLiteral (LCLIMPORTDIR), eval));
2145 llmsg (message ("%s = <not set, default: %s>", cstring_makeLiteralTemp (LCLIMPORTDIR),
2146 cstring_makeLiteralTemp (DEFAULT_LCLIMPORTDIR)));
2149 llmsglit (" --- directory containing lcl standard library files "
2150 "(import with < ... >)");;
2153 ("include path = %q (set by environment variable %s and -I flags)",
2154 cppReader_getIncludePath (), INCLUDEPATH_VAR));
2156 llmsglit (" --- path used to find #include'd files");
2159 ("systemdirs = %s (set by -systemdirs or environment variable %s)", /*@i413223@*/
2160 context_getString (FLG_SYSTEMDIRS),
2163 llmsglit (" --- if file is found on this path, it is treated as a system file for error reporting");
2172 fprintf (stderr, "*** Interrupt\n");
2173 llexit (LLINTERRUPT);
2178 /* Cheat when there are parse errors */
2181 fprintf (stderr, "*** Segmentation Violation\n");
2183 /* Don't catch it if fileloc_unparse causes a signal */
2184 (void) signal (SIGSEGV, NULL);
2186 loc = fileloc_unparse (g_currentloc);
2188 fprintf (stderr, "*** Location (not trusted): %s\n",
2189 cstring_toCharsSafe (loc));
2192 fprintf (stderr, "*** Please report bug to %s\n", SPLINT_MAINTAINER);
2196 fprintf (stderr, "*** Signal: %d\n", i);
2198 fprintf (stderr, "*** Location (not trusted): %s\n",
2199 cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
2202 fprintf (stderr, "*** Please report bug to %s ***\n", SPLINT_MAINTAINER);
2210 static bool doneCleanup = FALSE;
2212 /* make sure this is only called once! */
2214 if (doneCleanup) return;
2219 ** Close all open files
2220 ** (There should only be open files, if we exited after a fatal error.)
2223 fileTable_closeAll (context_fileTable ());
2225 if (context_getFlag (FLG_KEEP))
2227 check (fputs ("Temporary files kept:\n", stderr) != EOF);
2228 fileTable_printTemps (context_fileTable ());
2233 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
2237 llbug (message ("Files unclosed: %d", nfiles));
2240 fileTable_cleanup (context_fileTable ());
2247 ** cleans up temp files (if necessary) and exits
2253 DPRINTF (("llexit: %d", status));
2256 if (status == LLFAILURE)
2264 if (status != LLFAILURE)
2266 context_destroyMod ();
2267 exprNode_destroyMod ();
2270 uentry_destroyMod ();
2271 typeIdSet_destroyMod ();
2274 dmalloc_shutdown ();
2278 exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
2281 bool readOptionsFile (cstring fname, cstringSList *passThroughArgs, bool report)
2285 if (fileTable_exists (context_fileTable (), fname))
2291 message ("Multiple attempts to read options file: %s", fname),
2297 FILE *innerf = fileTable_openFile (context_fileTable (), fname, "r");
2301 fileloc fc = g_currentloc;
2302 g_currentloc = fileloc_createRc (fname);
2304 if (context_getFlag (FLG_SHOWSCAN))
2306 lldiagmsg (message ("< reading options from %q >",
2307 fileloc_outputFilename (g_currentloc)));
2310 loadrc (innerf, passThroughArgs);
2311 fileloc_reallyFree (g_currentloc);
2321 message ("Cannot open options file: %s", fname),
2331 ** This shouldn't be necessary, but Apple Darwin can't handle '"''s.
2335 loadrc (/*:open:*/ FILE *rcfile, cstringSList *passThroughArgs)
2336 /*@modifies rcfile@*/
2337 /*@ensures closed rcfile@*/
2339 char *s = mstring_create (MAX_LINE_LENGTH);
2342 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2346 while (reader_readLine (rcfile, s, MAX_LINE_LENGTH) != NULL)
2353 DPRINTF (("Line: %s", s));
2354 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2356 while (*s == ' ' || *s == '\t')
2364 bool escaped = FALSE;
2365 bool quoted = FALSE;
2368 DPRINTF (("Process: %s", s));
2369 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2370 /* comment characters */
2371 if (c == '#' || c == ';' || c == '\n')
2377 if (c == '-' || c == '+')
2384 voptgenerror (FLG_BADFLAG,
2385 message ("Bad flag syntax (+ or - expected, "
2386 "+ is assumed): %s",
2387 cstring_fromChars (s)),
2398 while ((c = *s) != '\0')
2399 { /* remember to handle spaces and quotes in -D and -U ... */
2425 if (c == ' ' || c == '\t' || c == '\n')
2427 /*@innerbreak@*/ break;
2435 DPRINTF (("Nulling: %c", *s));
2438 if (mstring_isEmpty (thisflag))
2440 llfatalerror (message ("Missing flag: %s",
2441 cstring_fromChars (os)));
2444 DPRINTF (("Flag: %s", thisflag));
2446 opt = flags_identifyFlag (cstring_fromChars (thisflag));
2448 if (flagcode_isSkip (opt))
2452 else if (flagcode_isInvalid (opt))
2454 DPRINTF (("Invalid: %s", thisflag));
2456 if (isMode (cstring_fromChars (thisflag)))
2458 context_setMode (cstring_fromChars (thisflag));
2462 voptgenerror (FLG_BADFLAG,
2463 message ("Unrecognized option: %s",
2464 cstring_fromChars (thisflag)),
2470 context_userSetFlag (opt, set);
2472 if (flagcode_hasArgument (opt))
2474 if (opt == FLG_HELP)
2477 voptgenerror (FLG_BADFLAG,
2478 message ("Cannot use help in rc files"),
2481 else if (flagcode_isPassThrough (opt)) /* -D or -U */
2483 cstring arg = cstring_fromCharsNew (thisflag);
2484 cstring_markOwned (arg);
2485 *passThroughArgs = cstringSList_add (*passThroughArgs, arg);
2486 DPRINTF (("Pass through: %s",
2487 cstringSList_unparse (*passThroughArgs)));
2489 else if (opt == FLG_INCLUDEPATH
2490 || opt == FLG_SPECPATH)
2492 cstring dir = cstring_suffix (cstring_fromChars (thisflag), 1); /* skip over I/S */
2496 case FLG_INCLUDEPATH:
2497 cppAddIncludeDir (dir);
2498 /*@switchbreak@*/ break;
2501 g_localSpecPath = cstring_toCharsSafe
2502 (message ("%s:%s", cstring_fromChars (g_localSpecPath), dir));
2504 /*@switchbreak@*/ break;
2508 else if (flagcode_hasString (opt)
2509 || flagcode_hasNumber (opt)
2510 || flagcode_hasChar (opt)
2511 || opt == FLG_INIT || opt == FLG_OPTF)
2513 cstring extra = cstring_undefined;
2518 rest = mstring_copy (s);
2519 DPRINTF (("Here: rest = %s", rest));
2523 while ((rchar = *rest) != '\0'
2524 && (isspace ((int) rchar)))
2530 DPRINTF (("Yo: %s", rest));
2532 while ((rchar = *rest) != '\0'
2533 && !isspace ((int) rchar))
2535 extra = cstring_appendChar (extra, rchar);
2540 DPRINTF (("Yo: %s", extra));
2543 if (cstring_isUndefined (extra))
2549 ("Flag %s must be followed by an argument",
2550 flagcode_unparse (opt)),
2557 DPRINTF (("Here we are: %s", extra));
2559 if (flagcode_hasNumber (opt) || flagcode_hasChar (opt))
2561 DPRINTF (("Set value flag: %s", extra));
2562 setValueFlag (opt, extra);
2564 else if (opt == FLG_OPTF)
2566 (void) readOptionsFile (extra, passThroughArgs, TRUE);
2568 else if (opt == FLG_INIT)
2571 llassert (inputStream_isUndefined (initFile));
2573 initFile = inputStream_create
2574 (cstring_copy (extra),
2575 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
2579 else if (flagcode_hasString (opt))
2581 DPRINTF (("Here: %s", extra));
2584 ** If it has "'s, we need to remove them.
2587 if (cstring_firstChar (extra) == '\"')
2589 if (cstring_lastChar (extra) == '\"')
2591 cstring unquoted = cstring_copyLength
2592 (cstring_toCharsSafe (cstring_suffix (extra, 1)),
2593 cstring_length (extra) - 2);
2595 DPRINTF (("string flag: %s -> %s", extra, unquoted));
2596 setStringFlag (opt, unquoted);
2597 cstring_free (extra);
2603 message ("Unmatched \" in option string: %s",
2606 setStringFlag (opt, extra);
2611 DPRINTF (("No quotes: %s", extra));
2612 setStringFlag (opt, extra);
2615 extra = cstring_undefined;
2623 cstring_free (extra);
2633 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2634 while ((c == ' ') || (c == '\t'))
2640 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2644 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2646 check (fileTable_closeFile (context_fileTable (), rcfile));
2649 static fileIdList preprocessFiles (fileIdList fl, bool xhfiles)
2650 /*@modifies fileSystem@*/
2652 bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
2653 int skip = (fileIdList_size (fl) / 5);
2654 int filesprocessed = 0;
2655 fileIdList dfiles = fileIdList_create ();
2657 fileloc_free (g_currentloc);
2658 g_currentloc = fileloc_createBuiltin ();
2660 fileIdList_elements (fl, fid)
2662 cstring ppfname = fileTable_fileName (fid);
2664 if (!(osd_fileIsReadable (ppfname)))
2666 lldiagmsg (message ("Cannot open file: %q", osd_outputPath (ppfname)));
2667 ppfname = cstring_undefined;
2670 if (cstring_isDefined (ppfname))
2672 fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
2676 llassert (fileTable_isXHFile (context_fileTable (), dfile));
2679 llassert (cstring_isNonEmpty (ppfname));
2683 if ((filesprocessed % skip) == 0)
2685 if (filesprocessed == 0) {
2686 fprintf (stderr, " ");
2689 fprintf (stderr, ".");
2692 (void) fflush (stderr);
2697 DPRINTF (("outfile: %s", fileTable_fileName (dfile)));
2699 if (cppProcess (ppfname, fileTable_fileName (dfile)) != 0)
2701 llfatalerror (message ("Preprocessing error for file: %s",
2702 fileTable_rootFileName (fid)));
2705 fileIdList_add (dfiles, dfile);
2707 } end_fileIdList_elements;
2712 /* This should be in an lclUtils.c file... */
2714 char *specFullName (char *specfile, /*@out@*/ char **inpath)
2716 /* extract the path and the specname associated with the given file */
2717 char *specname = (char *) dmalloc (sizeof (*specname)
2718 * (strlen (specfile) + 9));
2719 char *ospecname = specname;
2720 char *path = (char *) dmalloc (sizeof (*path) * (strlen (specfile)));
2724 /* initialized path to empty string or may have accidental garbage */
2727 /*@-mayaliasunique@*/
2728 strcpy (specname, specfile);
2729 /*@=mayaliasunique@*/
2731 /* trim off pathnames in specfile */
2732 size = strlen (specname);
2734 for (i = size_toInt (size) - 1; i >= 0; i--)
2736 if (specname[i] == CONNECTCHAR)
2738 /* strcpy (specname, (char *)specname+i+1); */
2739 for (j = 0; j <= i; j++) /* include '/' */
2741 path[j] = specname[j];
2751 ** also remove .lcl file extension, assume it's the last extension
2755 size = strlen (specname);
2757 for (i = size_toInt (size) - 1; i >= 0; i--)
2759 if (specname[i] == '.')
2769 ** If specname no longer points to the original char,
2770 ** we need to allocate a new pointer and copy the string.
2773 if (specname != ospecname) {
2774 char *rspecname = (char *) dmalloc (sizeof (*rspecname) * (strlen (specname) + 1));
2775 strcpy (rspecname, specname); /* evs 2000-05-16: Bug: was ospecname! */