2 ** LCLint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2000 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 lclint: lclint-request@cs.virginia.edu
21 ** To report a bug: lclint-bug@cs.virginia.edu
22 ** For more information: http://lclint.cs.virginia.edu
27 ** Main module for LCLint checker
33 ** Ensure that WIN32 and _WIN32 are both defined or both undefined.
38 # error "Inconsistent definitions."
42 # error "Inconsistent definitions."
51 # include "lclintMacros.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"
74 # include "fileIdList.h"
76 # include "cgrammar.h"
82 extern /*@external@*/ int yydebug;
84 static void printMail (void);
85 static void printMaintainer (void);
86 static void printReferences (void);
87 static void printFlags (void);
88 static void printAnnotations (void);
89 static void printParseErrors (void);
90 static void printComments (void);
91 static void describePrefixCodes (void);
92 static void cleanupFiles (void);
93 static void showHelp (void);
94 static void interrupt (int p_i);
95 static void loadrc (FILE *p_rcfile, cstringSList *p_passThroughArgs);
96 static void describeVars (void);
97 static bool specialFlagsHelp (char *p_next);
98 static bool hasShownHerald = FALSE;
100 static bool anylcl = FALSE;
101 static clock_t inittime;
103 static /*@only@*/ /*@null@*/ tsource *initFile = (tsource *) 0;
105 static fileIdList preprocessFiles (fileIdList)
106 /*@modifies fileSystem@*/ ;
111 void lslCleanup (void)
112 /*@globals killed g_symtab@*/
113 /*@modifies internalState, g_symtab@*/
116 ** Cleanup all the LCL/LSL.
119 static bool didCleanup = FALSE;
121 llassert (!didCleanup);
126 lsymbol_destroyMod ();
127 LCLSynTableCleanup ();
128 LCLTokenTableCleanup ();
129 LCLScanLineCleanup ();
132 /* clean up LSL parsing */
135 ltokenTableCleanup ();
139 symtable_free (g_symtab);
145 /*@globals undef g_symtab; @*/
146 /*@modifies g_symtab, internalState, fileSystem; @*/
149 ** Open init file provided by user, or use the default LCL init file
152 cstring larchpath = context_getLarchPath ();
153 tsource *LSLinitFile = (tsource *) 0;
157 if (initFile == (tsource *) 0)
159 initFile = tsource_create (INITFILENAME, LCLINIT_SUFFIX, FALSE);
161 if (!tsource_getPath (cstring_toCharsSafe (larchpath), initFile))
163 lldiagmsg (message ("Continuing without LCL init file: %s",
164 cstring_fromChars (tsource_fileName (initFile))));
168 if (!tsource_open (initFile))
170 lldiagmsg (message ("Continuing without LCL init file: %s",
171 cstring_fromChars (tsource_fileName (initFile))));
177 if (!tsource_open (initFile))
179 lldiagmsg (message ("Continuing without LCL init file: %s",
180 cstring_fromChars (tsource_fileName (initFile))));
184 /* Initialize checker */
192 LCLTokenTableInit ();
204 /* need this to initialize LCL checker */
205 llassert (initFile != NULL);
207 if (tsource_isOpen (initFile))
211 LCLScanReset (initFile);
212 LCLProcessInitFileInit ();
213 LCLProcessInitFileReset ();
216 LCLProcessInitFile ();
217 LCLProcessInitFileCleanup ();
220 check (tsource_close (initFile));
223 /* Initialize LSL init files, for parsing LSL signatures from LSL */
225 LSLinitFile = tsource_create ("lslinit.lsi", ".lsi", FALSE);
227 if (!tsource_getPath (cstring_toCharsSafe (larchpath), LSLinitFile))
229 lldiagmsg (message ("Continuing without LSL init file: %s",
230 cstring_fromChars (tsource_fileName (LSLinitFile))));
234 if (!tsource_open (LSLinitFile))
236 lldiagmsg (message ("Continuing without LSL init file: %s",
237 cstring_fromChars (tsource_fileName (LSLinitFile))));
253 if (tsource_isOpen (LSLinitFile))
256 LSLScanReset (LSLinitFile);
257 LSLProcessInitFileInit ();
259 LSLProcessInitFile ();
261 check (tsource_close (LSLinitFile));
264 tsource_free (LSLinitFile);
269 (cstring_makeLiteral ("LSL init file error. Attempting to continue."));
273 g_symtab = symtable_new ();
276 ** sort_init must come after symtab has been initialized
285 ** Equivalent to importing old spec_csupport.lcl
286 ** define immutable LCL type "bool" and bool constants TRUE and FALSE
287 ** and initialized them to be equal to LSL's "true" and "false".
289 ** Reads in CTrait.syms (derived from CTrait.lsl) on LARCH_PATH.
293 LCLReportEolTokens (FALSE);
297 lslProcess (fileIdList lclfiles)
298 /*@globals undef g_currentSpec, undef g_currentSpecName, g_currentloc,
299 undef killed g_symtab; @*/
300 /*@modifies g_currentSpec, g_currentSpecName, g_currentloc, internalState, fileSystem; @*/
303 bool parser_status = FALSE;
304 bool overallStatus = FALSE;
308 context_resetSpecLines ();
310 fileIdList_elements (lclfiles, fid)
312 char *actualName = (char *) dmalloc (sizeof (*actualName));
313 char *oactualName = actualName;
314 char *fname = cstring_toCharsSafe (fileName (fid));
316 if (osd_getPath (g_localSpecPath, fname, &actualName) == OSD_FILENOTFOUND)
318 if (mstring_equal (g_localSpecPath, "."))
320 lldiagmsg (message ("Spec file not found: %s",
321 cstring_fromChars (fname)));
325 lldiagmsg (message ("Spec file not found: %s (on %s)",
326 cstring_fromChars (fname),
327 cstring_fromChars (g_localSpecPath)));
334 while (*actualName == '.' && *(actualName + 1) == CONNECTCHAR)
339 specFile = tsource_create (actualName, LCL_SUFFIX, TRUE);
340 llassert (specFile != (tsource *) 0);
342 g_currentSpec = cstring_fromChars (mstring_copy (actualName));
344 g_currentSpecName = specFullName
345 (cstring_toCharsSafe (g_currentSpec),
350 if (context_getFlag (FLG_SHOWSCAN))
352 lldiagmsg (message ("< reading spec %s >", g_currentSpec));
355 /* Open source file */
357 if (!tsource_open (specFile))
359 lldiagmsg (message ("Cannot open file: %s",
360 cstring_fromChars (tsource_fileName (specFile))));
361 tsource_free (specFile);
365 scopeInfo dummy_scope = (scopeInfo) dmalloc (sizeof (*dummy_scope));
366 dummy_scope->kind = SPE_INVALID;
369 LCLScanReset (specFile);
372 ** Minor hacks to allow more than one LCL file to
373 ** be scanned, while keeping initializations
376 symtable_enterScope (g_symtab, dummy_scope);
377 resetImports (cstring_fromChars (g_currentSpecName));
378 context_enterLCLfile ();
379 (void) lclHadNewError ();
381 parser_status = (ylparse () != 0);
382 context_exitLCLfile ();
384 overallStatus = parser_status || lclHadNewError ();
386 if (context_getFlag (FLG_DOLCS))
390 outputLCSFile (path, "%%FAILED Output from ",
395 outputLCSFile (path, "%%PASSED Output from ",
400 (void) tsource_close (specFile);
401 tsource_free (specFile);
403 symtable_exitScope (g_symtab);
408 } end_fileIdList_elements;
410 /* Can cleanup lsl stuff right away */
414 g_currentSpec = cstring_undefined;
415 g_currentSpecName = NULL;
419 static void handlePassThroughFlag (char *arg)
422 char *quotechar = strchr (curarg, '\"');
426 while (quotechar != NULL)
428 if (*(quotechar - 1) == '\\')
430 char *tp = quotechar - 2;
441 curarg = quotechar + 1;
442 quotechar = strchr (curarg, '\"');
448 offset = (quotechar - arg) + 2;
452 arg = cstring_toCharsSafe
453 (message ("%s\"\'%s",
454 cstring_fromChars (arg),
455 cstring_fromChars (quotechar + 1)));
460 arg = cstring_toCharsSafe
461 (message ("%s\'\"%s",
462 cstring_fromChars (arg),
463 cstring_fromChars (quotechar + 1)));
467 curarg = arg + offset;
468 quotechar = strchr (curarg, '\"');
474 llerror (FLG_BADFLAG,
475 message ("Unclosed quote in flag: %s",
476 cstring_fromChars (arg)));
484 ** If the value is surrounded by single quotes ('), remove
485 ** them. This is an artifact of UNIX command line?
488 def = osd_fixDefine (arg + 1);
489 DPRINTF (("Do define: %s", def));
491 DPRINTF (("After define"));
493 } else if (arg[0] == 'U') {
494 cppDoUndefine (cstring_fromChars (arg + 1));
501 void showHerald (void)
503 if (hasShownHerald || context_getFlag (FLG_QUIET)) return;
507 fprintf (g_msgstream, "%s\n\n", LCL_VERSION);
508 hasShownHerald = TRUE;
513 static void addFile (fileIdList files, /*@only@*/ cstring s)
515 if (fileTable_exists (context_fileTable (), s))
518 lldiagmsg (message ("File listed multiple times: %s", s));
523 fileIdList_add (files, fileTable_addFileOnly (context_fileTable (), s));
528 ** Disable MSVC++ warning about return value. Methinks humbly lclint control
529 ** comments are a mite more legible.
533 # pragma warning (disable:4035)
536 int main (int argc, char *argv[])
538 /*@globals killed undef g_currentloc,
542 /*@modifies g_currentloc, fileSystem,
546 /*@globals killed undef g_currentloc,
547 killed undef initFile,
548 killed g_localSpecPath,
549 killed undef g_currentSpec,
550 killed undef g_currentSpecName,
554 /*@modifies g_currentloc, initFile,
555 g_localSpecPath, g_currentSpec, g_currentSpecName, fileSystem,
560 bool first_time = TRUE;
561 bool showhelp = FALSE;
564 tsource *sourceFile = (tsource *) 0;
566 fileIdList dercfiles;
567 cstringSList fl = cstringSList_undefined;
568 cstringSList passThroughArgs = cstringSList_undefined;
571 clock_t before, lcltime, libtime, pptime, cptime, rstime;
574 g_msgstream = stdout;
576 (void) signal (SIGINT, interrupt);
577 (void) signal (SIGSEGV, interrupt);
579 cfiles = fileIdList_create ();
580 lclfiles = fileIdList_create ();
583 typeIdSet_initMod ();
584 cppReader_initMod ();
588 g_currentloc = fileloc_createBuiltin ();
592 context_setInCommandLine ();
604 ** Add include directories from environment.
608 char *incval = mstring_copy (osd_getEnvironmentVariable (INCLUDE_VAR));
613 ** Each directory on the include path is a system include directory.
616 DPRINTF (("include: %s", incval));
617 context_setString (FLG_SYSTEMDIRS, cstring_fromCharsNew (incval));
619 while (incval != NULL)
621 char *nextsep = strchr (incval, SEPCHAR);
627 dir = cstring_fromCharsNew (incval);
629 if (cstring_length (dir) == 0
630 || !isalpha ((int) cstring_firstChar (dir)))
633 ** win32 environment values can have special values,
639 DPRINTF (("Add include: %s", dir));
640 cppAddIncludeDir (dir);
644 incval = nextsep + 1;
656 ** check RCFILE for default flags
660 cstring home = cstring_fromChars (osd_getHomeDir ());
663 bool defaultf = TRUE;
666 for (i = 1; i < argc; i++)
671 if (*thisarg == '-' || *thisarg == '+')
675 if (mstring_equal (thisarg, "nof"))
679 else if (mstring_equal (thisarg, "f"))
685 rcfile = fopen (fname, "r");
689 fileloc oloc = g_currentloc;
691 g_currentloc = fileloc_createRc (cstring_fromChars (fname));
692 loadrc (rcfile, &passThroughArgs);
693 fileloc_reallyFree (g_currentloc);
699 lldiagmsg (message ("Options file not found: %s",
700 cstring_fromChars (fname)));
705 (cstring_makeLiteral ("Flag f to select options file "
706 "requires an argument"));
710 ; /* wait to process later */
717 if (!cstring_isEmpty (home)) {
718 fname = cstring_toCharsSafe (message ("%s%h%s", home, CONNECTCHAR,
719 cstring_fromChars (RCFILE)));
720 mstring_markFree (fname);
726 if (!nof && defaultf)
728 if (!mstring_isEmpty (fname)) {
729 rcfile = fopen (fname, "r");
733 fileloc oloc = g_currentloc;
735 g_currentloc = fileloc_createRc (cstring_fromChars (fname));
736 loadrc (rcfile, &passThroughArgs);
737 fileloc_reallyFree (g_currentloc);
742 # if defined(MSDOS) || defined(OS2)
743 fname = cstring_toCharsSafe (message ("%s",
744 cstring_fromChars (RCFILE)));
746 fname = cstring_toCharsSafe (message ("./%s",
747 cstring_fromChars (RCFILE)));
750 rcfile = fopen (fname, "r");
754 fileloc oloc = g_currentloc;
756 g_currentloc = fileloc_createRc (cstring_fromChars (fname));
757 loadrc (rcfile, &passThroughArgs);
758 fileloc_reallyFree (g_currentloc);
768 for (i = 1; i < argc; i++)
784 if (*thisarg == '-' || *thisarg == '+')
786 thisarg++; /* skip '-' */
788 if (mstring_equal (thisarg, "modes"))
790 llmsg (describeModes ());
792 else if (mstring_equal (thisarg, "vars")
793 || mstring_equal (thisarg, "env"))
797 else if (mstring_equal (thisarg, "annotations"))
801 else if (mstring_equal (thisarg, "parseerrors"))
805 else if (mstring_equal (thisarg, "comments"))
809 else if (mstring_equal (thisarg, "prefixcodes"))
811 describePrefixCodes ();
813 else if (mstring_equal (thisarg, "references")
814 || mstring_equal (thisarg, "refs"))
818 else if (mstring_equal (thisarg, "mail"))
822 else if (mstring_equal (thisarg, "maintainer")
823 || mstring_equal (thisarg, "version"))
827 else if (mstring_equal (thisarg, "flags"))
831 char *next = argv[i + 1];
833 if (specialFlagsHelp (next))
839 flagkind k = identifyCategory (cstring_fromChars (next));
855 cstring s = describeFlag (cstring_fromChars (thisarg));
857 if (cstring_isDefined (s))
865 if (*thisarg == '-' || *thisarg == '+')
867 bool set = (*thisarg == '+');
870 thisarg++; /* skip '-' */
871 flagname = cstring_fromChars (thisarg);
873 opt = identifyFlag (flagname);
875 if (flagcode_isSkip (opt))
879 else if (flagcode_isInvalid (opt))
881 if (isMode (flagname))
883 context_setMode (flagname);
887 llgloberror (message ("Unrecognized option: %s",
888 cstring_fromChars (thisarg)));
893 context_userSetFlag (opt, set);
895 if (flagcode_hasArgument (opt))
901 else if (flagcode_isPassThrough (opt)) /* -D or -U */
903 passThroughArgs = cstringSList_add
904 (passThroughArgs, cstring_fromChars (thisarg));
906 else if (flagcode_hasValue (opt))
910 setValueFlag (opt, cstring_fromChars (argv[i]));
916 ("Flag %s must be followed by a number",
917 flagcode_unparse (opt)));
920 else if (opt == FLG_INCLUDEPATH || opt == FLG_SPECPATH)
922 cstring dir = cstring_suffix (cstring_fromChars (thisarg), 1); /* skip over I */
926 case FLG_INCLUDEPATH:
927 cppAddIncludeDir (dir);
928 /*@switchbreak@*/ break;
931 g_localSpecPath = cstring_toCharsSafe
933 cstring_fromChars (g_localSpecPath),
937 /*@switchbreak@*/ break;
941 else if (flagcode_hasString (opt)
942 || opt == FLG_INIT || opt == FLG_OPTF)
946 cstring arg = cstring_fromChars (argv[i]);
950 ; /* -f already processed */
952 else if (opt == FLG_INIT)
955 initFile = tsource_create
956 (cstring_toCharsSafe (arg),
957 LCLINIT_SUFFIX, FALSE);
963 setStringFlag (opt, arg);
970 ("Flag %s must be followed by a string",
971 flagcode_unparse (opt)));
981 else /* its a filename */
983 fl = cstringSList_add (fl, cstring_fromChars (thisarg));
991 ** create lists of C and LCL files
994 cstringSList_elements (fl, current)
996 char *fname = cstring_toCharsSafe (current);
997 char *ext = strrchr (fname, '.');
1001 /* no extension --- both C and LCL with default extensions */
1003 addFile (cfiles, message ("%s.c", cstring_fromChars (fname)));
1004 addFile (lclfiles, message ("%s.lcl", cstring_fromChars (fname)));
1006 else if (isCext (ext))
1008 addFile (cfiles, cstring_fromCharsNew (fname));
1012 if (!mstring_equal (ext, ".lcl"))
1014 lldiagmsg (message ("Unrecognized file extension: %s (assuming lcl)",
1015 cstring_fromChars (ext)));
1018 addFile (lclfiles, cstring_fromCharsNew (fname));
1020 } end_cstringSList_elements;
1032 fprintf (g_msgstream, "\n");
1034 fileIdList_free (cfiles);
1035 fileIdList_free (lclfiles);
1044 inittime = clock ();
1046 context_resetErrors ();
1047 context_clearInCommandLine ();
1049 anylcl = !fileIdList_isEmpty (lclfiles);
1051 if (context_doMerge ())
1053 cstring m = context_getMerge ();
1055 if (context_getFlag (FLG_SHOWSCAN))
1057 fprintf (g_msgstream, "< loading %s ", cstring_toCharsSafe (m));
1062 if (context_getFlag (FLG_SHOWSCAN))
1064 fprintf (g_msgstream, " >\n");
1067 if (!usymtab_existsType (context_getBoolName ()))
1069 usymtab_initBool ();
1074 if (!context_getFlag (FLG_NOLIB) && loadStandardState ())
1083 /* setup bool type and constants */
1084 usymtab_initBool ();
1087 fileloc_free (g_currentloc);
1088 g_currentloc = fileloc_createBuiltin ();
1095 llfatalerror (cstring_makeLiteral ("This version of LCLint does not handle LCL files."));
1097 lslProcess (lclfiles);
1104 ** call the pre-preprocessor and /lib/cpp to generate appropriate
1109 context_setInCommandLine ();
1111 cppReader_initialize ();
1113 DPRINTF (("Pass through: %s", cstringSList_unparse (passThroughArgs)));
1115 cstringSList_elements (passThroughArgs, thisarg) {
1116 handlePassThroughFlag (cstring_toCharsSafe (thisarg));
1117 } end_cstringSList_elements;
1119 cstringSList_free (passThroughArgs);
1123 cppReader_saveDefinitions ();
1125 context_clearInCommandLine ();
1127 if (!context_getFlag (FLG_NOPP))
1131 if (context_getFlag (FLG_SHOWSCAN))
1133 fprintf (stderr, "< preprocessing");
1138 context_setPreprocessing ();
1139 dercfiles = preprocessFiles (cfiles);
1140 context_clearPreprocessing ();
1142 fileIdList_free (cfiles);
1144 if (context_getFlag (FLG_SHOWSCAN))
1146 fprintf (stderr, " >\n");
1159 ** now, check all the corresponding C files
1161 ** (for now these are just <file>.c, but after pre-processing
1162 ** will be <tmpprefix>.<file>.c)
1167 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1171 llbug (message ("Files unclosed: %d", nfiles));
1176 exprNode_initMod ();
1178 fileIdList_elements (dercfiles, fid)
1180 sourceFile = tsource_create (cstring_toCharsSafe (fileName (fid)),
1182 context_setFileId (fid);
1184 /* Open source file */
1186 if (sourceFile == (tsource *) 0 || (!tsource_open (sourceFile)))
1188 /* previously, this was ignored ?! */
1189 llbug (message ("Could not open temp file: %s", fileName (fid)));
1193 yyin = sourceFile->file; /*< shared <- only */
1195 llassert (yyin != NULL);
1197 if (context_getFlag (FLG_SHOWSCAN))
1199 lldiagmsg (message ("< checking %s >", rootFileName (fid)));
1203 ** Every time, except the first time, through the loop,
1204 ** need to call yyrestart to clean up the parse buffer.
1209 (void) yyrestart (yyin);
1216 context_enterFile ();
1218 context_exitFile ();
1220 (void) tsource_close (sourceFile);
1223 } end_fileIdList_elements;
1227 /* process any leftover macros */
1229 context_processAllMacros ();
1231 /* check everything that was specified was defined */
1233 /* don't check if no c files were processed ?
1234 ** is this correct behaviour?
1237 if (context_getFlag (FLG_SHOWSCAN))
1239 lldiagmsg (cstring_makeLiteral ("< global checks >"));
1244 if (context_getLinesProcessed () > 0)
1246 usymtab_allDefined ();
1249 if (context_maybeSet (FLG_TOPUNUSED))
1251 uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main"));
1253 if (uentry_isValid (ue))
1255 uentry_setUsed (ue, fileloc_observeBuiltin ());
1261 if (context_maybeSet (FLG_EXPORTLOCAL))
1263 usymtab_exportLocal ();
1267 if (context_maybeSet (FLG_EXPORTHEADER))
1269 usymtab_exportHeader ();
1272 if (context_getFlag (FLG_SHOWUSES))
1274 usymtab_displayAllUses ();
1277 context_checkSuppressCounts ();
1279 if (context_doDump ())
1281 cstring dump = context_getDump ();
1292 if (context_getFlag (FLG_SHOWSUMMARY))
1299 bool isQuiet = context_getFlag (FLG_QUIET);
1300 cstring specErrors = cstring_undefined;
1302 int nspecErrors = lclNumberErrors ();
1307 if (context_neednl ())
1308 fprintf (g_msgstream, "\n");
1311 if (nspecErrors > 0)
1313 if (nspecErrors == context_getLCLExpect ())
1316 message ("%d spec error%p found, as expected\n ",
1321 if (context_getLCLExpect () > 0)
1324 message ("%d spec error%p found, expected %d\n ",
1326 (int) context_getLCLExpect ());
1330 specErrors = message ("%d spec error%p found\n ",
1338 if (context_getLCLExpect () > 0)
1340 specErrors = message ("No spec errors found, expected %d\n ",
1341 (int) context_getLCLExpect ());
1347 if (context_anyErrors ())
1349 if (context_numErrors () == context_getExpect ())
1352 llmsg (message ("Finished LCLint checking --- "
1353 "%s%d code error%p found, as expected",
1354 specErrors, context_numErrors ()));
1359 if (context_getExpect () > 0)
1363 ("Finished LCLint checking --- "
1364 "%s%d code error%p found, expected %d",
1365 specErrors, context_numErrors (),
1366 (int) context_getExpect ()));
1375 llmsg (message ("Finished LCLint checking --- "
1376 "%s%d code error%p found",
1377 specErrors, context_numErrors ()));
1386 if (context_getExpect () > 0)
1390 ("Finished LCLint checking --- "
1391 "%sno code errors found, expected %d",
1393 (int) context_getExpect ()));
1400 if (context_getLinesProcessed () > 0)
1403 llmsg (message ("Finished LCLint checking --- %sno code errors found",
1410 llmsg (message ("Finished LCLint checking --- %sno code processed",
1417 cstring_free (specErrors);
1420 if (context_getFlag (FLG_STATS))
1422 clock_t ttime = clock () - before;
1423 int specLines = context_getSpecLinesProcessed ();
1429 fprintf (g_msgstream, "%d spec, ", specLines);
1432 # ifndef CLOCKS_PER_SEC
1433 fprintf (g_msgstream, "%d source lines in %ld time steps (steps/sec unknown)\n",
1434 context_getLinesProcessed (),
1437 fprintf (g_msgstream, "%d source lines in %.2f s.\n",
1438 context_getLinesProcessed (),
1439 (double) ttime / CLOCKS_PER_SEC);
1447 if (context_getFlag (FLG_TIMEDIST))
1449 clock_t ttime = clock () - before;
1453 char *msg = (char *) dmalloc (256 * sizeof (*msg));
1458 "Time distribution (percent): initialize %.2f / lcl %.2f / "
1459 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1460 (100.0 * (double) (libtime - before) / ttime),
1461 (100.0 * (double) (lcltime - libtime) / ttime),
1462 (100.0 * (double) (pptime - lcltime) / ttime),
1463 (100.0 * (double) (cptime - pptime) / ttime),
1464 (100.0 * (double) (rstime - cptime) / ttime));
1469 "Time distribution (percent): initialize %.2f / "
1470 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1471 (100.0 * (double) (libtime - before) / ttime),
1472 (100.0 * (double) (pptime - libtime) / ttime),
1473 (100.0 * (double) (cptime - pptime) / ttime),
1474 (100.0 * (double) (rstime - cptime) / ttime));
1477 llgenindentmsgnoloc (cstring_fromCharsO (msg));
1481 llexit (expsuccess ? LLSUCCESS : LLFAILURE);
1485 ** Reenable return value warnings.
1488 #pragma warning (default:4035)
1495 llmsglit ("Source files are .c, .h and .lcl files. If there is no suffix,");
1496 llmsglit (" LCLint will look for <file>.c and <file>.lcl.");
1498 llmsglit ("Use lclint -help <topic or flag name> for more information");
1500 llmsglit ("Topics:");
1502 llmsglit (" annotations (describes source-code annotations)");
1503 llmsglit (" comments (describes control comments)");
1504 llmsglit (" flags (describes flag categories)");
1505 llmsglit (" flags <category> (describes flags in category)");
1506 llmsglit (" flags all (short description of all flags)");
1507 llmsglit (" flags alpha (list all flags alphabetically)");
1508 llmsglit (" flags full (full description of all flags)");
1509 llmsglit (" mail (information on mailing lists)");
1510 llmsglit (" modes (show mode settings)");
1511 llmsglit (" parseerrors (help on handling parser errors)");
1512 llmsglit (" prefixcodes (character codes in namespace prefixes)");
1513 llmsglit (" references (sources for more information)");
1514 llmsglit (" vars (environment variables)");
1515 llmsglit (" version (information on compilation, maintainer)");
1520 specialFlagsHelp (char *next)
1522 if ((next != NULL) && (*next != '-') && (*next != '+'))
1524 if (mstring_equal (next, "alpha"))
1529 else if (mstring_equal (next, "all"))
1531 printAllFlags (TRUE, FALSE);
1534 else if (mstring_equal (next, "categories")
1535 || mstring_equal (next, "cats"))
1537 listAllCategories ();
1540 else if (mstring_equal (next, "full"))
1542 printAllFlags (FALSE, TRUE);
1557 printParseErrors (void)
1559 llmsglit ("Parse Errors");
1560 llmsglit ("------------");
1562 llmsglit ("LCLint will sometimes encounter a parse error for code that "
1563 "can be parsed with a local compiler. There are a few likely "
1564 "causes for this and a number of techniques that can be used "
1565 "to work around the problem.");
1567 llmsglit ("Compiler extensions --- compilers sometimes extend the C "
1568 "language with compiler-specific keywords and syntax. While "
1569 "it is not advisible to use these, oftentimes one has no choice "
1570 "when the system header files use compiler extensions. ");
1572 llmsglit ("LCLint supports some of the GNU (gcc) compiler extensions, "
1573 "if the +gnuextensions flag is set. You may be able to workaround "
1574 "other compiler extensions by using a pre-processor define. "
1575 "Alternately, you can surround the unparseable code with");
1577 llmsglit (" # ifndef __LCLINT__");
1579 llmsglit (" # endif");
1581 llmsglit ("Missing type definitions --- an undefined type name will usually "
1582 "lead to a parse error. This ofter occurs when a standard header "
1583 "file defines some type that is not part of the standard library. ");
1584 llmsglit ("By default, LCLint does not process the local files corresponding "
1585 "to standard library headers, but uses a library specification "
1586 "instead so dependencies on local system headers can be detected. "
1587 "If another system header file that does not correspond to a "
1588 "standard library header uses one of these superfluous types, "
1589 "a parse error will result.");
1591 llmsglit ("If the parse error is inside a posix standard header file, the "
1592 "first thing to try is +posixlib. This make LCLint use "
1593 "the posix library specification instead of reading the posix "
1596 llmsglit ("Otherwise, you may need to either manually define the problematic "
1597 "type (e.g., add -Dmlink_t=int to your .lclintrc file) or force "
1598 "lclint to process the header file that defines it. This is done "
1599 "by setting -skipansiheaders or -skipposixheaders before "
1600 "the file that defines the type is #include'd.");
1601 llmsglit ("(See lclint -help "
1602 "skipansiheaders and lclint -help skipposixheaders for a list of "
1603 "standard headers.) For example, if <sys/local.h> uses a type "
1604 "defined by posix header <sys/types.h> but not defined by the "
1605 "posix library, we might do: ");
1607 llmsglit (" /*@-skipposixheaders@*/");
1608 llmsglit (" # include <sys/types.h>");
1609 llmsglit (" /*@=skipposixheaders@*/");
1610 llmsglit (" # include <sys/local.h>");
1612 llmsglit ("to force LCLint to process <sys/types.h>.");
1614 llmsglit ("At last resort, +trytorecover can be used to make LCLint attempt "
1615 "to continue after a parse error. This is usually not successful "
1616 "and the author does not consider assertion failures when +trytorecover "
1617 "is used to be bugs.");
1621 printAnnotations (void)
1623 llmsglit ("Annotations");
1624 llmsglit ("-----------");
1626 llmsglit ("Annotations are stylized comments that document certain "
1627 "assumptions about functions, variables, parameters, and types. ");
1629 llmsglit ("They may be used to indicate where the representation of a "
1630 "user-defined type is hidden, to limit where a global variable may "
1631 "be used or modified, to constrain what a function implementation "
1632 "may do to its parameters, and to express checked assumptions about "
1633 "variables, types, structure fields, function parameters, and "
1634 "function results.");
1636 llmsglit ("Annotations are introduced by \"/*@\". The role of the @ may be "
1637 "played by any printable character, selected using -commentchar <char>.");
1639 llmsglit ("Consult the User's Guide for descriptions of checking associated with each annotation.");
1641 llmsglit ("Globals: (in function declarations)");
1642 llmsglit (" /*@globals <globitem>,+ @*/");
1643 llmsglit (" globitem is an identifier, internalState or fileSystem");
1645 llmsglit ("Modifies: (in function declarations)");
1646 llmsglit (" /*@modifies <moditem>,+ @*/");
1647 llmsglit (" moditem is an lvalue");
1648 llmsglit (" /*@modifies nothing @*/");
1649 llmsglit (" /*@*/ (Abbreviation for no globals and modifies nothing.)");
1651 llmsglit ("Iterators:");
1652 llmsglit (" /*@iter <identifier> (<parameter-type-list>) @*/ - declare an iterator");
1654 llmsglit ("Constants:");
1655 llmsglit (" /*@constant <declaration> @*/ - declares a constant");
1657 llmsglit ("Alternate Types:");
1658 llmsglit (" /*@alt <basic-type>,+ @*/");
1659 llmsglit (" (e.g., int /*@alt char@*/ is a type matching either int or char)");
1661 llmsglit ("Declarator Annotations");
1663 llmsglit ("Type Definitions:");
1664 llmsglit (" /*@abstract@*/ - representation is hidden from clients");
1665 llmsglit (" /*@concrete@*/ - representation is visible to clients");
1666 llmsglit (" /*@immutable@*/ - instances of the type cannot change value");
1667 llmsglit (" /*@mutable@*/ - instances of the type can change value");
1668 llmsglit (" /*@refcounted@*/ - reference counted type");
1670 llmsglit ("Global Variables:");
1671 llmsglit (" /*@unchecked@*/ - weakest checking for global use");
1672 llmsglit (" /*@checkmod@*/ - check modification by not use of global");
1673 llmsglit (" /*@checked@*/ - check use and modification of global");
1674 llmsglit (" /*@checkedstrict@*/ - check use of global strictly");
1676 llmsglit ("Memory Management:");
1677 llmsglit (" /*@dependent@*/ - a reference to externally-owned storage");
1678 llmsglit (" /*@keep@*/ - a parameter that is kept by the called function");
1679 llmsglit (" /*@killref@*/ - a refcounted parameter, killed by the call");
1680 llmsglit (" /*@only@*/ - an unshared reference");
1681 llmsglit (" /*@owned@*/ - owner of storage that may be shared by /*@dependent@*/ references");
1682 llmsglit (" /*@shared@*/ - shared reference that is never deallocated");
1683 llmsglit (" /*@temp@*/ - temporary parameter");
1685 llmsglit ("Aliasing:");
1686 llmsglit (" /*@unique@*/ - may not be aliased by any other visible reference");
1687 llmsglit (" /*@returned@*/ - may be aliased by the return value");
1689 llmsglit ("Exposure:");
1690 llmsglit (" /*@observer@*/ - reference that cannot be modified");
1691 llmsglit (" /*@exposed@*/ - exposed reference to storage in another object");
1693 llmsglit ("Definition State:");
1694 llmsglit (" /*@out@*/ - storage reachable from reference need not be defined");
1695 llmsglit (" /*@in@*/ - all storage reachable from reference must be defined");
1696 llmsglit (" /*@partial@*/ - partially defined, may have undefined fields");
1697 llmsglit (" /*@reldef@*/ - relax definition checking");
1699 llmsglit ("Global State: (for globals lists, no /*@, since list is already in /*@\'s)");
1700 llmsglit (" undef - variable is undefined before the call");
1701 llmsglit (" killed - variable is undefined after the call");
1703 llmsglit ("Null State:");
1704 llmsglit (" /*@null@*/ - possibly null pointer");
1705 llmsglit (" /*@notnull@*/ - non-null pointer");
1706 llmsglit (" /*@relnull@*/ - relax null checking");
1708 llmsglit ("Null Predicates:");
1709 llmsglit (" /*@truenull@*/ - if result is TRUE, first parameter is NULL");
1710 llmsglit (" /*@falsenull@*/ - if result is TRUE, first parameter is not NULL");
1712 llmsglit ("Execution:");
1713 llmsglit (" /*@exits@*/ - function never returns");
1714 llmsglit (" /*@mayexit@*/ - function may or may not return");
1715 llmsglit (" /*@trueexit@*/ - function does not return if first parameter is TRUE");
1716 llmsglit (" /*@falseexit@*/ - function does not return if first parameter if FALSE");
1717 llmsglit (" /*@neverexit@*/ - function always returns");
1719 llmsglit ("Side-Effects:");
1720 llmsglit (" /*@sef@*/ - corresponding actual parameter has no side effects");
1722 llmsglit ("Declaration:");
1723 llmsglit (" /*@unused@*/ - need not be used (no unused errors reported)");
1724 llmsglit (" /*@external@*/ - defined externally (no undefined error reported)");
1727 llmsglit (" /*@fallthrough@*/ - fall-through case");
1729 llmsglit ("Break:");
1730 llmsglit (" /*@innerbreak@*/ - break is breaking an inner loop or switch");
1731 llmsglit (" /*@loopbreak@*/ - break is breaking a loop");
1732 llmsglit (" /*@switchbreak@*/ - break is breaking a switch");
1733 llmsglit (" /*@innercontinue@*/ - continue is continuing an inner loop");
1735 llmsglit ("Unreachable Code:");
1736 llmsglit (" /*@notreached@*/ - statement may be unreachable.");
1738 llmsglit ("Special Functions:");
1739 llmsglit (" /*@printflike@*/ - check variable arguments like printf");
1740 llmsglit (" /*@scanflike@*/ - check variable arguments like scanf");
1744 printComments (void)
1746 llmsglit ("Control Comments");
1747 llmsglit ("----------------");
1749 llmsglit ("Setting Flags");
1751 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.");
1753 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,");
1754 llmsglit (" /*@+boolint -modifies =showfunc@*/");
1755 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).");
1757 llmsglit ("Error Suppression");
1759 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.");
1761 llmsglit ("/*@ignore@*/ ... /*@end@*/");
1763 (cstring_makeLiteral
1764 ("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."));
1765 llmsglit ("/*@i@*/");
1767 (cstring_makeLiteral
1768 ("No errors will be reported from an /*@i@*/ comment to the end of the line."));
1769 llmsglit ("/*@i<n>@*/");
1771 (cstring_makeLiteral
1772 ("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, LCLint will report an error."));
1773 llmsglit ("/*@t@*/, /*@t<n>@*/");
1775 (cstring_makeLiteral
1776 ("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."));
1778 llmsglit ("Type Access");
1780 llmsglit ("/*@access <type>@*/");
1781 llmsglit (" Allows the following code to access the representation of <type>");
1782 llmsglit ("/*@noaccess <type>@*/");
1783 llmsglit (" Hides the representation of <type>");
1785 llmsglit ("Macro Expansion");
1787 llmsglit ("/*@notfunction@*/");
1789 (cstring_makeLiteral
1790 ("Indicates that the next macro definition is not intended to be a "
1791 "function, and should be expanded in line instead of checked as a "
1792 "macro function definition."));
1799 llmsglit ("Flag Categories");
1800 llmsglit ("---------------");
1801 listAllCategories ();
1802 llmsglit ("\nTo see the flags in a flag category, do\n lclint -help flags <category>");
1803 llmsglit ("To see a list of all flags in alphabetical order, do\n lclint -help flags alpha");
1804 llmsglit ("To see a full description of all flags, do\n lclint -help flags full");
1808 printMaintainer (void)
1810 llmsg (message ("Maintainer: %s", cstring_makeLiteralTemp (LCLINT_MAINTAINER)));
1811 llmsglit (LCL_COMPILE);
1817 llmsglit ("Mailing Lists");
1818 llmsglit ("-------------");
1820 llmsglit ("There are two mailing lists associated with LCLint: ");
1822 llmsglit (" lclint-announce@virginia.edu");
1824 llmsglit (" Reserved for announcements of new releases and bug fixes.");
1825 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
1826 llmsglit (" subscribe lclint-announce");
1828 llmsglit (" lclint-interest@virginia.edu");
1830 llmsglit (" Informal discussions on the use and development of lclint.");
1831 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
1832 llmsglit (" subscribe lclint-interest");
1836 printReferences (void)
1838 llmsglit ("References");
1839 llmsglit ("----------");
1841 llmsglit ("The LCLint web site is http://lclint.cs.virginia.edu");
1843 llmsglit ("Technical papers relating to LCLint include:");
1845 llmsglit (" David Evans. \"Static Detection of Dynamic Memory Errors\".");
1846 llmsglit (" SIGPLAN Conference on Programming Language Design and ");
1847 llmsglit (" Implementation (PLDI '96), Philadelphia, PA, May 1996.");
1849 llmsglit (" David Evans, John Guttag, Jim Horning and Yang Meng Tan. ");
1850 llmsglit (" \"LCLint: A Tool for Using Specifications to Check Code\".");
1851 llmsglit (" SIGSOFT Symposium on the Foundations of Software Engineering,");
1852 llmsglit (" December 1994.");
1854 llmsglit ("A general book on Larch is:");
1856 llmsglit (" Guttag, John V., Horning, James J., (with Garland, S. J., Jones, ");
1857 llmsglit (" K. D., Modet, A., and Wing, J. M.), \"Larch: Languages and Tools ");
1858 llmsglit (" for Formal Specification\", Springer-Verlag, 1993.");
1862 describePrefixCodes (void)
1864 llmsglit ("Prefix Codes");
1865 llmsglit ("------------");
1867 llmsglit ("These characters have special meaning in name prefixes:");
1869 llmsg (message (" %h Any uppercase letter [A-Z]", PFX_UPPERCASE));
1870 llmsg (message (" %h Any lowercase letter [a-z]", PFX_LOWERCASE));
1871 llmsg (message (" %h Any character (valid in a C identifier)", PFX_ANY));
1872 llmsg (message (" %h Any digit [0-9]", PFX_DIGIT));
1873 llmsg (message (" %h Any non-uppercase letter [a-z0-9_]", PFX_NOTUPPER));
1874 llmsg (message (" %h Any non-lowercase letter [A-Z0-9_]", PFX_NOTLOWER));
1875 llmsg (message (" %h Any letter [A-Za-z]", PFX_ANYLETTER));
1876 llmsg (message (" %h Any letter or digit [A-Za-z0-9]", PFX_ANYLETTERDIGIT));
1877 llmsglit (" * Zero or more repetitions of the previous character class until the end of the name");
1886 eval = context_getLarchPath ();
1887 def = osd_getEnvironmentVariable (LARCH_PATH);
1890 !cstring_equal (eval, cstring_fromChars (DEFAULT_LARCHPATH)))
1892 llmsg (message ("LARCH_PATH = %s", eval));
1896 llmsg (message ("LARCH_PATH = <not set> (default = %s)",
1897 cstring_fromChars (DEFAULT_LARCHPATH)));
1900 llmsglit (" --- path used to find larch initialization files and LSL traits");
1902 eval = context_getLCLImportDir ();
1903 def = osd_getEnvironmentVariable (LCLIMPORTDIR);
1906 !cstring_equal (eval, cstring_fromChars (DEFAULT_LCLIMPORTDIR)))
1908 llmsg (message ("%q = %s", cstring_makeLiteral (LCLIMPORTDIR), eval));
1912 llmsg (message ("%s = <not set, default: %s>", cstring_makeLiteralTemp (LCLIMPORTDIR),
1913 cstring_makeLiteralTemp (DEFAULT_LCLIMPORTDIR)));
1916 llmsglit (" --- directory containing lcl standard library files "
1917 "(import with < ... >)");;
1920 cstring dirs = context_getString (FLG_SYSTEMDIRS);
1922 ("systemdirs = %s (set by include envirnoment variable or -systemdirs)",
1934 fprintf (stderr, "*** Interrupt\n");
1935 llexit (LLINTERRUPT);
1940 /* Cheat when there are parse errors */
1943 fprintf (stderr, "*** Segmentation Violation\n");
1945 /* Don't catch it if fileloc_unparse causes a signal */
1946 (void) signal (SIGSEGV, NULL);
1948 loc = fileloc_unparse (g_currentloc);
1950 fprintf (stderr, "*** Location (not trusted): %s\n",
1951 cstring_toCharsSafe (loc));
1954 fprintf (stderr, "*** Please report bug to %s\n", LCLINT_MAINTAINER);
1958 fprintf (stderr, "*** Signal: %d\n", i);
1960 fprintf (stderr, "*** Location (not trusted): %s\n",
1961 cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
1964 fprintf (stderr, "*** Please report bug to %s ***\n", LCLINT_MAINTAINER);
1972 static bool doneCleanup = FALSE;
1974 /* make sure this is only called once! */
1976 if (doneCleanup) return;
1980 if (context_getFlag (FLG_KEEP))
1982 check (fputs ("Temporary files kept:\n", stderr) != EOF);
1983 fileTable_printTemps (context_fileTable ());
1988 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1992 llbug (message ("Files unclosed: %d", nfiles));
1995 fileTable_cleanup (context_fileTable ());
2002 ** cleans up temp files (if necessary)
2009 DPRINTF (("llexit: %d", status));
2012 if (status == LLFAILURE)
2020 if (status != LLFAILURE)
2022 context_destroyMod ();
2023 exprNode_destroyMod ();
2026 uentry_destroyMod ();
2027 typeIdSet_destroyMod ();
2030 dmalloc_shutdown ();
2034 exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
2038 loadrc (FILE *rcfile, cstringSList *passThroughArgs)
2040 char *s = mstring_create (MAX_LINE_LENGTH);
2043 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2047 while (fgets (s, MAX_LINE_LENGTH, rcfile) != NULL)
2054 DPRINTF (("Line: %s", s));
2055 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2058 while (*s == ' ' || *s == '\t' || *s == '\n')
2066 bool escaped = FALSE;
2067 bool quoted = FALSE;
2070 DPRINTF (("Process: %s", s));
2071 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2072 /* comment characters */
2073 if (c == '#' || c == ';' || c == '\n')
2079 if (c == '-' || c == '+')
2086 llerror (FLG_SYNTAX,
2087 message ("Bad flag syntax (+ or - expected, "
2088 "+ is assumed): %s",
2089 cstring_fromChars (s)));
2099 while ((c = *s) != '\0')
2100 { /* remember to handle spaces and quotes in -D and -U ... */
2126 if (c == ' ' || c == '\t' || c == '\n')
2128 /*@innerbreak@*/ break;
2136 DPRINTF (("Nulling: %c", *s));
2139 if (mstring_isEmpty (thisflag))
2141 llfatalerror (message ("Missing flag: %s",
2142 cstring_fromChars (os)));
2145 DPRINTF (("Flag: %s", thisflag));
2147 opt = identifyFlag (cstring_fromChars (thisflag));
2149 if (flagcode_isSkip (opt))
2153 else if (flagcode_isInvalid (opt))
2155 if (isMode (cstring_fromChars (thisflag)))
2157 context_setMode (cstring_fromChars (thisflag));
2161 llerror (FLG_BADFLAG,
2162 message ("Unrecognized option: %s",
2163 cstring_fromChars (thisflag)));
2168 context_userSetFlag (opt, set);
2170 if (flagcode_hasArgument (opt))
2172 if (opt == FLG_HELP)
2175 llerror (FLG_BADFLAG,
2176 message ("Cannot use help in rc files"));
2178 else if (flagcode_isPassThrough (opt)) /* -D or -U */
2180 cstring arg = cstring_fromCharsNew (thisflag);
2181 cstring_markOwned (arg);
2182 *passThroughArgs = cstringSList_add (*passThroughArgs, arg);
2183 DPRINTF (("Pass through: %s",
2184 cstringSList_unparse (*passThroughArgs)));
2186 else if (opt == FLG_INCLUDEPATH
2187 || opt == FLG_SPECPATH)
2189 cstring dir = cstring_suffix (cstring_fromChars (thisflag), 1); /* skip over I/S */
2193 case FLG_INCLUDEPATH:
2194 cppAddIncludeDir (dir);
2195 /*@switchbreak@*/ break;
2198 g_localSpecPath = cstring_toCharsSafe
2199 (message ("%s:%s", cstring_fromChars (g_localSpecPath), dir));
2201 /*@switchbreak@*/ break;
2205 else if (flagcode_hasString (opt)
2206 || flagcode_hasValue (opt)
2207 || opt == FLG_INIT || opt == FLG_OPTF)
2209 cstring extra = cstring_undefined;
2214 rest = mstring_copy (s);
2215 DPRINTF (("Here: rest = %s", rest));
2219 while ((rchar = *rest) != '\0'
2220 && (isspace ((int) rchar)))
2226 DPRINTF (("Yo: %s", rest));
2228 while ((rchar = *rest) != '\0'
2229 && !isspace ((int) rchar))
2231 extra = cstring_appendChar (extra, rchar);
2236 DPRINTF (("Yo: %s", extra));
2239 if (cstring_isUndefined (extra))
2245 ("Flag %s must be followed by an argument",
2246 flagcode_unparse (opt)));
2252 DPRINTF (("Here we are: %s", extra));
2254 if (flagcode_hasValue (opt))
2256 DPRINTF (("Set value flag: %s", extra));
2257 setValueFlag (opt, extra);
2258 cstring_free (extra);
2260 else if (opt == FLG_OPTF)
2262 FILE *innerf = fopen (cstring_toCharsSafe (extra), "r");
2263 cstring_markOwned (extra);
2267 fileloc fc = g_currentloc;
2268 g_currentloc = fileloc_createRc (extra);
2269 loadrc (innerf, passThroughArgs);
2270 fileloc_reallyFree (g_currentloc);
2278 message ("Options file not found: %s",
2282 else if (opt == FLG_INIT)
2285 llassert (initFile == NULL);
2287 initFile = tsource_create
2288 (cstring_toCharsSafe (extra),
2289 LCLINIT_SUFFIX, FALSE);
2290 cstring_markOwned (extra);
2292 cstring_free (extra);
2295 else if (flagcode_hasString (opt))
2297 if (cstring_firstChar (extra) == '"')
2299 if (cstring_lastChar (extra) == '"')
2301 char *extras = cstring_toCharsSafe (extra);
2303 llassert (extras[strlen(extras) - 1] == '"');
2304 extras[strlen(extras) - 1] = '\0';
2305 extra = cstring_fromChars (extras + 1);
2306 DPRINTF (("Remove quites: %s", extra));
2312 message ("Unmatched \" in option string: %s",
2317 setStringFlag (opt, extra);
2321 cstring_free (extra);
2334 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2335 while ((c == ' ') || (c == '\t'))
2341 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2345 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2347 check (fclose (rcfile) == 0);
2350 static fileIdList preprocessFiles (fileIdList fl)
2351 /*@modifies fileSystem@*/
2353 bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
2354 int skip = (fileIdList_size (fl) / 5);
2355 int filesprocessed = 0;
2356 fileIdList dfiles = fileIdList_create ();
2358 fileloc_free (g_currentloc);
2359 g_currentloc = fileloc_createBuiltin ();
2361 fileIdList_elements (fl, fid)
2363 char *ppfname = cstring_toCharsSafe (fileName (fid));
2365 if (!(osd_fileIsReadable (ppfname)))
2367 lldiagmsg (message ("Cannot open file: %s",
2368 cstring_fromChars (ppfname)));
2372 fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
2374 llassert (!mstring_isEmpty (ppfname));
2378 if ((filesprocessed % skip) == 0)
2380 if (filesprocessed == 0) {
2381 fprintf (stderr, " ");
2384 fprintf (stderr, ".");
2387 (void) fflush (stderr);
2392 if (cppProcess (cstring_fromChars (ppfname),
2393 fileName (dfile)) != 0)
2395 llfatalerror (message ("Preprocessing error for file: %s",
2396 rootFileName (fid)));
2399 fileIdList_add (dfiles, dfile);
2401 } end_fileIdList_elements;