2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2002 University of Virginia,
4 ** Massachusetts Institute of Technology
6 ** This program is free software; you can redistribute it and/or modify it
7 ** under the terms of the GNU General Public License as published by the
8 ** Free Software Foundation; either version 2 of the License, or (at your
9 ** option) any later version.
11 ** This program is distributed in the hope that it will be useful, but
12 ** WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ** General Public License for more details.
16 ** The GNU General Public License is available from http://www.gnu.org/ or
17 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18 ** MA 02111-1307, USA.
20 ** For information on splint: info@splint.org
21 ** To report a bug: splint-bug@splint.org
22 ** For more information: http://www.splint.org
27 ** Main module for Splint annotation-assisted program checker
33 ** Ensure that WIN32 and _WIN32 are both defined or both undefined.
38 # error "Inconsistent definitions."
42 # error "Inconsistent definitions."
51 # include "splintMacros.nf"
58 # include "scanline.h"
59 # include "lclscanline.h"
60 # include "lclsyntable.h"
61 # include "lcltokentable.h"
62 # include "lslparse.h"
64 # include "syntable.h"
65 # include "tokentable.h"
72 # include "Headers/version.h" /* Visual C++ finds the wrong version.h */
73 # include "fileIdList.h"
75 # include "cgrammar.h"
80 extern /*@external@*/ int yydebug;
82 static void printMail (void);
83 static void printMaintainer (void);
84 static void printReferences (void);
85 static void printFlags (void);
86 static void printAnnotations (void);
87 static void printParseErrors (void);
88 static void printComments (void);
89 static void describePrefixCodes (void);
90 static void cleanupFiles (void);
91 static void showHelp (void);
92 static void interrupt (int p_i);
94 static bool readOptionsFile (cstring p_fname,
95 cstringSList *p_passThroughArgs,
97 /*@modifies fileSystem, internalState, *p_passThroughArgs@*/ ;
99 static void loadrc (FILE *p_rcfile, cstringSList *p_passThroughArgs)
100 /*@modifies *p_passThroughArgs, p_rcfile@*/
101 /*@ensures closed p_rcfile@*/ ;
103 static void describeVars (void);
104 static bool specialFlagsHelp (char *p_next);
105 static bool hasShownHerald = FALSE;
106 static char *specFullName (char *p_specfile, /*@out@*/ char **p_inpath)
107 /*@modifies *p_inpath@*/ ;
109 static bool anylcl = FALSE;
110 static clock_t inittime;
112 static /*@only@*/ /*@null@*/ inputStream initFile = inputStream_undefined;
114 static fileIdList preprocessFiles (fileIdList, bool)
115 /*@modifies fileSystem@*/ ;
117 static void warnSysFiles(fileIdList p_files) /*@modifies fileSystem@*/;
122 void lslCleanup (void)
123 /*@globals killed g_symtab@*/
124 /*@modifies internalState, g_symtab@*/
127 ** Cleanup all the LCL/LSL.
130 static bool didCleanup = FALSE;
132 llassert (!didCleanup);
137 lsymbol_destroyMod ();
138 LCLSynTableCleanup ();
139 LCLTokenTableCleanup ();
140 LCLScanLineCleanup ();
143 /* clean up LSL parsing */
146 ltokenTableCleanup ();
150 symtable_free (g_symtab);
156 /*@globals undef g_symtab; @*/
157 /*@modifies g_symtab, internalState, fileSystem; @*/
160 ** Open init file provided by user, or use the default LCL init file
163 cstring larchpath = context_getLarchPath ();
164 inputStream LSLinitFile = inputStream_undefined;
168 if (inputStream_isUndefined (initFile))
170 initFile = inputStream_create (cstring_makeLiteral (INITFILENAME),
171 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
174 if (!inputStream_getPath (larchpath, initFile))
176 lldiagmsg (message ("Continuing without LCL init file: %s",
177 inputStream_fileName (initFile)));
181 if (!inputStream_open (initFile))
183 lldiagmsg (message ("Continuing without LCL init file: %s",
184 inputStream_fileName (initFile)));
190 if (!inputStream_open (initFile))
192 lldiagmsg (message ("Continuing without LCL init file: %s",
193 inputStream_fileName (initFile)));
197 /* Initialize checker */
205 LCLTokenTableInit ();
217 /* need this to initialize LCL checker */
219 llassert (inputStream_isDefined (initFile));
220 if (inputStream_isOpen (initFile))
224 LCLScanReset (initFile);
225 LCLProcessInitFileInit ();
226 LCLProcessInitFileReset ();
229 LCLProcessInitFile ();
230 LCLProcessInitFileCleanup ();
233 check (inputStream_close (initFile));
236 /* Initialize LSL init files, for parsing LSL signatures from LSL */
238 LSLinitFile = inputStream_create (cstring_makeLiteral ("lslinit.lsi"),
239 cstring_makeLiteralTemp (".lsi"),
242 if (!inputStream_getPath (larchpath, LSLinitFile))
244 lldiagmsg (message ("Continuing without LSL init file: %s",
245 inputStream_fileName (LSLinitFile)));
249 if (!inputStream_open (LSLinitFile))
251 lldiagmsg (message ("Continuing without LSL init file: %s",
252 inputStream_fileName (LSLinitFile)));
268 if (inputStream_isOpen (LSLinitFile))
271 LSLScanReset (LSLinitFile);
272 LSLProcessInitFileInit ();
274 LSLProcessInitFile ();
276 check (inputStream_close (LSLinitFile));
279 inputStream_free (LSLinitFile);
284 (cstring_makeLiteral ("LSL init file error. Attempting to continue."));
288 g_symtab = symtable_new ();
291 ** sort_init must come after symtab has been initialized
300 ** Equivalent to importing old spec_csupport.lcl
301 ** define immutable LCL type "bool" and bool constants TRUE and FALSE
302 ** and initialized them to be equal to LSL's "true" and "false".
304 ** Reads in CTrait.syms (derived from CTrait.lsl) on LARCH_PATH.
308 LCLReportEolTokens (FALSE);
312 lslProcess (fileIdList lclfiles)
313 /*@globals undef g_currentSpec, undef g_currentSpecName, g_currentloc,
314 undef killed g_symtab; @*/
315 /*@modifies g_currentSpec, g_currentSpecName, g_currentloc, internalState, fileSystem; @*/
318 bool parser_status = FALSE;
319 bool overallStatus = FALSE;
323 context_resetSpecLines ();
325 fileIdList_elements (lclfiles, fid)
327 cstring actualName = cstring_undefined;
328 cstring fname = fileTable_fileName (fid);
330 if (osd_getPath (cstring_fromChars (g_localSpecPath),
331 fname, &actualName) == OSD_FILENOTFOUND)
333 if (mstring_equal (g_localSpecPath, "."))
335 lldiagmsg (message ("Spec file not found: %q", osd_outputPath (fname)));
339 lldiagmsg (message ("Spec file not found: %q (on %s)",
340 osd_outputPath (fname),
341 cstring_fromChars (g_localSpecPath)));
346 inputStream specFile;
348 char *namePtr = actualName;
350 while (*namePtr == '.' && *(namePtr + 1) == CONNECTCHAR)
354 /*@noaccess cstring@*/
356 g_currentSpec = cstring_fromCharsNew (namePtr);
358 specFile = inputStream_create (cstring_copy (g_currentSpec),
359 LCL_EXTENSION, TRUE);
361 llassert (inputStream_isDefined (specFile));
363 g_currentSpecName = specFullName
364 (cstring_toCharsSafe (g_currentSpec),
369 displayScan (message ("reading spec %s", g_currentSpec));
371 /* Open the source file */
373 if (!inputStream_open (specFile))
375 lldiagmsg (message ("Cannot open file: %q",
376 osd_outputPath (inputStream_fileName (specFile))));
377 inputStream_free (specFile);
381 scopeInfo dummy_scope = (scopeInfo) dmalloc (sizeof (*dummy_scope));
382 dummy_scope->kind = SPE_INVALID;
385 LCLScanReset (specFile);
388 ** Minor hacks to allow more than one LCL file to
389 ** be scanned, while keeping initializations
392 symtable_enterScope (g_symtab, dummy_scope);
393 resetImports (cstring_fromChars (g_currentSpecName));
394 context_enterLCLfile ();
395 (void) lclHadNewError ();
397 parser_status = (ylparse () != 0);
398 context_exitLCLfile ();
400 overallStatus = parser_status || lclHadNewError ();
402 if (context_getFlag (FLG_DOLCS))
406 outputLCSFile (path, "%FAILED Output from ",
411 outputLCSFile (path, "%PASSED Output from ",
416 (void) inputStream_close (specFile);
417 inputStream_free (specFile);
419 symtable_exitScope (g_symtab);
422 cstring_free (actualName);
423 } end_fileIdList_elements;
425 /* Can cleanup lsl stuff right away */
429 g_currentSpec = cstring_undefined;
430 g_currentSpecName = NULL;
434 static void handlePassThroughFlag (char *arg)
437 char *quotechar = strchr (curarg, '\"');
440 char *freearg = NULL;
442 while (quotechar != NULL)
444 if (*(quotechar - 1) == '\\')
446 char *tp = quotechar - 2;
457 curarg = quotechar + 1;
458 quotechar = strchr (curarg, '\"');
463 llassert (quotechar != NULL);
465 offset = (quotechar - arg) + 2;
469 arg = cstring_toCharsSafe
470 (message ("%s\"\'%s",
471 cstring_fromChars (arg),
472 cstring_fromChars (quotechar + 1)));
478 arg = cstring_toCharsSafe
479 (message ("%s\'\"%s",
480 cstring_fromChars (arg),
481 cstring_fromChars (quotechar + 1)));
486 curarg = arg + offset;
487 quotechar = strchr (curarg, '\"');
493 voptgenerror (FLG_BADFLAG,
494 message ("Unclosed quote in flag: %s",
495 cstring_fromChars (arg)),
504 ** If the value is surrounded by single quotes ('), remove
505 ** them. This is an artifact of UNIX command line?
508 def = osd_fixDefine (cstring_fromChars (arg + 1));
509 DPRINTF (("Do define: %s", def));
511 DPRINTF (("After define"));
513 } else if (arg[0] == 'U') {
514 cppDoUndefine (cstring_fromChars (arg + 1));
523 void showHerald (void)
525 if (hasShownHerald || context_getFlag (FLG_QUIET))
531 fprintf (g_messagestream, "%s\n\n", SPLINT_VERSION);
532 hasShownHerald = TRUE;
537 static cstring findLarchPathFile (/*@temp@*/ cstring s)
542 status = osd_getPath (context_getLarchPath (), s, &pathName);
544 if (status == OSD_FILEFOUND)
548 else if (status == OSD_FILENOTFOUND)
551 lldiagmsg (message ("Cannot find file on LARCH_PATH: %s", s));
553 else if (status == OSD_PATHTOOLONG)
555 /* Directory and filename are too long. Report error. */
556 llbuglit ("soure_getPath: Filename plus directory from search path too long");
563 return cstring_undefined;
566 static void addLarchPathFile (fileIdList files, /*@temp@*/ cstring s)
568 cstring pathName = findLarchPathFile (s);
570 if (cstring_isDefined (pathName))
572 if (fileTable_exists (context_fileTable (), pathName))
575 lldiagmsg (message ("File listed multiple times: %s", pathName));
576 cstring_free (pathName);
580 fileIdList_add (files, fileTable_addFileOnly (context_fileTable (), pathName));
585 static void addFile (fileIdList files, /*@only@*/ cstring s)
587 if (fileTable_exists (context_fileTable (), s))
590 lldiagmsg (message ("File listed multiple times: %s", s));
595 fileIdList_add (files, fileTable_addFileOnly (context_fileTable (), s));
599 static void addXHFile (fileIdList files, /*@temp@*/ cstring s)
601 cstring pathName = findLarchPathFile (s);
603 if (cstring_isDefined (pathName))
605 if (fileTable_exists (context_fileTable (), pathName))
608 lldiagmsg (message ("File listed multiple times: %s", s));
612 fileIdList_add (files, fileTable_addXHFile (context_fileTable (), pathName));
616 cstring_free (pathName);
620 ** Disable MSVC++ warning about return value. Methinks humbly splint control
621 ** comments are a mite more legible.
625 # pragma warning (disable:4035)
628 int main (int argc, char *argv[])
630 /*@globals killed undef g_currentloc,
632 undef g_warningstream, g_messagestream, g_errorstream;
634 /*@modifies g_currentloc, fileSystem,
638 /*@globals killed undef g_currentloc,
639 killed undef initFile,
640 killed g_localSpecPath,
641 killed undef g_currentSpec,
642 killed undef g_currentSpecName,
644 undef g_warningstream, g_messagestream, g_errorstream;
646 /*@modifies g_currentloc, initFile,
647 g_localSpecPath, g_currentSpec, g_currentSpecName, fileSystem,
652 bool first_time = TRUE;
654 inputStream sourceFile = inputStream_undefined;
656 fileIdList dercfiles;
657 cstringSList fl = cstringSList_undefined;
658 cstringSList passThroughArgs = cstringSList_undefined;
659 fileIdList cfiles, xfiles, lclfiles, mtfiles;
660 clock_t before, lcltime, libtime, pptime, cptime, rstime;
664 _wildcard (&argc, &argv);
667 g_warningstream = stdout;
668 g_messagestream = stderr;
669 g_errorstream = stderr;
671 (void) signal (SIGINT, interrupt);
672 (void) signal (SIGSEGV, interrupt);
674 cfiles = fileIdList_create ();
675 xfiles = fileIdList_create ();
676 lclfiles = fileIdList_create ();
677 mtfiles = fileIdList_create ();
680 clabstract_initMod ();
681 typeIdSet_initMod ();
682 cppReader_initMod ();
687 g_currentloc = fileloc_createBuiltin ();
692 context_setInCommandLine ();
700 /* -help must be the first flag to get help */
701 if (flagcode_isHelpFlag (flags_identifyFlag (argv[1])))
703 flags_processHelp (argc - 1, argv + 1);
711 ** Add include directories from environment.
715 cstring incval = cstring_copy (osd_getEnvironmentVariable (INCLUDEPATH_VAR));
716 cstring oincval = incval;
718 if (cstring_isDefined (incval))
721 ** Each directory on the include path is a system include directory.
724 DPRINTF (("include: %s", incval));
725 context_setString (FLG_SYSTEMDIRS, cstring_copy (incval));
727 while (cstring_isDefined (incval))
730 char *nextsep = strchr (incval, PATH_SEPARATOR);
736 dir = cstring_copy (incval);
738 if (cstring_length (dir) == 0
739 || !isalpha ((int) cstring_firstChar (dir)))
742 ** win32 environment values can have special values,
748 cppAddIncludeDir (dir);
751 *nextsep = PATH_SEPARATOR;
752 incval = cstring_fromChars (nextsep + 1);
760 /*@noaccess cstring@*/
763 else /* 2001-09-09: herbert */
765 /* Put C_INCLUDE_PATH directories in sysdirs */
766 cstring cincval = osd_getEnvironmentVariable (cstring_makeLiteralTemp ("C_INCLUDE_PATH"));
768 if (cstring_isDefined (cincval))
770 context_setString (FLG_SYSTEMDIRS, cstring_copy (cincval));
775 cstring_free (oincval);
779 ** check RCFILE for default flags
783 cstring home = osd_getHomeDir ();
784 cstring fname = cstring_undefined;
785 bool defaultf = TRUE;
788 for (i = 1; i < argc; i++)
793 if (*thisarg == '-' || *thisarg == '+')
795 bool set = (*thisarg == '+');
801 ** Don't report warnings this time
804 opt = flags_identifyFlagQuiet (cstring_fromChars (thisarg));
810 else if (flagcode_isMessageControlFlag (opt))
813 ** Need to set it immediately, so rc file scan is displayed
816 context_userSetFlag (opt, set);
818 if (flagcode_hasArgument (opt))
820 llassert (flagcode_hasString (opt));
824 fname = cstring_fromChars (argv[i]);
825 setStringFlag (opt, fname);
831 ("Flag %s must be followed by a string",
832 flagcode_unparse (opt)));
836 else if (opt == FLG_OPTF)
841 fname = cstring_fromChars (argv[i]);
842 (void) readOptionsFile (fname, &passThroughArgs, TRUE);
846 (cstring_makeLiteral ("Flag f to select options file "
847 "requires an argument"));
851 ; /* wait to process later */
858 if (!nof && defaultf)
861 ** No explicit rc file, first try reading ~/.splintrc
864 if (cstring_isUndefined (fname))
866 if (!cstring_isEmpty (home))
868 bool readhomerc, readaltrc;
869 cstring homename, altname;
871 homename = message ("%s%h%s", home, CONNECTCHAR,
872 cstring_fromChars (RCFILE));
873 readhomerc = readOptionsFile (homename, &passThroughArgs, FALSE);
876 ** Try ~/.splintrc also for historical accuracy
879 altname = message ("%s%h%s", home, CONNECTCHAR,
880 cstring_fromChars (ALTRCFILE));
881 readaltrc = readOptionsFile (altname, &passThroughArgs, FALSE);
883 if (readhomerc && readaltrc)
888 message ("Found both %s and %s files. Using both files, "
889 "but recommend using only %s to avoid confusion.",
890 homename, altname, homename),
894 cstring_free (homename);
895 cstring_free (altname);
900 ** Next, read .splintrc in the current working directory
904 cstring rcname = message ("%s%s",osd_getCurrentDirectory (), cstring_fromChars (RCFILE));
905 cstring altname = message ("%s%s",osd_getCurrentDirectory (), cstring_fromChars (ALTRCFILE));
906 bool readrc, readaltrc;
908 readrc = readOptionsFile (rcname, &passThroughArgs, FALSE);
909 readaltrc = readOptionsFile (altname, &passThroughArgs, FALSE);
911 if (readrc && readaltrc)
913 voptgenerror (FLG_WARNRC,
914 message ("Found both %s and %s files. Using both files, "
915 "but recommend using only %s to avoid confusion.",
916 rcname, altname, rcname),
921 cstring_free (rcname);
922 cstring_free (altname);
929 /* argv[0] is the program name, don't pass it to flags_processFlags */
930 flags_processFlags (argc - 1, argv + 1);
935 ** create lists of C and LCL files
938 cstringSList_elements (fl, current)
940 cstring ext = fileLib_getExtension (current);
942 if (cstring_isUndefined (ext))
944 /* no extension --- both C and LCL with default extensions */
946 addFile (cfiles, message ("%s%s", current, C_EXTENSION));
947 addFile (lclfiles, message ("%s%s", current, LCL_EXTENSION));
949 else if (cstring_equal (ext, XH_EXTENSION))
951 addXHFile (xfiles, current);
953 else if (cstring_equal (ext, PP_EXTENSION))
955 if (!context_getFlag (FLG_NOPP))
959 message ("File extension %s used without +nopp flag (will be processed as C source code): %s",
964 addFile (cfiles, cstring_copy (current));
966 else if (cstring_equal (ext, LCL_EXTENSION))
968 addFile (lclfiles, cstring_copy (current));
970 else if (fileLib_isCExtension (ext))
972 addFile (cfiles, cstring_copy (current));
974 else if (cstring_equal (ext, MTS_EXTENSION))
976 addLarchPathFile (mtfiles, current);
982 message ("Unrecognized file extension: %s (assuming %s is C source code)",
986 addFile (cfiles, cstring_copy (current));
988 } end_cstringSList_elements;
996 fprintf (g_warningstream, "\n");
998 fileIdList_free (cfiles);
999 fileIdList_free (xfiles);
1000 fileIdList_free (lclfiles);
1009 inittime = clock ();
1011 context_resetErrors ();
1012 context_clearInCommandLine ();
1014 anylcl = !fileIdList_isEmpty (lclfiles);
1016 if (context_doMerge ())
1018 cstring m = context_getMerge ();
1020 displayScanOpen (message ("< loading %s ", m));
1022 displayScanClose ();
1024 if (!usymtab_existsType (context_getBoolName ()))
1026 usymtab_initBool ();
1031 if (!context_getFlag (FLG_NOLIB) && loadStandardState ())
1040 /* setup bool type and constants */
1041 usymtab_initBool ();
1044 fileloc_free (g_currentloc);
1045 g_currentloc = fileloc_createBuiltin ();
1048 ** Read metastate files (must happen before loading libraries)
1051 fileIdList_elements (mtfiles, mtfile)
1053 context_setFileId (mtfile);
1054 displayScan (message ("processing %s", fileTable_rootFileName (mtfile)));
1055 mtreader_readFile (cstring_copy (fileTable_fileName (mtfile)));
1056 } end_fileIdList_elements;
1063 llfatalerror (cstring_makeLiteral ("This version of Splint does not handle LCL files."));
1065 lslProcess (lclfiles);
1069 usymtab_initGlobalMarker ();
1074 ** call the pre-preprocessor and /lib/cpp to generate appropriate
1079 context_setInCommandLine ();
1081 DPRINTF (("Pass through: %s", cstringSList_unparse (passThroughArgs)));
1083 cstringSList_elements (passThroughArgs, thisarg) {
1084 handlePassThroughFlag (cstring_toCharsSafe (thisarg));
1085 } end_cstringSList_elements;
1087 cstringSList_free (passThroughArgs);
1091 DPRINTF (("Initializing cpp reader!"));
1092 cppReader_initialize ();
1093 cppReader_saveDefinitions ();
1095 context_clearInCommandLine ();
1097 if (!context_getFlag (FLG_NOPP))
1103 displayScanOpen (cstring_makeLiteral ("preprocessing"));
1107 context_setPreprocessing ();
1108 dercfiles = preprocessFiles (xfiles, TRUE);
1109 tfiles = preprocessFiles (cfiles, FALSE);
1110 warnSysFiles(cfiles);
1111 dercfiles = fileIdList_append (dercfiles, tfiles);
1112 fileIdList_free (tfiles);
1114 context_clearPreprocessing ();
1116 fileIdList_free (cfiles);
1118 displayScanClose ();
1124 dercfiles = fileIdList_append (cfiles, xfiles);
1129 ** now, check all the corresponding C files
1131 ** (for now these are just <file>.c, but after pre-processing
1132 ** will be <tmpprefix>.<file>.c)
1137 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1141 llbug (message ("Files unclosed: %d", nfiles));
1146 DPRINTF (("Initializing..."));
1148 exprNode_initMod ();
1150 DPRINTF (("Okay..."));
1152 fileIdList_elements (dercfiles, fid)
1154 sourceFile = inputStream_create (cstring_copy (fileTable_fileName (fid)), C_EXTENSION, TRUE);
1155 context_setFileId (fid);
1157 /* Open source file */
1159 if (inputStream_isUndefined (sourceFile) || (!inputStream_open (sourceFile)))
1161 /* previously, this was ignored ?! */
1162 llbug (message ("Could not open temp file: %s", fileTable_fileName (fid)));
1166 yyin = inputStream_getFile (sourceFile); /*< shared <- only */
1168 llassert (yyin != NULL);
1170 displayScan (message ("checking %q", osd_outputPath (fileTable_rootFileName (fid))));
1173 ** Every time, except the first time, through the loop,
1174 ** need to call yyrestart to clean up the parse buffer.
1179 (void) yyrestart (yyin);
1186 DPRINTF (("Entering..."));
1187 context_enterFile ();
1189 context_exitCFile ();
1191 (void) inputStream_close (sourceFile);
1193 } end_fileIdList_elements;
1197 /* process any leftover macros */
1199 context_processAllMacros ();
1201 /* check everything that was specified was defined */
1203 /* don't check if no c files were processed ?
1204 ** is this correct behaviour?
1207 displayScan (cstring_makeLiteral ("global checks"));
1211 if (context_getLinesProcessed () > 0)
1213 usymtab_allDefined ();
1216 if (context_maybeSet (FLG_TOPUNUSED))
1218 uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main"));
1220 if (uentry_isValid (ue))
1222 uentry_setUsed (ue, fileloc_observeBuiltin ());
1228 if (context_maybeSet (FLG_EXPORTLOCAL))
1230 usymtab_exportLocal ();
1234 if (context_maybeSet (FLG_EXPORTHEADER))
1236 usymtab_exportHeader ();
1239 if (context_getFlag (FLG_SHOWUSES))
1241 usymtab_displayAllUses ();
1244 context_checkSuppressCounts ();
1246 if (context_doDump ())
1248 cstring dump = context_getDump ();
1259 if (context_getFlag (FLG_SHOWSUMMARY))
1266 bool isQuiet = context_getFlag (FLG_QUIET);
1267 cstring specErrors = cstring_undefined;
1269 int nspecErrors = lclNumberErrors ();
1274 if (context_neednl ())
1275 fprintf (g_warningstream, "\n");
1278 if (nspecErrors > 0)
1280 if (nspecErrors == context_getLCLExpect ())
1283 message ("%d spec warning%&, as expected\n ",
1288 if (context_getLCLExpect () > 0)
1291 message ("%d spec warning%&, expected %d\n ",
1293 (int) context_getLCLExpect ());
1297 specErrors = message ("%d spec warning%&\n ",
1305 if (context_getLCLExpect () > 0)
1307 specErrors = message ("No spec warnings, expected %d\n ",
1308 (int) context_getLCLExpect ());
1314 if (context_anyErrors ())
1316 if (context_numErrors () == context_getExpect ())
1319 llmsg (message ("Finished checking --- "
1320 "%s%d code warning%&, as expected",
1321 specErrors, context_numErrors ()));
1326 if (context_getExpect () > 0)
1330 ("Finished checking --- "
1331 "%s%d code warning%&, expected %d",
1332 specErrors, context_numErrors (),
1333 (int) context_getExpect ()));
1343 llmsg (message ("Finished checking --- "
1344 "%s%d code warning%&",
1345 specErrors, context_numErrors ()));
1354 if (context_getExpect () > 0)
1358 ("Finished checking --- "
1359 "%sno code warnings, expected %d",
1361 (int) context_getExpect ()));
1368 if (context_getLinesProcessed () > 0)
1370 if (cstring_isEmpty (specErrors))
1374 llmsg (message ("Finished checking --- no warnings"));
1381 llmsg (message ("Finished checking --- %sno code warnings",
1389 llmsg (message ("Finished checking --- %sno code processed",
1396 cstring_free (specErrors);
1399 if (context_getFlag (FLG_STATS))
1401 clock_t ttime = clock () - before;
1402 int specLines = context_getSpecLinesProcessed ();
1408 fprintf (g_warningstream, "%d spec, ", specLines);
1411 # ifndef CLOCKS_PER_SEC
1412 fprintf (g_warningstream, "%d source lines in %ld time steps (steps/sec unknown)\n",
1413 context_getLinesProcessed (),
1416 fprintf (g_warningstream, "%d source lines in %.2f s.\n",
1417 context_getLinesProcessed (),
1418 (double) ttime / CLOCKS_PER_SEC);
1426 if (context_getFlag (FLG_TIMEDIST))
1428 clock_t ttime = clock () - before;
1432 char *msg = (char *) dmalloc (256 * sizeof (*msg));
1437 "Time distribution (percent): initialize %.2f / lcl %.2f / "
1438 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1439 (100.0 * (double) (libtime - before) / ttime),
1440 (100.0 * (double) (lcltime - libtime) / ttime),
1441 (100.0 * (double) (pptime - lcltime) / ttime),
1442 (100.0 * (double) (cptime - pptime) / ttime),
1443 (100.0 * (double) (rstime - cptime) / ttime));
1448 "Time distribution (percent): initialize %.2f / "
1449 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1450 (100.0 * (double) (libtime - before) / ttime),
1451 (100.0 * (double) (pptime - libtime) / ttime),
1452 (100.0 * (double) (cptime - pptime) / ttime),
1453 (100.0 * (double) (rstime - cptime) / ttime));
1456 llgenindentmsgnoloc (cstring_fromCharsO (msg));
1460 llexit (expsuccess ? LLSUCCESS : LLFAILURE);
1461 BADBRANCHRET (LLFAILURE);
1466 ** Reenable return value warnings.
1468 # pragma warning (default:4035)
1476 llmsg (message ("Source files are .c, .h and %s files. If there is no suffix,",
1478 llmsg (message (" Splint will look for <file>.c and <file>%s.", LCL_EXTENSION));
1480 llmsglit ("Use splint -help <topic or flag name> for more information");
1482 llmsglit ("Topics:");
1484 llmsglit (" annotations (describes source-code annotations)");
1485 llmsglit (" comments (describes control comments)");
1486 llmsglit (" flags (describes flag categories)");
1487 llmsglit (" flags <category> (describes flags in category)");
1488 llmsglit (" flags all (short description of all flags)");
1489 llmsglit (" flags alpha (list all flags alphabetically)");
1490 llmsglit (" flags full (full description of all flags)");
1491 llmsglit (" mail (information on mailing lists)");
1492 llmsglit (" modes (show mode settings)");
1493 llmsglit (" parseerrors (help on handling parser errors)");
1494 llmsglit (" prefixcodes (character codes in namespace prefixes)");
1495 llmsglit (" references (sources for more information)");
1496 llmsglit (" vars (environment variables)");
1497 llmsglit (" version (information on compilation, maintainer)");
1502 specialFlagsHelp (char *next)
1504 if ((next != NULL) && (*next != '-') && (*next != '+'))
1506 if (mstring_equal (next, "alpha"))
1511 else if (mstring_equal (next, "all"))
1513 printAllFlags (TRUE, FALSE);
1516 else if (mstring_equal (next, "categories")
1517 || mstring_equal (next, "cats"))
1519 listAllCategories ();
1522 else if (mstring_equal (next, "full"))
1524 printAllFlags (FALSE, TRUE);
1527 else if (mstring_equal (next, "manual"))
1529 printFlagManual (FALSE);
1532 else if (mstring_equal (next, "webmanual"))
1534 printFlagManual (TRUE);
1549 printParseErrors (void)
1551 llmsglit ("Parse Errors");
1552 llmsglit ("------------");
1554 llmsglit ("Splint will sometimes encounter a parse error for code that "
1555 "can be parsed with a local compiler. There are a few likely "
1556 "causes for this and a number of techniques that can be used "
1557 "to work around the problem.");
1559 llmsglit ("Compiler extensions --- compilers sometimes extend the C "
1560 "language with compiler-specific keywords and syntax. While "
1561 "it is not advisible to use these, oftentimes one has no choice "
1562 "when the system header files use compiler extensions. ");
1564 llmsglit ("Splint supports some of the GNU (gcc) compiler extensions, "
1565 "if the +gnuextensions flag is set. You may be able to workaround "
1566 "other compiler extensions by using a pre-processor define. "
1567 "Alternately, you can surround the unparseable code with");
1569 llmsglit (" # ifndef S_SPLINT_S");
1571 llmsglit (" # endif");
1573 /* evans 2000-12-21 fixed typo reported by Jeroen Ruigrok/Asmodai */
1574 llmsglit ("Missing type definitions --- an undefined type name will usually "
1575 "lead to a parse error. This often occurs when a standard header "
1576 "file defines some type that is not part of the standard library. ");
1577 llmsglit ("By default, Splint does not process the local files corresponding "
1578 "to standard library headers, but uses a library specification "
1579 "instead so dependencies on local system headers can be detected. "
1580 "If another system header file that does not correspond to a "
1581 "standard library header uses one of these superfluous types, "
1582 "a parse error will result.");
1584 llmsglit ("If the parse error is inside a posix standard header file, the "
1585 "first thing to try is +posixlib. This makes Splint use "
1586 "the posix library specification instead of reading the posix "
1589 llmsglit ("Otherwise, you may need to either manually define the problematic "
1590 "type (e.g., add -Dmlink_t=int to your .splintrc file) or force "
1591 "splint to process the header file that defines it. This is done "
1592 "by setting -skipisoheaders or -skipposixheaders before "
1593 "the file that defines the type is #include'd.");
1594 llmsglit ("(See splint -help "
1595 "skipisoheaders and splint -help skipposixheaders for a list of "
1596 "standard headers.) For example, if <sys/local.h> uses a type "
1597 "defined by posix header <sys/types.h> but not defined by the "
1598 "posix library, we might do: ");
1600 llmsglit (" /*@-skipposixheaders@*/");
1601 llmsglit (" # include <sys/types.h>");
1602 llmsglit (" /*@=skipposixheaders@*/");
1603 llmsglit (" # include <sys/local.h>");
1605 llmsglit ("to force Splint to process <sys/types.h>.");
1607 llmsglit ("At last resort, +trytorecover can be used to make Splint attempt "
1608 "to continue after a parse error. This is usually not successful "
1609 "and the author does not consider assertion failures when +trytorecover "
1610 "is used to be bugs.");
1614 printAnnotations (void)
1616 llmsglit ("Annotations");
1617 llmsglit ("-----------");
1619 llmsglit ("Annotations are semantic comments that document certain "
1620 "assumptions about functions, variables, parameters, and types. ");
1622 llmsglit ("They may be used to indicate where the representation of a "
1623 "user-defined type is hidden, to limit where a global variable may "
1624 "be used or modified, to constrain what a function implementation "
1625 "may do to its parameters, and to express checked assumptions about "
1626 "variables, types, structure fields, function parameters, and "
1627 "function results.");
1629 llmsglit ("Annotations are introduced by \"/*@\". The role of the @ may be "
1630 "played by any printable character, selected using -commentchar <char>.");
1632 llmsglit ("Consult the User's Guide for descriptions of checking associated with each annotation.");
1634 llmsglit ("Globals: (in function declarations)");
1635 llmsglit (" /*@globals <globitem>,+ @*/");
1636 llmsglit (" globitem is an identifier, internalState or fileSystem");
1638 llmsglit ("Modifies: (in function declarations)");
1639 llmsglit (" /*@modifies <moditem>,+ @*/");
1640 llmsglit (" moditem is an lvalue");
1641 llmsglit (" /*@modifies nothing @*/");
1642 llmsglit (" /*@*/ (Abbreviation for no globals and modifies nothing.)");
1644 llmsglit ("Iterators:");
1645 llmsglit (" /*@iter <identifier> (<parameter-type-list>) @*/ - declare an iterator");
1647 llmsglit ("Constants:");
1648 llmsglit (" /*@constant <declaration> @*/ - declares a constant");
1650 llmsglit ("Alternate Types:");
1651 llmsglit (" /*@alt <basic-type>,+ @*/");
1652 llmsglit (" (e.g., int /*@alt char@*/ is a type matching either int or char)");
1654 llmsglit ("Declarator Annotations");
1656 llmsglit ("Type Definitions:");
1657 llmsglit (" /*@abstract@*/ - representation is hidden from clients");
1658 llmsglit (" /*@concrete@*/ - representation is visible to clients");
1659 llmsglit (" /*@immutable@*/ - instances of the type cannot change value");
1660 llmsglit (" /*@mutable@*/ - instances of the type can change value");
1661 llmsglit (" /*@refcounted@*/ - reference counted type");
1663 llmsglit ("Global Variables:");
1664 llmsglit (" /*@unchecked@*/ - weakest checking for global use");
1665 llmsglit (" /*@checkmod@*/ - check modification by not use of global");
1666 llmsglit (" /*@checked@*/ - check use and modification of global");
1667 llmsglit (" /*@checkedstrict@*/ - check use of global strictly");
1669 llmsglit ("Memory Management:");
1670 llmsglit (" /*@dependent@*/ - a reference to externally-owned storage");
1671 llmsglit (" /*@keep@*/ - a parameter that is kept by the called function");
1672 llmsglit (" /*@killref@*/ - a refcounted parameter, killed by the call");
1673 llmsglit (" /*@only@*/ - an unshared reference");
1674 llmsglit (" /*@owned@*/ - owner of storage that may be shared by /*@dependent@*/ references");
1675 llmsglit (" /*@shared@*/ - shared reference that is never deallocated");
1676 llmsglit (" /*@temp@*/ - temporary parameter");
1678 llmsglit ("Aliasing:");
1679 llmsglit (" /*@unique@*/ - may not be aliased by any other visible reference");
1680 llmsglit (" /*@returned@*/ - may be aliased by the return value");
1682 llmsglit ("Exposure:");
1683 llmsglit (" /*@observer@*/ - reference that cannot be modified");
1684 llmsglit (" /*@exposed@*/ - exposed reference to storage in another object");
1686 llmsglit ("Definition State:");
1687 llmsglit (" /*@out@*/ - storage reachable from reference need not be defined");
1688 llmsglit (" /*@in@*/ - all storage reachable from reference must be defined");
1689 llmsglit (" /*@partial@*/ - partially defined, may have undefined fields");
1690 llmsglit (" /*@reldef@*/ - relax definition checking");
1692 llmsglit ("Global State: (for globals lists, no /*@, since list is already in /*@\'s)");
1693 llmsglit (" undef - variable is undefined before the call");
1694 llmsglit (" killed - variable is undefined after the call");
1696 llmsglit ("Null State:");
1697 llmsglit (" /*@null@*/ - possibly null pointer");
1698 llmsglit (" /*@notnull@*/ - definitely non-null pointer");
1699 llmsglit (" /*@relnull@*/ - relax null checking");
1701 llmsglit ("Null Predicates:");
1702 llmsglit (" /*@nullwhentrue@*/ - if result is TRUE, first parameter is NULL");
1703 llmsglit (" /*@falsewhennull@*/ - if result is TRUE, first parameter is not NULL");
1705 llmsglit ("Execution:");
1706 llmsglit (" /*@noreturn@*/ - function never returns");
1707 llmsglit (" /*@maynotreturn@*/ - function may or may not return");
1708 llmsglit (" /*@noreturnwhentrue@*/ - function does not return if first parameter is TRUE");
1709 llmsglit (" /*@noreturnwhenfalse@*/ - function does not return if first parameter if FALSE");
1710 llmsglit (" /*@alwaysreturns@*/ - function always returns");
1712 llmsglit ("Side-Effects:");
1713 llmsglit (" /*@sef@*/ - corresponding actual parameter has no side effects");
1715 llmsglit ("Declaration:");
1716 llmsglit (" /*@unused@*/ - need not be used (no unused errors reported)");
1717 llmsglit (" /*@external@*/ - defined externally (no undefined error reported)");
1720 llmsglit (" /*@fallthrough@*/ - fall-through case");
1722 llmsglit ("Break:");
1723 llmsglit (" /*@innerbreak@*/ - break is breaking an inner loop or switch");
1724 llmsglit (" /*@loopbreak@*/ - break is breaking a loop");
1725 llmsglit (" /*@switchbreak@*/ - break is breaking a switch");
1726 llmsglit (" /*@innercontinue@*/ - continue is continuing an inner loop");
1728 llmsglit ("Unreachable Code:");
1729 llmsglit (" /*@notreached@*/ - statement may be unreachable.");
1731 llmsglit ("Special Functions:");
1732 llmsglit (" /*@printflike@*/ - check variable arguments like printf");
1733 llmsglit (" /*@scanflike@*/ - check variable arguments like scanf");
1737 printComments (void)
1739 llmsglit ("Control Comments");
1740 llmsglit ("----------------");
1742 llmsglit ("Setting Flags");
1744 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.");
1746 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,");
1747 llmsglit (" /*@+boolint -modifies =showfunc@*/");
1748 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).");
1750 llmsglit ("Error Suppression");
1752 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.");
1754 llmsglit ("/*@ignore@*/ ... /*@end@*/");
1756 (cstring_makeLiteral
1757 ("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."));
1758 llmsglit ("/*@i@*/");
1760 (cstring_makeLiteral
1761 ("No errors will be reported from an /*@i@*/ comment to the end of the line."));
1762 llmsglit ("/*@i<n>@*/");
1764 (cstring_makeLiteral
1765 ("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."));
1766 llmsglit ("/*@t@*/, /*@t<n>@*/");
1768 (cstring_makeLiteral
1769 ("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."));
1771 llmsglit ("Type Access");
1773 llmsglit ("/*@access <type>@*/");
1774 llmsglit (" Allows the following code to access the representation of <type>");
1775 llmsglit ("/*@noaccess <type>@*/");
1776 llmsglit (" Hides the representation of <type>");
1778 llmsglit ("Macro Expansion");
1780 llmsglit ("/*@notfunction@*/");
1782 (cstring_makeLiteral
1783 ("Indicates that the next macro definition is not intended to be a "
1784 "function, and should be expanded in line instead of checked as a "
1785 "macro function definition."));
1792 llmsglit ("Flag Categories");
1793 llmsglit ("---------------");
1794 listAllCategories ();
1795 llmsglit ("\nTo see the flags in a flag category, do\n splint -help flags <category>");
1796 llmsglit ("To see a list of all flags in alphabetical order, do\n splint -help flags alpha");
1797 llmsglit ("To see a full description of all flags, do\n splint -help flags full");
1801 printMaintainer (void)
1803 llmsg (message ("Maintainer: %s", cstring_makeLiteralTemp (SPLINT_MAINTAINER)));
1804 llmsglit (LCL_COMPILE);
1810 llmsglit ("Mailing Lists");
1811 llmsglit ("-------------");
1813 llmsglit ("There are two mailing lists associated with Splint: ");
1815 llmsglit (" lclint-announce@virginia.edu");
1817 llmsglit (" Reserved for announcements of new releases and bug fixes.");
1818 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
1819 llmsglit (" subscribe lclint-announce");
1821 llmsglit (" lclint-interest@virginia.edu");
1823 llmsglit (" Informal discussions on the use and development of Splint.");
1824 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
1825 llmsglit (" subscribe lclint-interest");
1829 printReferences (void)
1831 llmsglit ("References");
1832 llmsglit ("----------");
1834 llmsglit ("For more information, see the Splint web site: http://www.splint.org");
1838 describePrefixCodes (void)
1840 llmsglit ("Prefix Codes");
1841 llmsglit ("------------");
1843 llmsglit ("These characters have special meaning in name prefixes:");
1845 llmsg (message (" %h Any uppercase letter [A-Z]", PFX_UPPERCASE));
1846 llmsg (message (" %h Any lowercase letter [a-z]", PFX_LOWERCASE));
1847 llmsg (message (" %h Any character (valid in a C identifier)", PFX_ANY));
1848 llmsg (message (" %h Any digit [0-9]", PFX_DIGIT));
1849 llmsg (message (" %h Any non-uppercase letter [a-z0-9_]", PFX_NOTUPPER));
1850 llmsg (message (" %h Any non-lowercase letter [A-Z0-9_]", PFX_NOTLOWER));
1851 llmsg (message (" %h Any letter [A-Za-z]", PFX_ANYLETTER));
1852 llmsg (message (" %h Any letter or digit [A-Za-z0-9]", PFX_ANYLETTERDIGIT));
1853 llmsglit (" * Zero or more repetitions of the previous character class until the end of the name");
1862 eval = context_getLarchPath ();
1863 def = osd_getEnvironmentVariable (LARCH_PATH);
1865 if (cstring_isDefined (def) ||
1866 !cstring_equal (eval, cstring_fromChars (DEFAULT_LARCHPATH)))
1868 llmsg (message ("LARCH_PATH = %s", eval));
1872 llmsg (message ("LARCH_PATH = <not set> (default = %s)",
1873 cstring_fromChars (DEFAULT_LARCHPATH)));
1876 llmsglit (" --- path used to find larch initialization files and LSL traits");
1878 eval = context_getLCLImportDir ();
1879 def = osd_getEnvironmentVariable (cstring_makeLiteralTemp (LCLIMPORTDIR));
1881 if (cstring_isDefined (def) ||
1882 !cstring_equal (eval, cstring_fromChars (DEFAULT_LCLIMPORTDIR)))
1884 llmsg (message ("%q = %s", cstring_makeLiteral (LCLIMPORTDIR), eval));
1888 llmsg (message ("%s = <not set, default: %s>", cstring_makeLiteralTemp (LCLIMPORTDIR),
1889 cstring_makeLiteralTemp (DEFAULT_LCLIMPORTDIR)));
1892 llmsglit (" --- directory containing lcl standard library files "
1893 "(import with < ... >)");;
1896 ("include path = %q (set by environment variable %s and -I flags)",
1897 cppReader_getIncludePath (), INCLUDEPATH_VAR));
1899 llmsglit (" --- path used to find #include'd files");
1902 ("systemdirs = %s (set by -systemdirs or environment variable %s)", /*@i413223@*/
1903 context_getString (FLG_SYSTEMDIRS),
1906 llmsglit (" --- if file is found on this path, it is treated as a system file for error reporting");
1915 fprintf (g_errorstream, "*** Interrupt\n");
1916 llexit (LLINTERRUPT);
1921 /* Cheat when there are parse errors */
1924 fprintf (g_errorstream, "*** Segmentation Violation\n");
1926 /* Don't catch it if fileloc_unparse causes a signal */
1927 (void) signal (SIGSEGV, NULL);
1929 loc = fileloc_unparse (g_currentloc);
1931 fprintf (g_errorstream, "*** Location (not trusted): %s\n",
1932 cstring_toCharsSafe (loc));
1935 fprintf (g_errorstream, "*** Please report bug to %s\n", SPLINT_MAINTAINER);
1939 fprintf (g_errorstream, "*** Signal: %d\n", i);
1941 fprintf (g_errorstream, "*** Location (not trusted): %s\n",
1942 cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
1945 fprintf (g_errorstream, "*** Please report bug to %s ***\n", SPLINT_MAINTAINER);
1953 static bool doneCleanup = FALSE;
1955 /* make sure this is only called once! */
1957 if (doneCleanup) return;
1962 ** Close all open files
1963 ** (There should only be open files, if we exited after a fatal error.)
1966 fileTable_closeAll (context_fileTable ());
1968 if (context_getFlag (FLG_KEEP))
1970 check (fputs ("Temporary files kept:\n", g_messagestream) != EOF);
1971 fileTable_printTemps (context_fileTable ());
1976 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1980 llbug (message ("Files unclosed: %d", nfiles));
1983 fileTable_cleanup (context_fileTable ());
1990 ** cleans up temp files (if necessary) and exits
1996 DPRINTF (("llexit: %d", status));
1999 if (status == LLFAILURE)
2007 if (status != LLFAILURE)
2009 context_destroyMod ();
2010 exprNode_destroyMod ();
2013 uentry_destroyMod ();
2014 typeIdSet_destroyMod ();
2017 dmalloc_shutdown ();
2021 exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
2024 bool readOptionsFile (cstring fname, cstringSList *passThroughArgs, bool report)
2028 if (fileTable_exists (context_fileTable (), fname))
2034 message ("Multiple attempts to read options file: %s", fname),
2040 FILE *innerf = fileTable_openReadFile (context_fileTable (), fname);
2044 fileloc fc = g_currentloc;
2045 g_currentloc = fileloc_createRc (fname);
2047 displayScan (message ("< reading options from %q >",
2048 fileloc_outputFilename (g_currentloc)));
2050 loadrc (innerf, passThroughArgs);
2051 fileloc_reallyFree (g_currentloc);
2061 message ("Cannot open options file: %s", fname),
2071 ** This shouldn't be necessary, but Apple Darwin can't handle '"''s.
2075 loadrc (/*:open:*/ FILE *rcfile, cstringSList *passThroughArgs)
2076 /*@modifies rcfile@*/
2077 /*@ensures closed rcfile@*/
2079 char *s = mstring_create (MAX_LINE_LENGTH);
2082 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2086 while (reader_readLine (rcfile, s, MAX_LINE_LENGTH) != NULL)
2093 DPRINTF (("Line: %s", s));
2094 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2096 while (*s == ' ' || *s == '\t')
2104 bool escaped = FALSE;
2105 bool quoted = FALSE;
2108 DPRINTF (("Process: %s", s));
2109 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2110 /* comment characters */
2111 if (c == '#' || c == ';' || c == '\n')
2117 if (c == '-' || c == '+')
2124 voptgenerror (FLG_BADFLAG,
2125 message ("Bad flag syntax (+ or - expected, "
2126 "+ is assumed): %s",
2127 cstring_fromChars (s)),
2138 while ((c = *s) != '\0')
2139 { /* remember to handle spaces and quotes in -D and -U ... */
2165 if (c == ' ' || c == '\t' || c == '\n')
2167 /*@innerbreak@*/ break;
2175 DPRINTF (("Nulling: %c", *s));
2178 if (mstring_isEmpty (thisflag))
2180 llfatalerror (message ("Missing flag: %s",
2181 cstring_fromChars (os)));
2184 DPRINTF (("Flag: %s", thisflag));
2186 opt = flags_identifyFlag (cstring_fromChars (thisflag));
2188 if (flagcode_isSkip (opt))
2192 else if (flagcode_isInvalid (opt))
2194 DPRINTF (("Invalid: %s", thisflag));
2196 if (flags_isModeName (cstring_fromChars (thisflag)))
2198 context_setMode (cstring_fromChars (thisflag));
2202 voptgenerror (FLG_BADFLAG,
2203 message ("Unrecognized option: %s",
2204 cstring_fromChars (thisflag)),
2210 context_userSetFlag (opt, set);
2212 if (flagcode_hasArgument (opt))
2214 if (opt == FLG_HELP)
2217 voptgenerror (FLG_BADFLAG,
2218 message ("Cannot use help in rc files"),
2221 else if (flagcode_isPassThrough (opt)) /* -D or -U */
2223 cstring arg = cstring_fromCharsNew (thisflag);
2224 cstring_markOwned (arg);
2225 *passThroughArgs = cstringSList_add (*passThroughArgs, arg);
2226 DPRINTF (("Pass through: %s",
2227 cstringSList_unparse (*passThroughArgs)));
2229 else if (opt == FLG_INCLUDEPATH
2230 || opt == FLG_SPECPATH)
2235 ** Either -I<dir> or -I <dir>
2238 if (cstring_length (thisflag) > 1)
2240 dir = cstring_suffix (cstring_fromChars (thisflag), 1); /* skip over I/S */
2244 BADBRANCH; /*@!!!!@*/
2249 case FLG_INCLUDEPATH:
2250 cppAddIncludeDir (dir);
2251 /*@switchbreak@*/ break;
2254 g_localSpecPath = cstring_toCharsSafe
2255 (message ("%s:%s", cstring_fromChars (g_localSpecPath), dir));
2257 /*@switchbreak@*/ break;
2261 else if (flagcode_hasString (opt)
2262 || flagcode_hasNumber (opt)
2263 || flagcode_hasChar (opt)
2264 || opt == FLG_INIT || opt == FLG_OPTF)
2266 cstring extra = cstring_undefined;
2271 rest = mstring_copy (s);
2272 DPRINTF (("Here: rest = %s", rest));
2276 while ((rchar = *rest) != '\0'
2277 && (isspace ((int) rchar)))
2283 DPRINTF (("Yo: %s", rest));
2285 while ((rchar = *rest) != '\0'
2286 && !isspace ((int) rchar))
2288 extra = cstring_appendChar (extra, rchar);
2293 DPRINTF (("Yo: %s", extra));
2296 if (cstring_isUndefined (extra))
2302 ("Flag %s must be followed by an argument",
2303 flagcode_unparse (opt)),
2310 DPRINTF (("Here we are: %s", extra));
2312 if (flagcode_hasNumber (opt) || flagcode_hasChar (opt))
2314 DPRINTF (("Set value flag: %s", extra));
2315 setValueFlag (opt, extra);
2317 else if (opt == FLG_OPTF)
2319 (void) readOptionsFile (extra, passThroughArgs, TRUE);
2321 else if (opt == FLG_INIT)
2324 llassert (inputStream_isUndefined (initFile));
2326 initFile = inputStream_create
2327 (cstring_copy (extra),
2328 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
2332 else if (flagcode_hasString (opt))
2334 DPRINTF (("Here: %s", extra));
2337 ** If it has "'s, we need to remove them.
2340 if (cstring_firstChar (extra) == '\"')
2342 if (cstring_lastChar (extra) == '\"')
2344 cstring unquoted = cstring_copyLength
2345 (cstring_toCharsSafe (cstring_suffix (extra, 1)),
2346 cstring_length (extra) - 2);
2348 DPRINTF (("string flag: %s -> %s", extra, unquoted));
2349 setStringFlag (opt, unquoted);
2350 cstring_free (extra);
2356 message ("Unmatched \" in option string: %s",
2359 setStringFlag (opt, extra);
2364 DPRINTF (("No quotes: %s", extra));
2365 setStringFlag (opt, extra);
2368 extra = cstring_undefined;
2376 cstring_free (extra);
2386 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2387 while ((c == ' ') || (c == '\t'))
2393 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2397 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2399 check (fileTable_closeFile (context_fileTable (), rcfile));
2402 static fileIdList preprocessFiles (fileIdList fl, bool xhfiles)
2403 /*@modifies fileSystem@*/
2405 bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
2406 int skip = (fileIdList_size (fl) / 5);
2407 int filesprocessed = 0;
2408 fileIdList dfiles = fileIdList_create ();
2410 fileloc_free (g_currentloc);
2411 g_currentloc = fileloc_createBuiltin ();
2413 fileIdList_elements (fl, fid)
2415 cstring ppfname = fileTable_fileName (fid);
2417 if (!(osd_fileIsReadable (ppfname)))
2419 lldiagmsg (message ("Cannot open file: %q", osd_outputPath (ppfname)));
2420 ppfname = cstring_undefined;
2423 if (cstring_isDefined (ppfname))
2425 fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
2429 llassert (fileTable_isXHFile (context_fileTable (), dfile));
2432 llassert (cstring_isNonEmpty (ppfname));
2436 if ((filesprocessed % skip) == 0)
2438 if (filesprocessed == 0) {
2439 fprintf (g_messagestream, " ");
2442 fprintf (g_messagestream, ".");
2445 (void) fflush (g_messagestream);
2450 DPRINTF (("outfile: %s", fileTable_fileName (dfile)));
2452 if (cppProcess (ppfname, fileTable_fileName (dfile)) != 0)
2454 llfatalerror (message ("Preprocessing error for file: %s",
2455 fileTable_rootFileName (fid)));
2458 fileIdList_add (dfiles, dfile);
2460 } end_fileIdList_elements;
2465 /* This should be in an lclUtils.c file... */
2467 char *specFullName (char *specfile, /*@out@*/ char **inpath)
2469 /* extract the path and the specname associated with the given file */
2470 char *specname = (char *) dmalloc (sizeof (*specname)
2471 * (strlen (specfile) + 9));
2472 char *ospecname = specname;
2473 char *path = (char *) dmalloc (sizeof (*path) * (strlen (specfile)));
2477 /* initialized path to empty string or may have accidental garbage */
2480 /*@-mayaliasunique@*/
2481 strcpy (specname, specfile);
2482 /*@=mayaliasunique@*/
2484 /* trim off pathnames in specfile */
2485 size = strlen (specname);
2487 for (i = size_toInt (size) - 1; i >= 0; i--)
2489 if (specname[i] == CONNECTCHAR)
2491 /* strcpy (specname, (char *)specname+i+1); */
2492 for (j = 0; j <= i; j++) /* include '/' */
2494 path[j] = specname[j];
2504 ** also remove .lcl file extension, assume it's the last extension
2508 size = strlen (specname);
2510 for (i = size_toInt (size) - 1; i >= 0; i--)
2512 if (specname[i] == '.')
2522 ** If specname no longer points to the original char,
2523 ** we need to allocate a new pointer and copy the string.
2526 if (specname != ospecname) {
2527 char *rspecname = (char *) dmalloc (sizeof (*rspecname) * (strlen (specname) + 1));
2528 strcpy (rspecname, specname); /* evs 2000-05-16: Bug: was ospecname! */
2537 void warnSysFiles(fileIdList files)
2539 fileIdList_elements (files, file)
2542 if (fileTable_isSystemFile (context_fileTable (), file) )
2544 if (!context_getFlag( FLG_SYSTEMDIRERRORS ) )
2546 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);
2550 end_fileIdList_elements;