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;
563 tsource *sourceFile = (tsource *) 0;
565 fileIdList dercfiles;
566 cstringSList fl = cstringSList_undefined;
567 cstringSList passThroughArgs = cstringSList_undefined;
570 clock_t before, lcltime, libtime, pptime, cptime, rstime;
573 g_msgstream = stdout;
575 (void) signal (SIGINT, interrupt);
576 (void) signal (SIGSEGV, interrupt);
578 cfiles = fileIdList_create ();
579 lclfiles = fileIdList_create ();
582 typeIdSet_initMod ();
583 cppReader_initMod ();
587 g_currentloc = fileloc_createBuiltin ();
591 context_setInCommandLine ();
603 ** Add include directories from environment.
607 char *incval = mstring_copy (osd_getEnvironmentVariable (INCLUDE_VAR));
612 ** Each directory on the include path is a system include directory.
615 DPRINTF (("include: %s", incval));
616 context_setString (FLG_SYSTEMDIRS, cstring_fromCharsNew (incval));
618 while (incval != NULL)
620 char *nextsep = strchr (incval, SEPCHAR);
626 dir = cstring_fromCharsNew (incval);
628 if (cstring_length (dir) == 0
629 || !isalpha ((int) cstring_firstChar (dir)))
632 ** win32 environment values can have special values,
638 DPRINTF (("Add include: %s", dir));
639 cppAddIncludeDir (dir);
643 incval = nextsep + 1;
655 ** check RCFILE for default flags
659 cstring home = cstring_fromChars (osd_getHomeDir ());
662 bool defaultf = TRUE;
665 for (i = 1; i < argc; i++)
670 if (*thisarg == '-' || *thisarg == '+')
674 if (mstring_equal (thisarg, "nof"))
678 else if (mstring_equal (thisarg, "f"))
684 rcfile = fopen (fname, "r");
688 fileloc oloc = g_currentloc;
690 g_currentloc = fileloc_createRc (cstring_fromChars (fname));
691 loadrc (rcfile, &passThroughArgs);
692 fileloc_reallyFree (g_currentloc);
698 lldiagmsg (message ("Options file not found: %s",
699 cstring_fromChars (fname)));
704 (cstring_makeLiteral ("Flag f to select options file "
705 "requires an argument"));
709 ; /* wait to process later */
716 if (!cstring_isEmpty (home)) {
717 fname = cstring_toCharsSafe (message ("%s%h%s", home, CONNECTCHAR,
718 cstring_fromChars (RCFILE)));
719 mstring_markFree (fname);
725 if (!nof && defaultf)
727 if (!mstring_isEmpty (fname)) {
728 rcfile = fopen (fname, "r");
732 fileloc oloc = g_currentloc;
734 g_currentloc = fileloc_createRc (cstring_fromChars (fname));
735 loadrc (rcfile, &passThroughArgs);
736 fileloc_reallyFree (g_currentloc);
741 # if defined(MSDOS) || defined(OS2)
742 fname = cstring_toCharsSafe (message ("%s",
743 cstring_fromChars (RCFILE)));
745 fname = cstring_toCharsSafe (message ("./%s",
746 cstring_fromChars (RCFILE)));
749 rcfile = fopen (fname, "r");
753 fileloc oloc = g_currentloc;
755 g_currentloc = fileloc_createRc (cstring_fromChars (fname));
756 loadrc (rcfile, &passThroughArgs);
757 fileloc_reallyFree (g_currentloc);
767 for (i = 1; i < argc; i++)
783 if (*thisarg == '-' || *thisarg == '+')
785 thisarg++; /* skip '-' */
787 if (mstring_equal (thisarg, "modes"))
789 llmsg (describeModes ());
791 else if (mstring_equal (thisarg, "vars")
792 || mstring_equal (thisarg, "env"))
796 else if (mstring_equal (thisarg, "annotations"))
800 else if (mstring_equal (thisarg, "parseerrors"))
804 else if (mstring_equal (thisarg, "comments"))
808 else if (mstring_equal (thisarg, "prefixcodes"))
810 describePrefixCodes ();
812 else if (mstring_equal (thisarg, "references")
813 || mstring_equal (thisarg, "refs"))
817 else if (mstring_equal (thisarg, "mail"))
821 else if (mstring_equal (thisarg, "maintainer")
822 || mstring_equal (thisarg, "version"))
826 else if (mstring_equal (thisarg, "flags"))
830 char *next = argv[i + 1];
832 if (specialFlagsHelp (next))
838 flagkind k = identifyCategory (cstring_fromChars (next));
854 cstring s = describeFlag (cstring_fromChars (thisarg));
856 if (cstring_isDefined (s))
864 if (*thisarg == '-' || *thisarg == '+')
866 bool set = (*thisarg == '+');
869 thisarg++; /* skip '-' */
870 flagname = cstring_fromChars (thisarg);
872 opt = identifyFlag (flagname);
874 if (flagcode_isSkip (opt))
878 else if (flagcode_isInvalid (opt))
880 if (isMode (flagname))
882 context_setMode (flagname);
886 llgloberror (message ("Unrecognized option: %s",
887 cstring_fromChars (thisarg)));
892 context_userSetFlag (opt, set);
894 if (flagcode_hasArgument (opt))
900 else if (flagcode_isPassThrough (opt)) /* -D or -U */
902 passThroughArgs = cstringSList_add
903 (passThroughArgs, cstring_fromChars (thisarg));
905 else if (flagcode_hasValue (opt))
909 setValueFlag (opt, cstring_fromChars (argv[i]));
915 ("Flag %s must be followed by a number",
916 flagcode_unparse (opt)));
919 else if (opt == FLG_INCLUDEPATH || opt == FLG_SPECPATH)
921 cstring dir = cstring_suffix (cstring_fromChars (thisarg), 1); /* skip over I */
925 case FLG_INCLUDEPATH:
926 cppAddIncludeDir (dir);
927 /*@switchbreak@*/ break;
930 g_localSpecPath = cstring_toCharsSafe
932 cstring_fromChars (g_localSpecPath),
936 /*@switchbreak@*/ break;
940 else if (flagcode_hasString (opt)
941 || opt == FLG_INIT || opt == FLG_OPTF)
945 cstring arg = cstring_fromChars (argv[i]);
949 ; /* -f already processed */
951 else if (opt == FLG_INIT)
954 initFile = tsource_create
955 (cstring_toCharsSafe (arg),
956 LCLINIT_SUFFIX, FALSE);
962 setStringFlag (opt, arg);
969 ("Flag %s must be followed by a string",
970 flagcode_unparse (opt)));
980 else /* its a filename */
982 fl = cstringSList_add (fl, cstring_fromChars (thisarg));
990 ** create lists of C and LCL files
993 cstringSList_elements (fl, current)
995 char *fname = cstring_toCharsSafe (current);
996 char *ext = strrchr (fname, '.');
1000 /* no extension --- both C and LCL with default extensions */
1002 addFile (cfiles, message ("%s.c", cstring_fromChars (fname)));
1003 addFile (lclfiles, message ("%s.lcl", cstring_fromChars (fname)));
1005 else if (isCext (ext))
1007 addFile (cfiles, cstring_fromCharsNew (fname));
1011 if (!mstring_equal (ext, ".lcl"))
1013 lldiagmsg (message ("Unrecognized file extension: %s (assuming lcl)",
1014 cstring_fromChars (ext)));
1017 addFile (lclfiles, cstring_fromCharsNew (fname));
1019 } end_cstringSList_elements;
1031 fprintf (g_msgstream, "\n");
1033 fileIdList_free (cfiles);
1034 fileIdList_free (lclfiles);
1043 inittime = clock ();
1045 context_resetErrors ();
1046 context_clearInCommandLine ();
1048 anylcl = !fileIdList_isEmpty (lclfiles);
1050 if (context_doMerge ())
1052 cstring m = context_getMerge ();
1054 if (context_getFlag (FLG_SHOWSCAN))
1056 fprintf (g_msgstream, "< loading %s ", cstring_toCharsSafe (m));
1061 if (context_getFlag (FLG_SHOWSCAN))
1063 fprintf (g_msgstream, " >\n");
1066 if (!usymtab_existsType (context_getBoolName ()))
1068 usymtab_initBool ();
1073 if (!context_getFlag (FLG_NOLIB) && loadStandardState ())
1082 /* setup bool type and constants */
1083 usymtab_initBool ();
1086 fileloc_free (g_currentloc);
1087 g_currentloc = fileloc_createBuiltin ();
1094 llfatalerror (cstring_makeLiteral ("This version of LCLint does not handle LCL files."));
1096 lslProcess (lclfiles);
1103 ** call the pre-preprocessor and /lib/cpp to generate appropriate
1108 context_setInCommandLine ();
1110 cppReader_initialize ();
1112 DPRINTF (("Pass through: %s", cstringSList_unparse (passThroughArgs)));
1114 cstringSList_elements (passThroughArgs, thisarg) {
1115 handlePassThroughFlag (cstring_toCharsSafe (thisarg));
1116 } end_cstringSList_elements;
1118 cstringSList_free (passThroughArgs);
1122 cppReader_saveDefinitions ();
1124 context_clearInCommandLine ();
1126 if (!context_getFlag (FLG_NOPP))
1130 if (context_getFlag (FLG_SHOWSCAN))
1132 fprintf (stderr, "< preprocessing");
1137 context_setPreprocessing ();
1138 dercfiles = preprocessFiles (cfiles);
1139 context_clearPreprocessing ();
1141 fileIdList_free (cfiles);
1143 if (context_getFlag (FLG_SHOWSCAN))
1145 fprintf (stderr, " >\n");
1158 ** now, check all the corresponding C files
1160 ** (for now these are just <file>.c, but after pre-processing
1161 ** will be <tmpprefix>.<file>.c)
1166 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1170 llbug (message ("Files unclosed: %d", nfiles));
1175 exprNode_initMod ();
1177 fileIdList_elements (dercfiles, fid)
1179 sourceFile = tsource_create (cstring_toCharsSafe (fileName (fid)),
1181 context_setFileId (fid);
1183 /* Open source file */
1185 if (sourceFile == (tsource *) 0 || (!tsource_open (sourceFile)))
1187 /* previously, this was ignored ?! */
1188 llbug (message ("Could not open temp file: %s", fileName (fid)));
1192 yyin = sourceFile->file; /*< shared <- only */
1194 llassert (yyin != NULL);
1196 if (context_getFlag (FLG_SHOWSCAN))
1198 lldiagmsg (message ("< checking %s >", rootFileName (fid)));
1202 ** Every time, except the first time, through the loop,
1203 ** need to call yyrestart to clean up the parse buffer.
1208 (void) yyrestart (yyin);
1215 context_enterFile ();
1217 context_exitFile ();
1219 (void) tsource_close (sourceFile);
1222 } end_fileIdList_elements;
1226 /* process any leftover macros */
1228 context_processAllMacros ();
1230 /* check everything that was specified was defined */
1232 /* don't check if no c files were processed ?
1233 ** is this correct behaviour?
1236 if (context_getFlag (FLG_SHOWSCAN))
1238 lldiagmsg (cstring_makeLiteral ("< global checks >"));
1243 if (context_getLinesProcessed () > 0)
1245 usymtab_allDefined ();
1248 if (context_maybeSet (FLG_TOPUNUSED))
1250 uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main"));
1252 if (uentry_isValid (ue))
1254 uentry_setUsed (ue, fileloc_observeBuiltin ());
1260 if (context_maybeSet (FLG_EXPORTLOCAL))
1262 usymtab_exportLocal ();
1266 if (context_maybeSet (FLG_EXPORTHEADER))
1268 usymtab_exportHeader ();
1271 if (context_getFlag (FLG_SHOWUSES))
1273 usymtab_displayAllUses ();
1276 context_checkSuppressCounts ();
1278 if (context_doDump ())
1280 cstring dump = context_getDump ();
1291 if (context_getFlag (FLG_SHOWSUMMARY))
1296 if (!context_getFlag (FLG_QUIET))
1298 cstring specErrors = cstring_undefined;
1300 int nspecErrors = lclNumberErrors ();
1303 if (context_neednl ())
1304 fprintf (g_msgstream, "\n");
1307 if (nspecErrors > 0)
1309 if (nspecErrors == context_getLCLExpect ())
1312 message ("%d spec error%p found, as expected\n ",
1317 if (context_getLCLExpect () > 0)
1320 message ("%d spec error%p found, expected %d\n ",
1322 (int) context_getLCLExpect ());
1326 specErrors = message ("%d spec error%p found\n ",
1333 if (context_getLCLExpect () > 0)
1335 specErrors = message ("No spec errors found, expected %d\n ",
1336 (int) context_getLCLExpect ());
1341 if (context_anyErrors ())
1343 if (context_numErrors () == context_getExpect ())
1345 llmsg (message ("Finished LCLint checking --- "
1346 "%s%d code error%p found, as expected",
1347 specErrors, context_numErrors ()));
1351 if (context_getExpect () > 0)
1354 ("Finished LCLint checking --- "
1355 "%s%d code error%p found, expected %d",
1356 specErrors, context_numErrors (),
1357 (int) context_getExpect ()));
1361 llmsg (message ("Finished LCLint checking --- "
1362 "%s%d code error%p found",
1363 specErrors, context_numErrors ()));
1369 if (context_getExpect () > 0)
1372 ("Finished LCLint checking --- "
1373 "%sno code errors found, expected %d",
1375 (int) context_getExpect ()));
1379 if (context_getLinesProcessed () > 0)
1381 llmsg (message ("Finished LCLint checking --- %sno code errors found",
1386 llmsg (message ("Finished LCLint checking --- %sno code processed",
1392 cstring_free (specErrors);
1395 if (context_getFlag (FLG_STATS))
1397 clock_t ttime = clock () - before;
1398 int specLines = context_getSpecLinesProcessed ();
1404 fprintf (g_msgstream, "%d spec, ", specLines);
1407 # ifndef CLOCKS_PER_SEC
1408 fprintf (g_msgstream, "%d source lines in %ld time steps (steps/sec unknown)\n",
1409 context_getLinesProcessed (),
1412 fprintf (g_msgstream, "%d source lines in %.2f s.\n",
1413 context_getLinesProcessed (),
1414 (double) ttime / CLOCKS_PER_SEC);
1422 if (context_getFlag (FLG_TIMEDIST))
1424 clock_t ttime = clock () - before;
1428 char *msg = (char *) dmalloc (256 * sizeof (*msg));
1433 "Time distribution (percent): initialize %.2f / lcl %.2f / "
1434 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1435 (100.0 * (double) (libtime - before) / ttime),
1436 (100.0 * (double) (lcltime - libtime) / ttime),
1437 (100.0 * (double) (pptime - lcltime) / ttime),
1438 (100.0 * (double) (cptime - pptime) / ttime),
1439 (100.0 * (double) (rstime - cptime) / ttime));
1444 "Time distribution (percent): initialize %.2f / "
1445 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1446 (100.0 * (double) (libtime - before) / ttime),
1447 (100.0 * (double) (pptime - libtime) / ttime),
1448 (100.0 * (double) (cptime - pptime) / ttime),
1449 (100.0 * (double) (rstime - cptime) / ttime));
1452 llgenindentmsgnoloc (cstring_fromCharsO (msg));
1460 ** Reenable return value warnings.
1463 #pragma warning (default:4035)
1470 llmsglit ("Source files are .c, .h and .lcl files. If there is no suffix,");
1471 llmsglit (" LCLint will look for <file>.c and <file>.lcl.");
1473 llmsglit ("Use lclint -help <topic or flag name> for more information");
1475 llmsglit ("Topics:");
1477 llmsglit (" annotations (describes source-code annotations)");
1478 llmsglit (" comments (describes control comments)");
1479 llmsglit (" flags (describes flag categories)");
1480 llmsglit (" flags <category> (describes flags in category)");
1481 llmsglit (" flags all (short description of all flags)");
1482 llmsglit (" flags alpha (list all flags alphabetically)");
1483 llmsglit (" flags full (full description of all flags)");
1484 llmsglit (" mail (information on mailing lists)");
1485 llmsglit (" modes (show mode settings)");
1486 llmsglit (" parseerrors (help on handling parser errors)");
1487 llmsglit (" prefixcodes (character codes in namespace prefixes)");
1488 llmsglit (" references (sources for more information)");
1489 llmsglit (" vars (environment variables)");
1490 llmsglit (" version (information on compilation, maintainer)");
1495 specialFlagsHelp (char *next)
1497 if ((next != NULL) && (*next != '-') && (*next != '+'))
1499 if (mstring_equal (next, "alpha"))
1504 else if (mstring_equal (next, "all"))
1506 printAllFlags (TRUE, FALSE);
1509 else if (mstring_equal (next, "categories")
1510 || mstring_equal (next, "cats"))
1512 listAllCategories ();
1515 else if (mstring_equal (next, "full"))
1517 printAllFlags (FALSE, TRUE);
1532 printParseErrors (void)
1534 llmsglit ("Parse Errors");
1535 llmsglit ("------------");
1537 llmsglit ("LCLint will sometimes encounter a parse error for code that "
1538 "can be parsed with a local compiler. There are a few likely "
1539 "causes for this and a number of techniques that can be used "
1540 "to work around the problem.");
1542 llmsglit ("Compiler extensions --- compilers sometimes extend the C "
1543 "language with compiler-specific keywords and syntax. While "
1544 "it is not advisible to use these, oftentimes one has no choice "
1545 "when the system header files use compiler extensions. ");
1547 llmsglit ("LCLint supports some of the GNU (gcc) compiler extensions, "
1548 "if the +gnuextensions flag is set. You may be able to workaround "
1549 "other compiler extensions by using a pre-processor define. "
1550 "Alternately, you can surround the unparseable code with");
1552 llmsglit (" # ifndef __LCLINT__");
1554 llmsglit (" # endif");
1556 llmsglit ("Missing type definitions --- an undefined type name will usually "
1557 "lead to a parse error. This ofter occurs when a standard header "
1558 "file defines some type that is not part of the standard library. ");
1559 llmsglit ("By default, LCLint does not process the local files corresponding "
1560 "to standard library headers, but uses a library specification "
1561 "instead so dependencies on local system headers can be detected. "
1562 "If another system header file that does not correspond to a "
1563 "standard library header uses one of these superfluous types, "
1564 "a parse error will result.");
1566 llmsglit ("If the parse error is inside a posix standard header file, the "
1567 "first thing to try is +posixlib. This make LCLint use "
1568 "the posix library specification instead of reading the posix "
1571 llmsglit ("Otherwise, you may need to either manually define the problematic "
1572 "type (e.g., add -Dmlink_t=int to your .lclintrc file) or force "
1573 "lclint to process the header file that defines it. This is done "
1574 "by setting -skipansiheaders or -skipposixheaders before "
1575 "the file that defines the type is #include'd.");
1576 llmsglit ("(See lclint -help "
1577 "skipansiheaders and lclint -help skipposixheaders for a list of "
1578 "standard headers.) For example, if <sys/local.h> uses a type "
1579 "defined by posix header <sys/types.h> but not defined by the "
1580 "posix library, we might do: ");
1582 llmsglit (" /*@-skipposixheaders@*/");
1583 llmsglit (" # include <sys/types.h>");
1584 llmsglit (" /*@=skipposixheaders@*/");
1585 llmsglit (" # include <sys/local.h>");
1587 llmsglit ("to force LCLint to process <sys/types.h>.");
1589 llmsglit ("At last resort, +trytorecover can be used to make LCLint attempt "
1590 "to continue after a parse error. This is usually not successful "
1591 "and the author does not consider assertion failures when +trytorecover "
1592 "is used to be bugs.");
1596 printAnnotations (void)
1598 llmsglit ("Annotations");
1599 llmsglit ("-----------");
1601 llmsglit ("Annotations are stylized comments that document certain "
1602 "assumptions about functions, variables, parameters, and types. ");
1604 llmsglit ("They may be used to indicate where the representation of a "
1605 "user-defined type is hidden, to limit where a global variable may "
1606 "be used or modified, to constrain what a function implementation "
1607 "may do to its parameters, and to express checked assumptions about "
1608 "variables, types, structure fields, function parameters, and "
1609 "function results.");
1611 llmsglit ("Annotations are introduced by \"/*@\". The role of the @ may be "
1612 "played by any printable character, selected using -commentchar <char>.");
1614 llmsglit ("Consult the User's Guide for descriptions of checking associated with each annotation.");
1616 llmsglit ("Globals: (in function declarations)");
1617 llmsglit (" /*@globals <globitem>,+ @*/");
1618 llmsglit (" globitem is an identifier, internalState or fileSystem");
1620 llmsglit ("Modifies: (in function declarations)");
1621 llmsglit (" /*@modifies <moditem>,+ @*/");
1622 llmsglit (" moditem is an lvalue");
1623 llmsglit (" /*@modifies nothing @*/");
1624 llmsglit (" /*@*/ (Abbreviation for no globals and modifies nothing.)");
1626 llmsglit ("Iterators:");
1627 llmsglit (" /*@iter <identifier> (<parameter-type-list>) @*/ - declare an iterator");
1629 llmsglit ("Constants:");
1630 llmsglit (" /*@constant <declaration> @*/ - declares a constant");
1632 llmsglit ("Alternate Types:");
1633 llmsglit (" /*@alt <basic-type>,+ @*/");
1634 llmsglit (" (e.g., int /*@alt char@*/ is a type matching either int or char)");
1636 llmsglit ("Declarator Annotations");
1638 llmsglit ("Type Definitions:");
1639 llmsglit (" /*@abstract@*/ - representation is hidden from clients");
1640 llmsglit (" /*@concrete@*/ - representation is visible to clients");
1641 llmsglit (" /*@immutable@*/ - instances of the type cannot change value");
1642 llmsglit (" /*@mutable@*/ - instances of the type can change value");
1643 llmsglit (" /*@refcounted@*/ - reference counted type");
1645 llmsglit ("Global Variables:");
1646 llmsglit (" /*@unchecked@*/ - weakest checking for global use");
1647 llmsglit (" /*@checkmod@*/ - check modification by not use of global");
1648 llmsglit (" /*@checked@*/ - check use and modification of global");
1649 llmsglit (" /*@checkedstrict@*/ - check use of global strictly");
1651 llmsglit ("Memory Management:");
1652 llmsglit (" /*@dependent@*/ - a reference to externally-owned storage");
1653 llmsglit (" /*@keep@*/ - a parameter that is kept by the called function");
1654 llmsglit (" /*@killref@*/ - a refcounted parameter, killed by the call");
1655 llmsglit (" /*@only@*/ - an unshared reference");
1656 llmsglit (" /*@owned@*/ - owner of storage that may be shared by /*@dependent@*/ references");
1657 llmsglit (" /*@shared@*/ - shared reference that is never deallocated");
1658 llmsglit (" /*@temp@*/ - temporary parameter");
1660 llmsglit ("Aliasing:");
1661 llmsglit (" /*@unique@*/ - may not be aliased by any other visible reference");
1662 llmsglit (" /*@returned@*/ - may be aliased by the return value");
1664 llmsglit ("Exposure:");
1665 llmsglit (" /*@observer@*/ - reference that cannot be modified");
1666 llmsglit (" /*@exposed@*/ - exposed reference to storage in another object");
1668 llmsglit ("Definition State:");
1669 llmsglit (" /*@out@*/ - storage reachable from reference need not be defined");
1670 llmsglit (" /*@in@*/ - all storage reachable from reference must be defined");
1671 llmsglit (" /*@partial@*/ - partially defined, may have undefined fields");
1672 llmsglit (" /*@reldef@*/ - relax definition checking");
1674 llmsglit ("Global State: (for globals lists, no /*@, since list is already in /*@\'s)");
1675 llmsglit (" undef - variable is undefined before the call");
1676 llmsglit (" killed - variable is undefined after the call");
1678 llmsglit ("Null State:");
1679 llmsglit (" /*@null@*/ - possibly null pointer");
1680 llmsglit (" /*@notnull@*/ - non-null pointer");
1681 llmsglit (" /*@relnull@*/ - relax null checking");
1683 llmsglit ("Null Predicates:");
1684 llmsglit (" /*@truenull@*/ - if result is TRUE, first parameter is NULL");
1685 llmsglit (" /*@falsenull@*/ - if result is TRUE, first parameter is not NULL");
1687 llmsglit ("Execution:");
1688 llmsglit (" /*@exits@*/ - function never returns");
1689 llmsglit (" /*@mayexit@*/ - function may or may not return");
1690 llmsglit (" /*@trueexit@*/ - function does not return if first parameter is TRUE");
1691 llmsglit (" /*@falseexit@*/ - function does not return if first parameter if FALSE");
1692 llmsglit (" /*@neverexit@*/ - function always returns");
1694 llmsglit ("Side-Effects:");
1695 llmsglit (" /*@sef@*/ - corresponding actual parameter has no side effects");
1697 llmsglit ("Declaration:");
1698 llmsglit (" /*@unused@*/ - need not be used (no unused errors reported)");
1699 llmsglit (" /*@external@*/ - defined externally (no undefined error reported)");
1702 llmsglit (" /*@fallthrough@*/ - fall-through case");
1704 llmsglit ("Break:");
1705 llmsglit (" /*@innerbreak@*/ - break is breaking an inner loop or switch");
1706 llmsglit (" /*@loopbreak@*/ - break is breaking a loop");
1707 llmsglit (" /*@switchbreak@*/ - break is breaking a switch");
1708 llmsglit (" /*@innercontinue@*/ - continue is continuing an inner loop");
1710 llmsglit ("Unreachable Code:");
1711 llmsglit (" /*@notreached@*/ - statement may be unreachable.");
1713 llmsglit ("Special Functions:");
1714 llmsglit (" /*@printflike@*/ - check variable arguments like printf");
1715 llmsglit (" /*@scanflike@*/ - check variable arguments like scanf");
1719 printComments (void)
1721 llmsglit ("Control Comments");
1722 llmsglit ("----------------");
1724 llmsglit ("Setting Flags");
1726 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.");
1728 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,");
1729 llmsglit (" /*@+boolint -modifies =showfunc@*/");
1730 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).");
1732 llmsglit ("Error Suppression");
1734 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.");
1736 llmsglit ("/*@ignore@*/ ... /*@end@*/");
1738 (cstring_makeLiteral
1739 ("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."));
1740 llmsglit ("/*@i@*/");
1742 (cstring_makeLiteral
1743 ("No errors will be reported from an /*@i@*/ comment to the end of the line."));
1744 llmsglit ("/*@i<n>@*/");
1746 (cstring_makeLiteral
1747 ("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."));
1748 llmsglit ("/*@t@*/, /*@t<n>@*/");
1750 (cstring_makeLiteral
1751 ("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."));
1753 llmsglit ("Type Access");
1755 llmsglit ("/*@access <type>@*/");
1756 llmsglit (" Allows the following code to access the representation of <type>");
1757 llmsglit ("/*@noaccess <type>@*/");
1758 llmsglit (" Hides the representation of <type>");
1760 llmsglit ("Macro Expansion");
1762 llmsglit ("/*@notfunction@*/");
1764 (cstring_makeLiteral
1765 ("Indicates that the next macro definition is not intended to be a "
1766 "function, and should be expanded in line instead of checked as a "
1767 "macro function definition."));
1774 llmsglit ("Flag Categories");
1775 llmsglit ("---------------");
1776 listAllCategories ();
1777 llmsglit ("\nTo see the flags in a flag category, do\n lclint -help flags <category>");
1778 llmsglit ("To see a list of all flags in alphabetical order, do\n lclint -help flags alpha");
1779 llmsglit ("To see a full description of all flags, do\n lclint -help flags full");
1783 printMaintainer (void)
1785 llmsg (message ("Maintainer: %s", cstring_makeLiteralTemp (LCLINT_MAINTAINER)));
1786 llmsglit (LCL_COMPILE);
1792 llmsglit ("Mailing Lists");
1793 llmsglit ("-------------");
1795 llmsglit ("There are two mailing lists associated with LCLint: ");
1797 llmsglit (" lclint-announce@virginia.edu");
1799 llmsglit (" Reserved for announcements of new releases and bug fixes.");
1800 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
1801 llmsglit (" subscribe lclint-announce");
1803 llmsglit (" lclint-interest@virginia.edu");
1805 llmsglit (" Informal discussions on the use and development of lclint.");
1806 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
1807 llmsglit (" subscribe lclint-interest");
1811 printReferences (void)
1813 llmsglit ("References");
1814 llmsglit ("----------");
1816 llmsglit ("The LCLint web site is http://lclint.cs.virginia.edu");
1818 llmsglit ("Technical papers relating to LCLint include:");
1820 llmsglit (" David Evans. \"Static Detection of Dynamic Memory Errors\".");
1821 llmsglit (" SIGPLAN Conference on Programming Language Design and ");
1822 llmsglit (" Implementation (PLDI '96), Philadelphia, PA, May 1996.");
1824 llmsglit (" David Evans, John Guttag, Jim Horning and Yang Meng Tan. ");
1825 llmsglit (" \"LCLint: A Tool for Using Specifications to Check Code\".");
1826 llmsglit (" SIGSOFT Symposium on the Foundations of Software Engineering,");
1827 llmsglit (" December 1994.");
1829 llmsglit ("A general book on Larch is:");
1831 llmsglit (" Guttag, John V., Horning, James J., (with Garland, S. J., Jones, ");
1832 llmsglit (" K. D., Modet, A., and Wing, J. M.), \"Larch: Languages and Tools ");
1833 llmsglit (" for Formal Specification\", Springer-Verlag, 1993.");
1837 describePrefixCodes (void)
1839 llmsglit ("Prefix Codes");
1840 llmsglit ("------------");
1842 llmsglit ("These characters have special meaning in name prefixes:");
1844 llmsg (message (" %h Any uppercase letter [A-Z]", PFX_UPPERCASE));
1845 llmsg (message (" %h Any lowercase letter [a-z]", PFX_LOWERCASE));
1846 llmsg (message (" %h Any character (valid in a C identifier)", PFX_ANY));
1847 llmsg (message (" %h Any digit [0-9]", PFX_DIGIT));
1848 llmsg (message (" %h Any non-uppercase letter [a-z0-9_]", PFX_NOTUPPER));
1849 llmsg (message (" %h Any non-lowercase letter [A-Z0-9_]", PFX_NOTLOWER));
1850 llmsg (message (" %h Any letter [A-Za-z]", PFX_ANYLETTER));
1851 llmsg (message (" %h Any letter or digit [A-Za-z0-9]", PFX_ANYLETTERDIGIT));
1852 llmsglit (" * Zero or more repetitions of the previous character class until the end of the name");
1861 eval = context_getLarchPath ();
1862 def = osd_getEnvironmentVariable (LARCH_PATH);
1865 !cstring_equal (eval, cstring_fromChars (DEFAULT_LARCHPATH)))
1867 llmsg (message ("LARCH_PATH = %s", eval));
1871 llmsg (message ("LARCH_PATH = <not set> (default = %s)",
1872 cstring_fromChars (DEFAULT_LARCHPATH)));
1875 llmsglit (" --- path used to find larch initialization files and LSL traits");
1877 eval = context_getLCLImportDir ();
1878 def = osd_getEnvironmentVariable (LCLIMPORTDIR);
1881 !cstring_equal (eval, cstring_fromChars (DEFAULT_LCLIMPORTDIR)))
1883 llmsg (message ("%q = %s", cstring_makeLiteral (LCLIMPORTDIR), eval));
1887 llmsg (message ("%s = <not set, default: %s>", cstring_makeLiteralTemp (LCLIMPORTDIR),
1888 cstring_makeLiteralTemp (DEFAULT_LCLIMPORTDIR)));
1891 llmsglit (" --- directory containing lcl standard library files "
1892 "(import with < ... >)");;
1895 cstring dirs = context_getString (FLG_SYSTEMDIRS);
1897 ("systemdirs = %s (set by include envirnoment variable or -systemdirs)",
1909 fprintf (stderr, "*** Interrupt\n");
1910 llexit (LLINTERRUPT);
1915 /* Cheat when there are parse errors */
1918 fprintf (stderr, "*** Segmentation Violation\n");
1920 /* Don't catch it if fileloc_unparse causes a signal */
1921 (void) signal (SIGSEGV, NULL);
1923 loc = fileloc_unparse (g_currentloc);
1925 fprintf (stderr, "*** Location (not trusted): %s\n",
1926 cstring_toCharsSafe (loc));
1929 fprintf (stderr, "*** Please report bug to %s\n", LCLINT_MAINTAINER);
1933 fprintf (stderr, "*** Signal: %d\n", i);
1935 fprintf (stderr, "*** Location (not trusted): %s\n",
1936 cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
1939 fprintf (stderr, "*** Please report bug to %s ***\n", LCLINT_MAINTAINER);
1947 static bool doneCleanup = FALSE;
1949 /* make sure this is only called once! */
1951 if (doneCleanup) return;
1955 if (context_getFlag (FLG_KEEP))
1957 check (fputs ("Temporary files kept:\n", stderr) != EOF);
1958 fileTable_printTemps (context_fileTable ());
1963 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1967 llbug (message ("Files unclosed: %d", nfiles));
1970 fileTable_cleanup (context_fileTable ());
1977 ** cleans up temp files (if necessary)
1985 if (status == LLFAILURE)
1993 if (status != LLFAILURE)
1995 context_destroyMod ();
1996 exprNode_destroyMod ();
1999 uentry_destroyMod ();
2000 typeIdSet_destroyMod ();
2003 dmalloc_shutdown ();
2007 exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
2011 loadrc (FILE *rcfile, cstringSList *passThroughArgs)
2013 char *s = mstring_create (MAX_LINE_LENGTH);
2016 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2020 while (fgets (s, MAX_LINE_LENGTH, rcfile) != NULL)
2027 DPRINTF (("Line: %s", s));
2028 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2031 while (*s == ' ' || *s == '\t' || *s == '\n')
2039 bool escaped = FALSE;
2040 bool quoted = FALSE;
2043 DPRINTF (("Process: %s", s));
2044 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2045 /* comment characters */
2046 if (c == '#' || c == ';' || c == '\n')
2052 if (c == '-' || c == '+')
2059 llerror (FLG_SYNTAX,
2060 message ("Bad flag syntax (+ or - expected, "
2061 "+ is assumed): %s",
2062 cstring_fromChars (s)));
2072 while ((c = *s) != '\0')
2073 { /* remember to handle spaces and quotes in -D and -U ... */
2099 if (c == ' ' || c == '\t' || c == '\n')
2101 /*@innerbreak@*/ break;
2109 DPRINTF (("Nulling: %c", *s));
2112 if (mstring_isEmpty (thisflag))
2114 llfatalerror (message ("Missing flag: %s",
2115 cstring_fromChars (os)));
2118 DPRINTF (("Flag: %s", thisflag));
2120 opt = identifyFlag (cstring_fromChars (thisflag));
2122 if (flagcode_isSkip (opt))
2126 else if (flagcode_isInvalid (opt))
2128 if (isMode (cstring_fromChars (thisflag)))
2130 context_setMode (cstring_fromChars (thisflag));
2134 llerror (FLG_BADFLAG,
2135 message ("Unrecognized option: %s",
2136 cstring_fromChars (thisflag)));
2141 context_userSetFlag (opt, set);
2143 if (flagcode_hasArgument (opt))
2145 if (opt == FLG_HELP)
2148 llerror (FLG_BADFLAG,
2149 message ("Cannot use help in rc files"));
2151 else if (flagcode_isPassThrough (opt)) /* -D or -U */
2153 cstring arg = cstring_fromCharsNew (thisflag);
2154 cstring_markOwned (arg);
2155 *passThroughArgs = cstringSList_add (*passThroughArgs, arg);
2156 DPRINTF (("Pass through: %s",
2157 cstringSList_unparse (*passThroughArgs)));
2159 else if (opt == FLG_INCLUDEPATH
2160 || opt == FLG_SPECPATH)
2162 cstring dir = cstring_suffix (cstring_fromChars (thisflag), 1); /* skip over I/S */
2166 case FLG_INCLUDEPATH:
2167 cppAddIncludeDir (dir);
2168 /*@switchbreak@*/ break;
2171 g_localSpecPath = cstring_toCharsSafe
2172 (message ("%s:%s", cstring_fromChars (g_localSpecPath), dir));
2174 /*@switchbreak@*/ break;
2178 else if (flagcode_hasString (opt)
2179 || flagcode_hasValue (opt)
2180 || opt == FLG_INIT || opt == FLG_OPTF)
2182 cstring extra = cstring_undefined;
2187 rest = mstring_copy (s);
2188 DPRINTF (("Here: rest = %s", rest));
2192 while ((rchar = *rest) != '\0'
2193 && (isspace ((int) rchar)))
2199 DPRINTF (("Yo: %s", rest));
2201 while ((rchar = *rest) != '\0'
2202 && !isspace ((int) rchar))
2204 extra = cstring_appendChar (extra, rchar);
2209 DPRINTF (("Yo: %s", extra));
2212 if (cstring_isUndefined (extra))
2218 ("Flag %s must be followed by an argument",
2219 flagcode_unparse (opt)));
2225 DPRINTF (("Here we are: %s", extra));
2227 if (flagcode_hasValue (opt))
2229 DPRINTF (("Set value flag: %s", extra));
2230 setValueFlag (opt, extra);
2231 cstring_free (extra);
2233 else if (opt == FLG_OPTF)
2235 FILE *innerf = fopen (cstring_toCharsSafe (extra), "r");
2236 cstring_markOwned (extra);
2240 fileloc fc = g_currentloc;
2241 g_currentloc = fileloc_createRc (extra);
2242 loadrc (innerf, passThroughArgs);
2243 fileloc_reallyFree (g_currentloc);
2251 message ("Options file not found: %s",
2255 else if (opt == FLG_INIT)
2258 llassert (initFile == NULL);
2260 initFile = tsource_create
2261 (cstring_toCharsSafe (extra),
2262 LCLINIT_SUFFIX, FALSE);
2263 cstring_markOwned (extra);
2265 cstring_free (extra);
2268 else if (flagcode_hasString (opt))
2270 if (cstring_firstChar (extra) == '"')
2272 if (cstring_lastChar (extra) == '"')
2274 char *extras = cstring_toCharsSafe (extra);
2276 llassert (extras[strlen(extras) - 1] == '"');
2277 extras[strlen(extras) - 1] = '\0';
2278 extra = cstring_fromChars (extras + 1);
2279 DPRINTF (("Remove quites: %s", extra));
2285 message ("Unmatched \" in option string: %s",
2290 setStringFlag (opt, extra);
2294 cstring_free (extra);
2307 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2308 while ((c == ' ') || (c == '\t'))
2314 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2318 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2320 check (fclose (rcfile) == 0);
2323 static fileIdList preprocessFiles (fileIdList fl)
2324 /*@modifies fileSystem@*/
2326 bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
2327 int skip = (fileIdList_size (fl) / 5);
2328 int filesprocessed = 0;
2329 fileIdList dfiles = fileIdList_create ();
2331 fileloc_free (g_currentloc);
2332 g_currentloc = fileloc_createBuiltin ();
2334 fileIdList_elements (fl, fid)
2336 char *ppfname = cstring_toCharsSafe (fileName (fid));
2338 if (!(osd_fileIsReadable (ppfname)))
2340 lldiagmsg (message ("Cannot open file: %s",
2341 cstring_fromChars (ppfname)));
2345 fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
2347 llassert (!mstring_isEmpty (ppfname));
2351 if ((filesprocessed % skip) == 0)
2353 if (filesprocessed == 0) {
2354 fprintf (stderr, " ");
2357 fprintf (stderr, ".");
2360 (void) fflush (stderr);
2365 if (cppProcess (cstring_fromChars (ppfname),
2366 fileName (dfile)) != 0)
2368 llfatalerror (message ("Preprocessing error for file: %s",
2369 rootFileName (fid)));
2372 fileIdList_add (dfiles, dfile);
2374 } end_fileIdList_elements;