2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2003 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"
57 # include "scanline.h"
58 # include "lclscanline.h"
59 # include "lclsyntable.h"
60 # include "lcltokentable.h"
61 # include "lslparse.h"
63 # include "syntable.h"
64 # include "tokentable.h"
70 # include "Headers/version.h" /* Visual C++ finds the wrong version.h */
72 # include "cgrammar.h"
76 extern /*@external@*/ int yydebug;
77 static void cleanupFiles (void);
79 ** evans 2002-07-03: renamed from interrupt to avoid conflict with WATCOM compiler keyword
80 ** (Suggested by Adam Clarke)
83 static void llinterrupt (int p_i);
85 static void describeVars (void);
86 static bool specialFlagsHelp (char *p_next);
87 static bool hasShownHerald = FALSE;
88 static char *specFullName (char *p_specfile, /*@out@*/ char **p_inpath)
89 /*@modifies *p_inpath@*/ ;
91 static bool anylcl = FALSE;
92 static clock_t inittime;
94 static fileIdList preprocessFiles (fileIdList, bool)
95 /*@modifies fileSystem@*/ ;
97 static void warnSysFiles(fileIdList p_files) /*@modifies fileSystem@*/;
100 void lslCleanup (void)
101 /*@globals killed g_symtab@*/
102 /*@modifies internalState, g_symtab@*/
105 ** Cleanup all the LCL/LSL.
108 static bool didCleanup = FALSE;
110 llassert (!didCleanup);
115 lsymbol_destroyMod ();
116 LCLSynTableCleanup ();
117 LCLTokenTableCleanup ();
118 LCLScanLineCleanup ();
121 /* clean up LSL parsing */
124 ltokenTableCleanup ();
128 symtable_free (g_symtab);
133 lslProcess (fileIdList lclfiles)
134 /*@globals undef g_currentSpec, undef g_currentSpecName, g_currentloc,
135 undef killed g_symtab; @*/
136 /*@modifies g_currentSpec, g_currentSpecName, g_currentloc, internalState, fileSystem; @*/
139 bool parser_status = FALSE;
140 bool overallStatus = FALSE;
145 context_resetSpecLines ();
147 fileIdList_elements (lclfiles, fid)
149 cstring actualName = cstring_undefined;
150 cstring fname = fileTable_fileName (fid);
152 if (osd_getPath (cstring_fromChars (g_localSpecPath),
153 fname, &actualName) == OSD_FILENOTFOUND)
155 if (mstring_equal (g_localSpecPath, "."))
157 lldiagmsg (message ("Spec file not found: %q", osd_outputPath (fname)));
161 lldiagmsg (message ("Spec file not found: %q (on %s)",
162 osd_outputPath (fname),
163 cstring_fromChars (g_localSpecPath)));
168 inputStream specFile;
170 char *namePtr = actualName;
172 while (*namePtr == '.' && *(namePtr + 1) == CONNECTCHAR)
176 /*@noaccess cstring@*/
178 g_currentSpec = cstring_fromCharsNew (namePtr);
180 specFile = inputStream_create (cstring_copy (g_currentSpec),
181 LCL_EXTENSION, TRUE);
183 llassert (inputStream_isDefined (specFile));
185 g_currentSpecName = specFullName
186 (cstring_toCharsSafe (g_currentSpec),
191 displayScan (message ("reading spec %s", g_currentSpec));
193 /* Open the source file */
195 if (!inputStream_open (specFile))
197 lldiagmsg (message ("Cannot open file: %q",
198 osd_outputPath (inputStream_fileName (specFile))));
199 inputStream_free (specFile);
203 scopeInfo dummy_scope = (scopeInfo) dmalloc (sizeof (*dummy_scope));
204 dummy_scope->kind = SPE_INVALID;
207 LCLScanReset (specFile);
210 ** Minor hacks to allow more than one LCL file to
211 ** be scanned, while keeping initializations
214 symtable_enterScope (g_symtab, dummy_scope);
215 resetImports (cstring_fromChars (g_currentSpecName));
216 context_enterLCLfile ();
217 (void) lclHadNewError ();
219 parser_status = (ylparse () != 0);
220 context_exitLCLfile ();
222 overallStatus = parser_status || lclHadNewError ();
224 if (context_getFlag (FLG_DOLCS))
228 outputLCSFile (path, "%FAILED Output from ",
233 outputLCSFile (path, "%PASSED Output from ",
238 (void) inputStream_close (specFile);
239 inputStream_free (specFile);
241 symtable_exitScope (g_symtab);
244 cstring_free (actualName);
245 } end_fileIdList_elements;
247 /* Can cleanup lsl stuff right away */
251 g_currentSpec = cstring_undefined;
252 g_currentSpecName = NULL;
255 static void handlePassThroughFlag (char *arg)
258 char *quotechar = strchr (curarg, '\"');
261 char *freearg = NULL;
263 while (quotechar != NULL)
265 if (*(quotechar - 1) == '\\')
267 char *tp = quotechar - 2;
278 curarg = quotechar + 1;
279 quotechar = strchr (curarg, '\"');
284 llassert (quotechar != NULL);
286 offset = (quotechar - arg) + 2;
290 arg = cstring_toCharsSafe
291 (message ("%s\"\'%s",
292 cstring_fromChars (arg),
293 cstring_fromChars (quotechar + 1)));
299 arg = cstring_toCharsSafe
300 (message ("%s\'\"%s",
301 cstring_fromChars (arg),
302 cstring_fromChars (quotechar + 1)));
307 curarg = arg + offset;
308 quotechar = strchr (curarg, '\"');
314 voptgenerror (FLG_BADFLAG,
315 message ("Unclosed quote in flag: %s",
316 cstring_fromChars (arg)),
325 ** If the value is surrounded by single quotes ('), remove
326 ** them. This is an artifact of UNIX command line?
329 def = osd_fixDefine (cstring_fromChars (arg + 1));
330 DPRINTF (("Do define: %s", def));
332 DPRINTF (("After define"));
334 } else if (arg[0] == 'U') {
335 cppDoUndefine (cstring_fromChars (arg + 1));
344 void showHerald (void)
346 if (hasShownHerald || context_getFlag (FLG_QUIET))
352 fprintf (g_messagestream, "%s\n\n", SPLINT_VERSION);
353 hasShownHerald = TRUE;
359 ** Disable MSVC++ warning about return value. Methinks humbly splint control
360 ** comments are a mite more legible.
364 # pragma warning (disable:4035)
367 int main (int argc, char *argv[])
368 /*@globals killed undef g_currentloc,
369 killed g_localSpecPath,
370 killed undef g_currentSpec,
371 killed undef g_currentSpecName,
373 undef g_warningstream, g_messagestream, g_errorstream;
375 /*@modifies g_currentloc, g_localSpecPath, g_currentSpec, g_currentSpecName,
379 bool first_time = TRUE;
381 inputStream sourceFile = inputStream_undefined;
383 fileIdList dercfiles;
384 cstringList passThroughArgs = cstringList_undefined;
385 fileIdList cfiles, xfiles, lclfiles, mtfiles;
386 clock_t before, lcltime, libtime, pptime, cptime, rstime;
390 _wildcard (&argc, &argv);
393 g_warningstream = stdout;
394 g_messagestream = stderr;
395 g_errorstream = stderr;
397 (void) signal (SIGINT, llinterrupt);
398 (void) signal (SIGSEGV, llinterrupt);
402 clabstract_initMod ();
403 typeIdSet_initMod ();
405 cppReader_initMod ();
409 g_currentloc = fileloc_createBuiltin ();
414 context_setInCommandLine ();
418 help_showAvailableHelp ();
422 /* -help must be the first flag to get help */
423 if (flagcode_isHelpFlag (flags_identifyFlag (cstring_fromChars (argv[1]))))
426 ** Skip first flag and help flag
429 help_processFlags (argc - 2, argv + 2);
437 ** Add include directories from environment.
441 cstring incval = cstring_copy (osd_getEnvironmentVariable (INCLUDEPATH_VAR));
442 cstring oincval = incval;
444 if (cstring_isDefined (incval))
447 ** Each directory on the include path is a system include directory.
450 DPRINTF (("include: %s", incval));
451 context_setString (FLG_SYSTEMDIRS, cstring_copy (incval));
453 while (cstring_isDefined (incval))
456 char *nextsep = strchr (incval, PATH_SEPARATOR);
462 dir = cstring_copy (incval);
464 if (cstring_length (dir) == 0
465 || !isalpha ((int) cstring_firstChar (dir)))
468 ** win32 environment values can have special values,
474 cppAddIncludeDir (dir);
477 *nextsep = PATH_SEPARATOR;
478 incval = cstring_fromChars (nextsep + 1);
486 /*@noaccess cstring@*/
489 else /* 2001-09-09: herbert */
491 /* Put C_INCLUDE_PATH directories in sysdirs */
492 cstring cincval = osd_getEnvironmentVariable (cstring_makeLiteralTemp ("C_INCLUDE_PATH"));
494 if (cstring_isDefined (cincval))
496 context_setString (FLG_SYSTEMDIRS, cstring_copy (cincval));
501 cstring_free (oincval);
505 ** check RCFILE for default flags
509 ** Process command line message formatting flags before reading rc file
513 cstring home = osd_getHomeDir ();
514 cstring fname = cstring_undefined;
515 bool defaultf = TRUE;
518 for (i = 1; i < argc; i++)
523 if (*thisarg == '-' || *thisarg == '+')
525 bool set = (*thisarg == '+');
531 ** Don't report warnings this time
534 opt = flags_identifyFlagQuiet (cstring_fromChars (thisarg));
540 else if (flagcode_isMessageControlFlag (opt))
543 ** Need to set it immediately, so rc file scan is displayed
546 context_userSetFlag (opt, set);
548 if (flagcode_hasArgument (opt))
550 llassert (flagcode_hasString (opt));
554 fname = cstring_fromChars (argv[i]);
555 flags_setStringFlag (opt, fname);
562 ("Flag %s must be followed by a string",
563 flagcode_unparse (opt)),
568 else if (opt == FLG_OPTF)
573 fname = cstring_fromChars (argv[i]);
574 (void) rcfiles_read (fname, &passThroughArgs, TRUE);
578 (cstring_makeLiteral ("Flag f to select options file "
579 "requires an argument"));
583 ; /* wait to process later */
590 if (!nof && defaultf)
593 ** No explicit rc file, first try reading ~/.splintrc
596 if (cstring_isUndefined (fname))
598 if (!cstring_isEmpty (home))
600 bool readhomerc, readaltrc;
601 cstring homename, altname;
603 homename = message ("%s%h%s", home, CONNECTCHAR,
604 cstring_fromChars (RCFILE));
605 readhomerc = rcfiles_read (homename, &passThroughArgs, FALSE);
608 ** Try ~/.splintrc also for historical accuracy
611 altname = message ("%s%h%s", home, CONNECTCHAR,
612 cstring_fromChars (ALTRCFILE));
613 readaltrc = rcfiles_read (altname, &passThroughArgs, FALSE);
615 if (readhomerc && readaltrc)
620 message ("Found both %s and %s files. Using both files, "
621 "but recommend using only %s to avoid confusion.",
622 homename, altname, homename),
626 cstring_free (homename);
627 cstring_free (altname);
632 ** Next, read .splintrc in the current working directory
636 cstring rcname = message ("%s%s",osd_getCurrentDirectory (), cstring_fromChars (RCFILE));
637 cstring altname = message ("%s%s",osd_getCurrentDirectory (), cstring_fromChars (ALTRCFILE));
638 bool readrc, readaltrc;
640 readrc = rcfiles_read (rcname, &passThroughArgs, FALSE);
641 readaltrc = rcfiles_read (altname, &passThroughArgs, FALSE);
643 if (readrc && readaltrc)
645 voptgenerror (FLG_WARNRC,
646 message ("Found both %s and %s files. Using both files, "
647 "but recommend using only %s to avoid confusion.",
648 rcname, altname, rcname),
653 cstring_free (rcname);
654 cstring_free (altname);
660 llassert (fileloc_isBuiltin (g_currentloc));
662 cfiles = fileIdList_create ();
663 xfiles = fileIdList_create ();
664 lclfiles = fileIdList_create ();
665 mtfiles = fileIdList_create ();
667 /* argv[0] is the program name, don't pass it to flags_processFlags */
668 flags_processFlags (TRUE, xfiles, cfiles,
675 if (context_getFlag (FLG_CSV)) {
676 cstring fname = context_getString (FLG_CSV);
678 if (cstring_isDefined (fname)) {
679 if (osd_fileExists (fname) && !context_getFlag (FLG_CSVOVERWRITE)) {
680 lldiagmsg (message ("Specified CSV output file already exists (use +csvoverwrite to automatically overwrite): %s",
683 g_csvstream = fopen (cstring_toCharsSafe (fname), "w");
685 DPRINTF (("Creating: %s", fname));
686 if (g_csvstream == NULL) {
687 lldiagmsg (message ("Cannot open file for CSV output: %s", fname));
689 displayScan (message ("Starting CSV output file: %s", context_getString (FLG_CSV)));
690 fprintf (g_csvstream,
691 "Warning, Flag Code, Flag Name, Priority, File, Line, Column, Warning Text, Additional Text\n");
703 context_resetErrors ();
704 context_clearInCommandLine ();
706 anylcl = !fileIdList_isEmpty (lclfiles);
708 if (context_doMerge ())
710 cstring m = context_getMerge ();
712 displayScanOpen (message ("< loading %s ", m));
716 if (!usymtab_existsType (context_getBoolName ()))
723 if (!context_getFlag (FLG_NOLIB) && loadStandardState ())
732 /* setup bool type and constants */
736 fileloc_free (g_currentloc);
737 g_currentloc = fileloc_createBuiltin ();
740 ** Read metastate files (must happen before loading libraries)
743 fileIdList_elements (mtfiles, mtfile)
745 context_setFileId (mtfile);
746 displayScan (message ("processing %s", fileTable_rootFileName (mtfile)));
747 mtreader_readFile (cstring_copy (fileTable_fileName (mtfile)));
748 } end_fileIdList_elements;
754 lslProcess (lclfiles);
757 usymtab_initGlobalMarker ();
762 ** call the pre-preprocessor and /lib/cpp to generate appropriate
767 context_setInCommandLine ();
769 DPRINTF (("Pass through: %s", cstringSList_unparse (passThroughArgs)));
771 cstringList_elements (passThroughArgs, thisarg)
773 handlePassThroughFlag (cstring_toCharsSafe (thisarg));
775 end_cstringList_elements;
777 cstringList_free (passThroughArgs);
781 DPRINTF (("Initializing cpp reader!"));
782 cppReader_initialize ();
783 cppReader_saveDefinitions ();
785 context_clearInCommandLine ();
787 if (!context_getFlag (FLG_NOPP))
793 displayScanOpen (cstring_makeLiteral ("preprocessing"));
797 context_setPreprocessing ();
798 dercfiles = preprocessFiles (xfiles, TRUE);
799 tfiles = preprocessFiles (cfiles, FALSE);
800 warnSysFiles(cfiles);
801 dercfiles = fileIdList_append (dercfiles, tfiles);
802 fileIdList_free (tfiles);
804 context_clearPreprocessing ();
806 fileIdList_free (cfiles);
814 dercfiles = fileIdList_append (cfiles, xfiles);
819 ** now, check all the corresponding C files
821 ** (for now these are just <file>.c, but after pre-processing
822 ** will be <tmpprefix>.<file>.c)
827 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
831 llbug (message ("Files unclosed: %d", nfiles));
836 DPRINTF (("Initializing..."));
840 DPRINTF (("Okay..."));
842 fileIdList_elements (dercfiles, fid)
844 sourceFile = inputStream_create (cstring_copy (fileTable_fileName (fid)), C_EXTENSION, TRUE);
845 context_setFileId (fid);
847 /* Open source file */
849 if (inputStream_isUndefined (sourceFile) || (!inputStream_open (sourceFile)))
851 /* previously, this was ignored ?! */
852 llbug (message ("Could not open temp file: %s", fileTable_fileName (fid)));
856 yyin = inputStream_getFile (sourceFile); /*< shared <- only */
858 llassert (yyin != NULL);
860 displayScan (message ("checking %q", osd_outputPath (fileTable_rootFileName (fid))));
863 ** Every time, except the first time, through the loop,
864 ** need to call yyrestart to clean up the parse buffer.
869 (void) yyrestart (yyin);
876 DPRINTF (("Entering..."));
877 context_enterFile ();
879 context_exitCFile ();
881 (void) inputStream_close (sourceFile);
884 inputStream_free (sourceFile); /* evans 2002-07-12: why no warning without this?!! */
885 } end_fileIdList_elements;
887 fileIdList_free (dercfiles); /* evans 2002-07-12: why no warning without this?!! */
890 /* process any leftover macros */
892 context_processAllMacros ();
894 /* check everything that was specified was defined */
896 /* don't check if no c files were processed ?
897 ** is this correct behaviour?
900 displayScan (cstring_makeLiteral ("global checks"));
904 if (context_getLinesProcessed () > 0)
906 usymtab_allDefined ();
909 if (context_maybeSet (FLG_TOPUNUSED))
911 uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main"));
913 if (uentry_isValid (ue))
915 uentry_setUsed (ue, fileloc_observeBuiltin ());
921 if (context_maybeSet (FLG_EXPORTLOCAL))
923 usymtab_exportLocal ();
927 if (context_maybeSet (FLG_EXPORTHEADER))
929 usymtab_exportHeader ();
932 if (context_getFlag (FLG_SHOWUSES))
934 usymtab_displayAllUses ();
937 context_checkSuppressCounts ();
939 if (context_doDump ())
941 cstring dump = context_getDump ();
952 if (g_csvstream != NULL) {
953 displayScan (message ("Closing CSV file: %s", context_getString (FLG_CSV)));
954 check (fclose (g_csvstream) == 0);
957 if (context_getFlag (FLG_SHOWSUMMARY))
963 bool isQuiet = context_getFlag (FLG_QUIET);
964 cstring specErrors = cstring_undefined;
965 int nspecErrors = lclNumberErrors ();
969 if (context_neednl ())
970 fprintf (g_warningstream, "\n");
974 if (nspecErrors == context_getLCLExpect ())
977 message ("%d spec warning%&, as expected\n ",
982 if (context_getLCLExpect () > 0)
985 message ("%d spec warning%&, expected %d\n ",
987 (int) context_getLCLExpect ());
991 specErrors = message ("%d spec warning%&\n ",
999 if (context_getLCLExpect () > 0)
1001 specErrors = message ("No spec warnings, expected %d\n ",
1002 (int) context_getLCLExpect ());
1007 if (context_anyErrors ())
1009 if (context_numErrors () == context_getExpect ())
1012 llmsg (message ("Finished checking --- "
1013 "%s%d code warning%&, as expected",
1014 specErrors, context_numErrors ()));
1019 if (context_getExpect () > 0)
1023 ("Finished checking --- "
1024 "%s%d code warning%&, expected %d",
1025 specErrors, context_numErrors (),
1026 (int) context_getExpect ()));
1036 llmsg (message ("Finished checking --- "
1037 "%s%d code warning%&",
1038 specErrors, context_numErrors ()));
1047 if (context_getExpect () > 0)
1051 ("Finished checking --- "
1052 "%sno code warnings, expected %d",
1054 (int) context_getExpect ()));
1061 if (context_getLinesProcessed () > 0)
1063 if (cstring_isEmpty (specErrors))
1067 llmsg (message ("Finished checking --- no warnings"));
1074 llmsg (message ("Finished checking --- %sno code warnings",
1082 llmsg (message ("Finished checking --- %sno code processed",
1089 cstring_free (specErrors);
1092 if (context_getFlag (FLG_STATS))
1094 clock_t ttime = clock () - before;
1095 int specLines = context_getSpecLinesProcessed ();
1096 cstring specmsg = cstring_undefined;
1102 specmsg = message ("%d spec, ", specLines);
1105 /* The clock might wrap around, not platform-independent easy way to deal with this... */
1108 # ifndef CLOCKS_PER_SEC
1109 lldiagmsg (message ("%s%d source lines in %d time steps (steps/sec unknown)\n",
1111 context_getLinesProcessed (),
1114 lldiagmsg (message ("%s%d source lines in %f s.\n",
1116 context_getLinesProcessed (),
1117 (double) ttime / CLOCKS_PER_SEC));
1118 DPRINTF (("Time: %ld [%ld - %ld]", ttime, rstime, before));
1123 lldiagmsg (message ("%s%d source lines\n",
1125 context_getLinesProcessed ()));
1134 if (context_getFlag (FLG_TIMEDIST))
1136 clock_t ttime = clock () - before;
1140 char *msg = (char *) dmalloc (256 * sizeof (*msg));
1144 /* Gack: really should figure out how to make configure find snprintf... */
1146 (void) _snprintf (msg, 256,
1148 (void) snprintf (msg, 256,
1150 "Time distribution (percent): initialize %.2f / lcl %.2f / "
1151 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1152 (100.0 * (double) (libtime - before) / ttime),
1153 (100.0 * (double) (lcltime - libtime) / ttime),
1154 (100.0 * (double) (pptime - lcltime) / ttime),
1155 (100.0 * (double) (cptime - pptime) / ttime),
1156 (100.0 * (double) (rstime - cptime) / ttime));
1161 (void) _snprintf (msg, 256,
1163 (void) snprintf (msg, 256,
1165 "Time distribution (percent): initialize %.2f / "
1166 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1167 (100.0 * (double) (libtime - before) / ttime),
1168 (100.0 * (double) (pptime - libtime) / ttime),
1169 (100.0 * (double) (cptime - pptime) / ttime),
1170 (100.0 * (double) (rstime - cptime) / ttime));
1173 llgenindentmsgnoloc (cstring_fromCharsO (msg));
1177 llexit (expsuccess ? LLSUCCESS : LLFAILURE);
1178 BADBRANCHRET (LLFAILURE);
1183 ** Reenable return value warnings.
1185 # pragma warning (default:4035)
1194 fprintf (g_errorstream, "*** Interrupt\n");
1195 llexit (LLINTERRUPT);
1200 /* Cheat when there are parse errors */
1203 fprintf (g_errorstream, "*** Segmentation Violation\n");
1205 /* Don't catch it if fileloc_unparse causes a signal */
1206 (void) signal (SIGSEGV, NULL);
1208 loc = fileloc_unparse (g_currentloc);
1210 fprintf (g_errorstream, "*** Location (not trusted): %s\n",
1211 cstring_toCharsSafe (loc));
1214 fprintf (g_errorstream, "*** Please report bug to %s\n", SPLINT_MAINTAINER);
1218 fprintf (g_errorstream, "*** Signal: %d\n", i);
1220 fprintf (g_errorstream, "*** Location (not trusted): %s\n",
1221 cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
1224 fprintf (g_errorstream, "*** Please report bug to %s ***\n", SPLINT_MAINTAINER);
1232 static bool doneCleanup = FALSE;
1234 /* make sure this is only called once! */
1236 if (doneCleanup) return;
1241 ** Close all open files
1242 ** (There should only be open files, if we exited after a fatal error.)
1245 fileTable_closeAll (context_fileTable ());
1247 if (context_getFlag (FLG_KEEP))
1249 check (fputs ("Temporary files kept:\n", g_messagestream) != EOF);
1250 fileTable_printTemps (context_fileTable ());
1255 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1259 llbug (message ("Files unclosed: %d", nfiles));
1262 fileTable_cleanup (context_fileTable ());
1269 ** cleans up temp files (if necessary) and exits
1275 DPRINTF (("llexit: %d", status));
1278 if (status == LLFAILURE)
1286 if (status != LLFAILURE)
1288 usymtab_destroyMod ();
1290 /*drl I'm commenting this line out
1291 because it is causing Splint to crash when built with
1292 2.95 I'm not sure if this is a compiler bug or if if has to do with bool
1293 Any way if we're going to exist the program why do we bother freeing stuff...
1295 /* context_destroyMod (); */
1296 exprNode_destroyMod ();
1297 cppReader_destroyMod ();
1299 uentry_destroyMod ();
1300 typeIdSet_destroyMod ();
1303 fileloc_destroyMod ();
1305 dmalloc_shutdown ();
1309 exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
1312 static fileIdList preprocessFiles (fileIdList fl, bool xhfiles)
1313 /*@modifies fileSystem@*/
1315 bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
1316 int skip = (fileIdList_size (fl) / 5);
1317 int filesprocessed = 0;
1318 fileIdList dfiles = fileIdList_create ();
1320 fileloc_free (g_currentloc);
1321 g_currentloc = fileloc_createBuiltin ();
1323 fileIdList_elements (fl, fid)
1325 cstring ppfname = fileTable_fileName (fid);
1327 if (!(osd_fileIsReadable (ppfname)))
1329 lldiagmsg (message ("Cannot open file: %q", osd_outputPath (ppfname)));
1330 ppfname = cstring_undefined;
1333 if (cstring_isDefined (ppfname))
1335 fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
1339 llassert (fileTable_isXHFile (context_fileTable (), dfile));
1342 llassert (cstring_isNonEmpty (ppfname));
1346 if ((filesprocessed % skip) == 0)
1348 if (filesprocessed == 0) {
1349 displayScanContinue (cstring_makeLiteral (" "));
1352 displayScanContinue (cstring_makeLiteral ("."));
1358 DPRINTF (("outfile: %s", fileTable_fileName (dfile)));
1360 if (cppProcess (ppfname, fileTable_fileName (dfile)) != 0)
1362 llfatalerror (message ("Preprocessing error for file: %s",
1363 fileTable_rootFileName (fid)));
1366 fileIdList_add (dfiles, dfile);
1368 } end_fileIdList_elements;
1373 /* This should be in an lclUtils.c file... */
1374 char *specFullName (char *specfile, /*@out@*/ char **inpath)
1376 /* extract the path and the specname associated with the given file */
1377 char *specname = (char *) dmalloc (sizeof (*specname)
1378 * (strlen (specfile) + 9));
1379 char *ospecname = specname;
1380 char *path = (char *) dmalloc (sizeof (*path) * (strlen (specfile)));
1384 /* initialized path to empty string or may have accidental garbage */
1387 /*@-mayaliasunique@*/
1388 strcpy (specname, specfile);
1389 /*@=mayaliasunique@*/
1391 /* trim off pathnames in specfile */
1392 size = strlen (specname);
1394 for (i = size_toInt (size) - 1; i >= 0; i--)
1396 if (specname[i] == CONNECTCHAR)
1398 /* strcpy (specname, (char *)specname+i+1); */
1399 for (j = 0; j <= i; j++) /* include '/' */
1401 path[j] = specname[j];
1411 ** also remove .lcl file extension, assume it's the last extension
1415 size = strlen (specname);
1417 for (i = size_toInt (size) - 1; i >= 0; i--)
1419 if (specname[i] == '.')
1429 ** If specname no longer points to the original char,
1430 ** we need to allocate a new pointer and copy the string.
1433 if (specname != ospecname) {
1434 char *rspecname = (char *) dmalloc (sizeof (*rspecname) * (strlen (specname) + 1));
1435 strcpy (rspecname, specname); /* evs 2000-05-16: Bug: was ospecname! */
1443 void warnSysFiles(fileIdList files)
1445 fileIdList_elements (files, file)
1448 if (fileTable_isSystemFile (context_fileTable (), file) )
1450 if (!context_getFlag( FLG_SYSTEMDIRERRORS ) )
1452 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);
1456 end_fileIdList_elements;