2 ** LCLint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2001 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"
80 # include "mtreader.h"
83 extern /*@external@*/ int yydebug;
85 static void printMail (void);
86 static void printMaintainer (void);
87 static void printReferences (void);
88 static void printFlags (void);
89 static void printAnnotations (void);
90 static void printParseErrors (void);
91 static void printComments (void);
92 static void describePrefixCodes (void);
93 static void cleanupFiles (void);
94 static void showHelp (void);
95 static void interrupt (int p_i);
96 static void loadrc (/*@open@*/ FILE *p_rcfile, cstringSList *p_passThroughArgs)
97 ; // /*@ensures closed p_rcfile@*/ ;
98 static void describeVars (void);
99 static bool specialFlagsHelp (char *p_next);
100 static bool hasShownHerald = FALSE;
101 static char *specFullName (char *p_specfile, /*@out@*/ char **p_inpath)
102 /*@modifies *p_inpath@*/ ;
104 static bool anylcl = FALSE;
105 static clock_t inittime;
107 static /*@only@*/ /*@null@*/ inputStream initFile = inputStream_undefined;
109 static fileIdList preprocessFiles (fileIdList, bool)
110 /*@modifies fileSystem@*/ ;
115 void lslCleanup (void)
116 /*@globals killed g_symtab@*/
117 /*@modifies internalState, g_symtab@*/
120 ** Cleanup all the LCL/LSL.
123 static bool didCleanup = FALSE;
125 llassert (!didCleanup);
130 lsymbol_destroyMod ();
131 LCLSynTableCleanup ();
132 LCLTokenTableCleanup ();
133 LCLScanLineCleanup ();
136 /* clean up LSL parsing */
139 ltokenTableCleanup ();
143 symtable_free (g_symtab);
149 /*@globals undef g_symtab; @*/
150 /*@modifies g_symtab, internalState, fileSystem; @*/
153 ** Open init file provided by user, or use the default LCL init file
156 cstring larchpath = context_getLarchPath ();
157 inputStream LSLinitFile = inputStream_undefined;
161 if (inputStream_isUndefined (initFile))
163 initFile = inputStream_create (cstring_makeLiteral (INITFILENAME),
164 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
167 if (!inputStream_getPath (larchpath, initFile))
169 lldiagmsg (message ("Continuing without LCL init file: %s",
170 inputStream_fileName (initFile)));
174 if (!inputStream_open (initFile))
176 lldiagmsg (message ("Continuing without LCL init file: %s",
177 inputStream_fileName (initFile)));
183 if (!inputStream_open (initFile))
185 lldiagmsg (message ("Continuing without LCL init file: %s",
186 inputStream_fileName (initFile)));
190 /* Initialize checker */
198 LCLTokenTableInit ();
210 /* need this to initialize LCL checker */
212 llassert (inputStream_isDefined (initFile));
213 if (inputStream_isOpen (initFile))
217 LCLScanReset (initFile);
218 LCLProcessInitFileInit ();
219 LCLProcessInitFileReset ();
222 LCLProcessInitFile ();
223 LCLProcessInitFileCleanup ();
226 check (inputStream_close (initFile));
229 /* Initialize LSL init files, for parsing LSL signatures from LSL */
231 LSLinitFile = inputStream_create (cstring_makeLiteral ("lslinit.lsi"),
232 cstring_makeLiteralTemp (".lsi"),
235 if (!inputStream_getPath (larchpath, LSLinitFile))
237 lldiagmsg (message ("Continuing without LSL init file: %s",
238 inputStream_fileName (LSLinitFile)));
242 if (!inputStream_open (LSLinitFile))
244 lldiagmsg (message ("Continuing without LSL init file: %s",
245 inputStream_fileName (LSLinitFile)));
261 if (inputStream_isOpen (LSLinitFile))
264 LSLScanReset (LSLinitFile);
265 LSLProcessInitFileInit ();
267 LSLProcessInitFile ();
269 check (inputStream_close (LSLinitFile));
272 inputStream_free (LSLinitFile);
277 (cstring_makeLiteral ("LSL init file error. Attempting to continue."));
281 g_symtab = symtable_new ();
284 ** sort_init must come after symtab has been initialized
293 ** Equivalent to importing old spec_csupport.lcl
294 ** define immutable LCL type "bool" and bool constants TRUE and FALSE
295 ** and initialized them to be equal to LSL's "true" and "false".
297 ** Reads in CTrait.syms (derived from CTrait.lsl) on LARCH_PATH.
301 LCLReportEolTokens (FALSE);
305 lslProcess (fileIdList lclfiles)
306 /*@globals undef g_currentSpec, undef g_currentSpecName, g_currentloc,
307 undef killed g_symtab; @*/
308 /*@modifies g_currentSpec, g_currentSpecName, g_currentloc, internalState, fileSystem; @*/
311 bool parser_status = FALSE;
312 bool overallStatus = FALSE;
316 context_resetSpecLines ();
318 fileIdList_elements (lclfiles, fid)
320 cstring actualName = cstring_undefined;
321 cstring fname = fileName (fid);
323 if (osd_getPath (cstring_fromChars (g_localSpecPath),
324 fname, &actualName) == OSD_FILENOTFOUND)
326 if (mstring_equal (g_localSpecPath, "."))
328 lldiagmsg (message ("Spec file not found: %s", fname));
332 lldiagmsg (message ("Spec file not found: %s (on %s)",
334 cstring_fromChars (g_localSpecPath)));
339 inputStream specFile;
341 char *namePtr = actualName;
343 while (*namePtr == '.' && *(namePtr + 1) == CONNECTCHAR)
347 /*@noaccess cstring@*/
349 g_currentSpec = cstring_fromCharsNew (namePtr);
351 specFile = inputStream_create (cstring_copy (g_currentSpec),
352 LCL_EXTENSION, TRUE);
354 llassert (inputStream_isDefined (specFile));
356 g_currentSpecName = specFullName
357 (cstring_toCharsSafe (g_currentSpec),
362 if (context_getFlag (FLG_SHOWSCAN))
364 lldiagmsg (message ("< reading spec %s >", g_currentSpec));
367 /* Open source file */
369 if (!inputStream_open (specFile))
371 lldiagmsg (message ("Cannot open file: %s",
372 inputStream_fileName (specFile)));
373 inputStream_free (specFile);
377 scopeInfo dummy_scope = (scopeInfo) dmalloc (sizeof (*dummy_scope));
378 dummy_scope->kind = SPE_INVALID;
381 LCLScanReset (specFile);
384 ** Minor hacks to allow more than one LCL file to
385 ** be scanned, while keeping initializations
388 symtable_enterScope (g_symtab, dummy_scope);
389 resetImports (cstring_fromChars (g_currentSpecName));
390 context_enterLCLfile ();
391 (void) lclHadNewError ();
393 parser_status = (ylparse () != 0);
394 context_exitLCLfile ();
396 overallStatus = parser_status || lclHadNewError ();
398 if (context_getFlag (FLG_DOLCS))
402 outputLCSFile (path, "%FAILED Output from ",
407 outputLCSFile (path, "%PASSED Output from ",
412 (void) inputStream_close (specFile);
413 inputStream_free (specFile);
415 symtable_exitScope (g_symtab);
418 cstring_free (actualName);
419 } end_fileIdList_elements;
421 /* Can cleanup lsl stuff right away */
425 g_currentSpec = cstring_undefined;
426 g_currentSpecName = NULL;
430 static void handlePassThroughFlag (char *arg)
433 char *quotechar = strchr (curarg, '\"');
437 while (quotechar != NULL)
439 if (*(quotechar - 1) == '\\')
441 char *tp = quotechar - 2;
452 curarg = quotechar + 1;
453 quotechar = strchr (curarg, '\"');
459 offset = (quotechar - arg) + 2;
463 arg = cstring_toCharsSafe
464 (message ("%s\"\'%s",
465 cstring_fromChars (arg),
466 cstring_fromChars (quotechar + 1)));
471 arg = cstring_toCharsSafe
472 (message ("%s\'\"%s",
473 cstring_fromChars (arg),
474 cstring_fromChars (quotechar + 1)));
478 curarg = arg + offset;
479 quotechar = strchr (curarg, '\"');
485 llerror (FLG_BADFLAG,
486 message ("Unclosed quote in flag: %s",
487 cstring_fromChars (arg)));
495 ** If the value is surrounded by single quotes ('), remove
496 ** them. This is an artifact of UNIX command line?
499 def = osd_fixDefine (cstring_fromChars (arg + 1));
500 DPRINTF (("Do define: %s", def));
502 DPRINTF (("After define"));
504 } else if (arg[0] == 'U') {
505 cppDoUndefine (cstring_fromChars (arg + 1));
512 void showHerald (void)
514 if (hasShownHerald || context_getFlag (FLG_QUIET)) return;
518 fprintf (g_msgstream, "%s\n\n", LCL_VERSION);
519 hasShownHerald = TRUE;
524 static void addFile (fileIdList files, /*@only@*/ cstring s)
526 if (fileTable_exists (context_fileTable (), s))
529 lldiagmsg (message ("File listed multiple times: %s", s));
534 fileIdList_add (files, fileTable_addFileOnly (context_fileTable (), s));
538 static void addXHFile (fileIdList files, /*@only@*/ cstring s)
540 if (fileTable_exists (context_fileTable (), s))
543 lldiagmsg (message ("File listed multiple times: %s", s));
548 fileIdList_add (files, fileTable_addXHFile (context_fileTable (), s));
554 ** Disable MSVC++ warning about return value. Methinks humbly lclint control
555 ** comments are a mite more legible.
559 # pragma warning (disable:4035)
562 int main (int argc, char *argv[])
564 /*@globals killed undef g_currentloc,
568 /*@modifies g_currentloc, fileSystem,
572 /*@globals killed undef g_currentloc,
573 killed undef initFile,
574 killed g_localSpecPath,
575 killed undef g_currentSpec,
576 killed undef g_currentSpecName,
580 /*@modifies g_currentloc, initFile,
581 g_localSpecPath, g_currentSpec, g_currentSpecName, fileSystem,
586 bool first_time = TRUE;
587 bool showhelp = FALSE;
590 inputStream sourceFile = inputStream_undefined;
592 fileIdList dercfiles;
593 cstringSList fl = cstringSList_undefined;
594 cstringSList passThroughArgs = cstringSList_undefined;
595 fileIdList cfiles, xfiles, lclfiles, mtfiles;
596 clock_t before, lcltime, libtime, pptime, cptime, rstime;
599 g_msgstream = stdout;
601 (void) signal (SIGINT, interrupt);
602 (void) signal (SIGSEGV, interrupt);
604 cfiles = fileIdList_create ();
605 xfiles = fileIdList_create ();
606 lclfiles = fileIdList_create ();
607 mtfiles = fileIdList_create ();
610 clabstract_initMod ();
611 typeIdSet_initMod ();
612 cppReader_initMod ();
615 g_currentloc = fileloc_createBuiltin ();
620 context_setInCommandLine ();
632 ** Add include directories from environment.
636 cstring incval = cstring_copy
637 (osd_getEnvironmentVariable (cstring_makeLiteralTemp (INCLUDE_VAR)));
639 if (cstring_isDefined (incval))
642 ** Each directory on the include path is a system include directory.
645 DPRINTF (("include: %s", incval));
646 context_setString (FLG_SYSTEMDIRS, cstring_copy (incval));
648 while (cstring_isDefined (incval))
651 char *nextsep = strchr (incval, SEPCHAR);
657 dir = cstring_copy (incval);
659 if (cstring_length (dir) == 0
660 || !isalpha ((int) cstring_firstChar (dir)))
663 ** win32 environment values can have special values,
669 cppAddIncludeDir (dir);
673 incval = cstring_fromChars (nextsep + 1);
681 /*@noaccess cstring@*/
685 cstring_free (incval);
689 ** check RCFILE for default flags
693 cstring home = osd_getHomeDir ();
696 bool defaultf = TRUE;
699 for (i = 1; i < argc; i++)
704 if (*thisarg == '-' || *thisarg == '+')
708 if (mstring_equal (thisarg, "nof"))
712 else if (mstring_equal (thisarg, "f"))
718 rcfile = fopen (fname, "r");
722 fileloc oloc = g_currentloc;
724 g_currentloc = fileloc_createRc (cstring_fromChars (fname));
725 loadrc (rcfile, &passThroughArgs);
726 fileloc_reallyFree (g_currentloc);
732 lldiagmsg (message ("Options file not found: %s",
733 cstring_fromChars (fname)));
738 (cstring_makeLiteral ("Flag f to select options file "
739 "requires an argument"));
743 ; /* wait to process later */
750 if (!cstring_isEmpty (home)) {
751 fname = cstring_toCharsSafe (message ("%s%h%s", home, CONNECTCHAR,
752 cstring_fromChars (RCFILE)));
753 mstring_markFree (fname);
759 if (!nof && defaultf)
761 if (!mstring_isEmpty (fname)) {
762 rcfile = fopen (fname, "r");
766 fileloc oloc = g_currentloc;
768 g_currentloc = fileloc_createRc (cstring_fromChars (fname));
769 loadrc (rcfile, &passThroughArgs);
770 fileloc_reallyFree (g_currentloc);
775 # if defined(MSDOS) || defined(OS2)
776 fname = cstring_toCharsSafe (message ("%s",
777 cstring_fromChars (RCFILE)));
779 fname = cstring_toCharsSafe (message ("./%s",
780 cstring_fromChars (RCFILE)));
783 rcfile = fopen (fname, "r");
787 fileloc oloc = g_currentloc;
789 g_currentloc = fileloc_createRc (cstring_fromChars (fname));
790 loadrc (rcfile, &passThroughArgs);
791 fileloc_reallyFree (g_currentloc);
801 for (i = 1; i < argc; i++)
817 if (*thisarg == '-' || *thisarg == '+')
819 thisarg++; /* skip '-' */
821 if (mstring_equal (thisarg, "modes"))
823 llmsg (describeModes ());
825 else if (mstring_equal (thisarg, "vars")
826 || mstring_equal (thisarg, "env"))
830 else if (mstring_equal (thisarg, "annotations"))
834 else if (mstring_equal (thisarg, "parseerrors"))
838 else if (mstring_equal (thisarg, "comments"))
842 else if (mstring_equal (thisarg, "prefixcodes"))
844 describePrefixCodes ();
846 else if (mstring_equal (thisarg, "references")
847 || mstring_equal (thisarg, "refs"))
851 else if (mstring_equal (thisarg, "mail"))
855 else if (mstring_equal (thisarg, "maintainer")
856 || mstring_equal (thisarg, "version"))
860 else if (mstring_equal (thisarg, "flags"))
864 char *next = argv[i + 1];
866 if (specialFlagsHelp (next))
872 flagkind k = identifyCategory (cstring_fromChars (next));
888 cstring s = describeFlag (cstring_fromChars (thisarg));
890 if (cstring_isDefined (s))
898 if (*thisarg == '-' || *thisarg == '+')
900 bool set = (*thisarg == '+');
903 thisarg++; /* skip '-' */
904 flagname = cstring_fromChars (thisarg);
906 DPRINTF (("Flag: %s", flagname));
907 opt = identifyFlag (flagname);
908 DPRINTF (("Flag: %s", flagcode_unparse (opt)));
910 if (flagcode_isSkip (opt))
912 DPRINTF (("Skipping!"));
914 else if (flagcode_isInvalid (opt))
916 DPRINTF (("Invalid: %s", flagname));
918 if (isMode (flagname))
920 context_setMode (flagname);
924 DPRINTF (("Error!"));
925 llgloberror (message ("Unrecognized option: %s",
926 cstring_fromChars (thisarg)));
931 context_userSetFlag (opt, set);
933 if (flagcode_hasArgument (opt))
939 else if (flagcode_isPassThrough (opt)) /* -D or -U */
941 passThroughArgs = cstringSList_add
942 (passThroughArgs, cstring_fromChars (thisarg));
944 else if (flagcode_hasValue (opt))
948 setValueFlag (opt, cstring_fromChars (argv[i]));
954 ("Flag %s must be followed by a number",
955 flagcode_unparse (opt)));
958 else if (opt == FLG_INCLUDEPATH || opt == FLG_SPECPATH)
960 cstring dir = cstring_suffix (cstring_fromChars (thisarg), 1); /* skip over I */
964 case FLG_INCLUDEPATH:
965 cppAddIncludeDir (dir);
966 /*@switchbreak@*/ break;
969 g_localSpecPath = cstring_toCharsSafe
971 cstring_fromChars (g_localSpecPath),
975 /*@switchbreak@*/ break;
979 else if (flagcode_hasString (opt)
980 || opt == FLG_INIT || opt == FLG_OPTF)
984 cstring arg = cstring_fromChars (argv[i]);
988 ; /* -f already processed */
990 else if (opt == FLG_INIT)
993 initFile = inputStream_create
995 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
1002 DPRINTF (("String flag: %s / %s",
1003 flagcode_unparse (opt), arg));
1004 if (opt == FLG_MTSFILE)
1007 ** arg identifies mts files
1010 addFile (mtfiles, message ("%s%s", arg, MTS_EXTENSION));
1011 addXHFile (xfiles, message ("%s%s", arg, XH_EXTENSION));
1015 setStringFlag (opt, arg);
1023 ("Flag %s must be followed by a string",
1024 flagcode_unparse (opt)));
1034 else /* its a filename */
1036 DPRINTF (("Adding filename: %s", thisarg));
1037 fl = cstringSList_add (fl, cstring_fromChars (thisarg));
1045 ** create lists of C and LCL files
1048 cstringSList_elements (fl, current)
1050 cstring ext = fileLib_getExtension (current);
1052 if (cstring_isUndefined (ext))
1054 /* no extension --- both C and LCL with default extensions */
1056 addFile (cfiles, message ("%s%s", current, C_EXTENSION));
1057 addFile (lclfiles, message ("%s%s", current, LCL_EXTENSION));
1059 else if (cstring_equal (ext, XH_EXTENSION))
1061 addXHFile (xfiles, cstring_copy (current));
1063 else if (cstring_equal (ext, LCL_EXTENSION))
1065 addFile (lclfiles, cstring_copy (current));
1067 else if (fileLib_isCExtension (ext))
1069 addFile (cfiles, cstring_copy (current));
1071 else if (cstring_equal (ext, MTS_EXTENSION))
1073 addFile (mtfiles, cstring_copy (current));
1078 (FLG_FILEEXTENSIONS,
1079 message ("Unrecognized file extension: %s (assuming %s is C source code)",
1083 addFile (cfiles, cstring_copy (current));
1085 } end_cstringSList_elements;
1087 showHerald (); /*@i723 move earlier? */
1095 fprintf (g_msgstream, "\n");
1097 fileIdList_free (cfiles);
1098 fileIdList_free (xfiles);
1099 fileIdList_free (lclfiles);
1108 inittime = clock ();
1110 context_resetErrors ();
1111 context_clearInCommandLine ();
1113 anylcl = !fileIdList_isEmpty (lclfiles);
1115 if (context_doMerge ())
1117 cstring m = context_getMerge ();
1119 if (context_getFlag (FLG_SHOWSCAN))
1121 fprintf (g_msgstream, "< loading %s ", cstring_toCharsSafe (m));
1126 if (context_getFlag (FLG_SHOWSCAN))
1128 fprintf (g_msgstream, " >\n");
1131 if (!usymtab_existsType (context_getBoolName ()))
1133 usymtab_initBool ();
1138 if (!context_getFlag (FLG_NOLIB) && loadStandardState ())
1147 /* setup bool type and constants */
1148 usymtab_initBool ();
1151 fileloc_free (g_currentloc);
1152 g_currentloc = fileloc_createBuiltin ();
1155 ** Read metastate files (must happen before loading libraries)
1158 fileIdList_elements (mtfiles, mtfile)
1160 context_setFileId (mtfile);
1162 if (context_getFlag (FLG_SHOWSCAN))
1164 lldiagmsg (message ("< processing %s >", rootFileName (mtfile)));
1167 mtreader_readFile (cstring_copy (fileName (mtfile)));
1168 } end_fileIdList_elements;
1175 llfatalerror (cstring_makeLiteral ("This version of LCLint does not handle LCL files."));
1177 lslProcess (lclfiles);
1181 usymtab_initGlobalMarker ();
1186 ** call the pre-preprocessor and /lib/cpp to generate appropriate
1191 context_setInCommandLine ();
1193 DPRINTF (("Pass through: %s", cstringSList_unparse (passThroughArgs)));
1195 cstringSList_elements (passThroughArgs, thisarg) {
1196 handlePassThroughFlag (cstring_toCharsSafe (thisarg));
1197 } end_cstringSList_elements;
1199 cstringSList_free (passThroughArgs);
1203 DPRINTF (("Initializing cpp reader!"));
1204 cppReader_initialize ();
1205 cppReader_saveDefinitions ();
1207 context_clearInCommandLine ();
1209 if (!context_getFlag (FLG_NOPP))
1215 if (context_getFlag (FLG_SHOWSCAN))
1217 fprintf (stderr, "< preprocessing");
1222 context_setPreprocessing ();
1223 dercfiles = preprocessFiles (xfiles, TRUE);
1224 tfiles = preprocessFiles (cfiles, FALSE);
1225 dercfiles = fileIdList_append (dercfiles, tfiles);
1226 fileIdList_free (tfiles);
1228 context_clearPreprocessing ();
1230 fileIdList_free (cfiles);
1232 if (context_getFlag (FLG_SHOWSCAN))
1234 fprintf (stderr, " >\n");
1242 dercfiles = fileIdList_append (cfiles, xfiles);
1247 ** now, check all the corresponding C files
1249 ** (for now these are just <file>.c, but after pre-processing
1250 ** will be <tmpprefix>.<file>.c)
1255 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1259 llbug (message ("Files unclosed: %d", nfiles));
1264 DPRINTF (("Initializing..."));
1266 exprNode_initMod ();
1268 DPRINTF (("Okay..."));
1270 fileIdList_elements (dercfiles, fid)
1272 sourceFile = inputStream_create (cstring_copy (fileName (fid)), C_EXTENSION, TRUE);
1273 context_setFileId (fid);
1275 /* Open source file */
1277 if (inputStream_isUndefined (sourceFile) || (!inputStream_open (sourceFile)))
1279 /* previously, this was ignored ?! */
1280 llbug (message ("Could not open temp file: %s", fileName (fid)));
1284 yyin = inputStream_getFile (sourceFile); /*< shared <- only */
1286 llassert (yyin != NULL);
1288 if (context_getFlag (FLG_SHOWSCAN))
1290 lldiagmsg (message ("< checking %s >", rootFileName (fid)));
1294 ** Every time, except the first time, through the loop,
1295 ** need to call yyrestart to clean up the parse buffer.
1300 (void) yyrestart (yyin);
1307 DPRINTF (("Entering..."));
1308 context_enterFile ();
1310 context_exitCFile ();
1312 (void) inputStream_close (sourceFile);
1314 } end_fileIdList_elements;
1318 /* process any leftover macros */
1320 context_processAllMacros ();
1322 /* check everything that was specified was defined */
1324 /* don't check if no c files were processed ?
1325 ** is this correct behaviour?
1328 if (context_getFlag (FLG_SHOWSCAN))
1330 lldiagmsg (cstring_makeLiteral ("< global checks >"));
1335 if (context_getLinesProcessed () > 0)
1337 usymtab_allDefined ();
1340 if (context_maybeSet (FLG_TOPUNUSED))
1342 uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main"));
1344 if (uentry_isValid (ue))
1346 uentry_setUsed (ue, fileloc_observeBuiltin ());
1352 if (context_maybeSet (FLG_EXPORTLOCAL))
1354 usymtab_exportLocal ();
1358 if (context_maybeSet (FLG_EXPORTHEADER))
1360 usymtab_exportHeader ();
1363 if (context_getFlag (FLG_SHOWUSES))
1365 usymtab_displayAllUses ();
1368 context_checkSuppressCounts ();
1370 if (context_doDump ())
1372 cstring dump = context_getDump ();
1383 if (context_getFlag (FLG_SHOWSUMMARY))
1390 bool isQuiet = context_getFlag (FLG_QUIET);
1391 cstring specErrors = cstring_undefined;
1393 int nspecErrors = lclNumberErrors ();
1398 if (context_neednl ())
1399 fprintf (g_msgstream, "\n");
1402 if (nspecErrors > 0)
1404 if (nspecErrors == context_getLCLExpect ())
1407 message ("%d spec error%& found, as expected\n ",
1412 if (context_getLCLExpect () > 0)
1415 message ("%d spec error%& found, expected %d\n ",
1417 (int) context_getLCLExpect ());
1421 specErrors = message ("%d spec error%& found\n ",
1429 if (context_getLCLExpect () > 0)
1431 specErrors = message ("No spec errors found, expected %d\n ",
1432 (int) context_getLCLExpect ());
1438 if (context_anyErrors ())
1440 if (context_numErrors () == context_getExpect ())
1443 llmsg (message ("Finished LCLint checking --- "
1444 "%s%d code error%& found, as expected",
1445 specErrors, context_numErrors ()));
1450 if (context_getExpect () > 0)
1454 ("Finished LCLint checking --- "
1455 "%s%d code error%& found, expected %d",
1456 specErrors, context_numErrors (),
1457 (int) context_getExpect ()));
1467 llmsg (message ("Finished LCLint checking --- "
1468 "%s%d code error%& found",
1469 specErrors, context_numErrors ()));
1478 if (context_getExpect () > 0)
1482 ("Finished LCLint checking --- "
1483 "%sno code errors found, expected %d",
1485 (int) context_getExpect ()));
1492 if (context_getLinesProcessed () > 0)
1495 llmsg (message ("Finished LCLint checking --- %sno code errors found",
1502 llmsg (message ("Finished LCLint checking --- %sno code processed",
1509 cstring_free (specErrors);
1512 if (context_getFlag (FLG_STATS))
1514 clock_t ttime = clock () - before;
1515 int specLines = context_getSpecLinesProcessed ();
1521 fprintf (g_msgstream, "%d spec, ", specLines);
1524 # ifndef CLOCKS_PER_SEC
1525 fprintf (g_msgstream, "%d source lines in %ld time steps (steps/sec unknown)\n",
1526 context_getLinesProcessed (),
1529 fprintf (g_msgstream, "%d source lines in %.2f s.\n",
1530 context_getLinesProcessed (),
1531 (double) ttime / CLOCKS_PER_SEC);
1539 if (context_getFlag (FLG_TIMEDIST))
1541 clock_t ttime = clock () - before;
1545 char *msg = (char *) dmalloc (256 * sizeof (*msg));
1550 "Time distribution (percent): initialize %.2f / lcl %.2f / "
1551 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1552 (100.0 * (double) (libtime - before) / ttime),
1553 (100.0 * (double) (lcltime - libtime) / ttime),
1554 (100.0 * (double) (pptime - lcltime) / ttime),
1555 (100.0 * (double) (cptime - pptime) / ttime),
1556 (100.0 * (double) (rstime - cptime) / ttime));
1561 "Time distribution (percent): initialize %.2f / "
1562 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1563 (100.0 * (double) (libtime - before) / ttime),
1564 (100.0 * (double) (pptime - libtime) / ttime),
1565 (100.0 * (double) (cptime - pptime) / ttime),
1566 (100.0 * (double) (rstime - cptime) / ttime));
1569 llgenindentmsgnoloc (cstring_fromCharsO (msg));
1573 llexit (expsuccess ? LLSUCCESS : LLFAILURE);
1578 ** Reenable return value warnings.
1580 # pragma warning (default:4035)
1588 llmsg (message ("Source files are .c, .h and %s files. If there is no suffix,",
1590 llmsg (message (" LCLint will look for <file>.c and <file>%s.", LCL_EXTENSION));
1592 llmsglit ("Use lclint -help <topic or flag name> for more information");
1594 llmsglit ("Topics:");
1596 llmsglit (" annotations (describes source-code annotations)");
1597 llmsglit (" comments (describes control comments)");
1598 llmsglit (" flags (describes flag categories)");
1599 llmsglit (" flags <category> (describes flags in category)");
1600 llmsglit (" flags all (short description of all flags)");
1601 llmsglit (" flags alpha (list all flags alphabetically)");
1602 llmsglit (" flags full (full description of all flags)");
1603 llmsglit (" mail (information on mailing lists)");
1604 llmsglit (" modes (show mode settings)");
1605 llmsglit (" parseerrors (help on handling parser errors)");
1606 llmsglit (" prefixcodes (character codes in namespace prefixes)");
1607 llmsglit (" references (sources for more information)");
1608 llmsglit (" vars (environment variables)");
1609 llmsglit (" version (information on compilation, maintainer)");
1614 specialFlagsHelp (char *next)
1616 if ((next != NULL) && (*next != '-') && (*next != '+'))
1618 if (mstring_equal (next, "alpha"))
1623 else if (mstring_equal (next, "all"))
1625 printAllFlags (TRUE, FALSE);
1628 else if (mstring_equal (next, "categories")
1629 || mstring_equal (next, "cats"))
1631 listAllCategories ();
1634 else if (mstring_equal (next, "full"))
1636 printAllFlags (FALSE, TRUE);
1651 printParseErrors (void)
1653 llmsglit ("Parse Errors");
1654 llmsglit ("------------");
1656 llmsglit ("LCLint will sometimes encounter a parse error for code that "
1657 "can be parsed with a local compiler. There are a few likely "
1658 "causes for this and a number of techniques that can be used "
1659 "to work around the problem.");
1661 llmsglit ("Compiler extensions --- compilers sometimes extend the C "
1662 "language with compiler-specific keywords and syntax. While "
1663 "it is not advisible to use these, oftentimes one has no choice "
1664 "when the system header files use compiler extensions. ");
1666 llmsglit ("LCLint supports some of the GNU (gcc) compiler extensions, "
1667 "if the +gnuextensions flag is set. You may be able to workaround "
1668 "other compiler extensions by using a pre-processor define. "
1669 "Alternately, you can surround the unparseable code with");
1671 llmsglit (" # ifndef __LCLINT__");
1673 llmsglit (" # endif");
1675 /* evans 2000-12-21 fixed typo reported by Jeroen Ruigrok/Asmodai */
1676 llmsglit ("Missing type definitions --- an undefined type name will usually "
1677 "lead to a parse error. This often occurs when a standard header "
1678 "file defines some type that is not part of the standard library. ");
1679 llmsglit ("By default, LCLint does not process the local files corresponding "
1680 "to standard library headers, but uses a library specification "
1681 "instead so dependencies on local system headers can be detected. "
1682 "If another system header file that does not correspond to a "
1683 "standard library header uses one of these superfluous types, "
1684 "a parse error will result.");
1686 llmsglit ("If the parse error is inside a posix standard header file, the "
1687 "first thing to try is +posixlib. This make LCLint use "
1688 "the posix library specification instead of reading the posix "
1691 llmsglit ("Otherwise, you may need to either manually define the problematic "
1692 "type (e.g., add -Dmlink_t=int to your .lclintrc file) or force "
1693 "lclint to process the header file that defines it. This is done "
1694 "by setting -skipansiheaders or -skipposixheaders before "
1695 "the file that defines the type is #include'd.");
1696 llmsglit ("(See lclint -help "
1697 "skipansiheaders and lclint -help skipposixheaders for a list of "
1698 "standard headers.) For example, if <sys/local.h> uses a type "
1699 "defined by posix header <sys/types.h> but not defined by the "
1700 "posix library, we might do: ");
1702 llmsglit (" /*@-skipposixheaders@*/");
1703 llmsglit (" # include <sys/types.h>");
1704 llmsglit (" /*@=skipposixheaders@*/");
1705 llmsglit (" # include <sys/local.h>");
1707 llmsglit ("to force LCLint to process <sys/types.h>.");
1709 llmsglit ("At last resort, +trytorecover can be used to make LCLint attempt "
1710 "to continue after a parse error. This is usually not successful "
1711 "and the author does not consider assertion failures when +trytorecover "
1712 "is used to be bugs.");
1716 printAnnotations (void)
1718 llmsglit ("Annotations");
1719 llmsglit ("-----------");
1721 llmsglit ("Annotations are semantic comments that document certain "
1722 "assumptions about functions, variables, parameters, and types. ");
1724 llmsglit ("They may be used to indicate where the representation of a "
1725 "user-defined type is hidden, to limit where a global variable may "
1726 "be used or modified, to constrain what a function implementation "
1727 "may do to its parameters, and to express checked assumptions about "
1728 "variables, types, structure fields, function parameters, and "
1729 "function results.");
1731 llmsglit ("Annotations are introduced by \"/*@\". The role of the @ may be "
1732 "played by any printable character, selected using -commentchar <char>.");
1734 llmsglit ("Consult the User's Guide for descriptions of checking associated with each annotation.");
1736 llmsglit ("Globals: (in function declarations)");
1737 llmsglit (" /*@globals <globitem>,+ @*/");
1738 llmsglit (" globitem is an identifier, internalState or fileSystem");
1740 llmsglit ("Modifies: (in function declarations)");
1741 llmsglit (" /*@modifies <moditem>,+ @*/");
1742 llmsglit (" moditem is an lvalue");
1743 llmsglit (" /*@modifies nothing @*/");
1744 llmsglit (" /*@*/ (Abbreviation for no globals and modifies nothing.)");
1746 llmsglit ("Iterators:");
1747 llmsglit (" /*@iter <identifier> (<parameter-type-list>) @*/ - declare an iterator");
1749 llmsglit ("Constants:");
1750 llmsglit (" /*@constant <declaration> @*/ - declares a constant");
1752 llmsglit ("Alternate Types:");
1753 llmsglit (" /*@alt <basic-type>,+ @*/");
1754 llmsglit (" (e.g., int /*@alt char@*/ is a type matching either int or char)");
1756 llmsglit ("Declarator Annotations");
1758 llmsglit ("Type Definitions:");
1759 llmsglit (" /*@abstract@*/ - representation is hidden from clients");
1760 llmsglit (" /*@concrete@*/ - representation is visible to clients");
1761 llmsglit (" /*@immutable@*/ - instances of the type cannot change value");
1762 llmsglit (" /*@mutable@*/ - instances of the type can change value");
1763 llmsglit (" /*@refcounted@*/ - reference counted type");
1765 llmsglit ("Global Variables:");
1766 llmsglit (" /*@unchecked@*/ - weakest checking for global use");
1767 llmsglit (" /*@checkmod@*/ - check modification by not use of global");
1768 llmsglit (" /*@checked@*/ - check use and modification of global");
1769 llmsglit (" /*@checkedstrict@*/ - check use of global strictly");
1771 llmsglit ("Memory Management:");
1772 llmsglit (" /*@dependent@*/ - a reference to externally-owned storage");
1773 llmsglit (" /*@keep@*/ - a parameter that is kept by the called function");
1774 llmsglit (" /*@killref@*/ - a refcounted parameter, killed by the call");
1775 llmsglit (" /*@only@*/ - an unshared reference");
1776 llmsglit (" /*@owned@*/ - owner of storage that may be shared by /*@dependent@*/ references");
1777 llmsglit (" /*@shared@*/ - shared reference that is never deallocated");
1778 llmsglit (" /*@temp@*/ - temporary parameter");
1780 llmsglit ("Aliasing:");
1781 llmsglit (" /*@unique@*/ - may not be aliased by any other visible reference");
1782 llmsglit (" /*@returned@*/ - may be aliased by the return value");
1784 llmsglit ("Exposure:");
1785 llmsglit (" /*@observer@*/ - reference that cannot be modified");
1786 llmsglit (" /*@exposed@*/ - exposed reference to storage in another object");
1788 llmsglit ("Definition State:");
1789 llmsglit (" /*@out@*/ - storage reachable from reference need not be defined");
1790 llmsglit (" /*@in@*/ - all storage reachable from reference must be defined");
1791 llmsglit (" /*@partial@*/ - partially defined, may have undefined fields");
1792 llmsglit (" /*@reldef@*/ - relax definition checking");
1794 llmsglit ("Global State: (for globals lists, no /*@, since list is already in /*@\'s)");
1795 llmsglit (" undef - variable is undefined before the call");
1796 llmsglit (" killed - variable is undefined after the call");
1798 llmsglit ("Null State:");
1799 llmsglit (" /*@null@*/ - possibly null pointer");
1800 llmsglit (" /*@notnull@*/ - non-null pointer");
1801 llmsglit (" /*@relnull@*/ - relax null checking");
1803 llmsglit ("Null Predicates:");
1804 llmsglit (" /*@truenull@*/ - if result is TRUE, first parameter is NULL");
1805 llmsglit (" /*@falsenull@*/ - if result is TRUE, first parameter is not NULL");
1807 llmsglit ("Execution:");
1808 llmsglit (" /*@exits@*/ - function never returns");
1809 llmsglit (" /*@mayexit@*/ - function may or may not return");
1810 llmsglit (" /*@trueexit@*/ - function does not return if first parameter is TRUE");
1811 llmsglit (" /*@falseexit@*/ - function does not return if first parameter if FALSE");
1812 llmsglit (" /*@neverexit@*/ - function always returns");
1814 llmsglit ("Side-Effects:");
1815 llmsglit (" /*@sef@*/ - corresponding actual parameter has no side effects");
1817 llmsglit ("Declaration:");
1818 llmsglit (" /*@unused@*/ - need not be used (no unused errors reported)");
1819 llmsglit (" /*@external@*/ - defined externally (no undefined error reported)");
1822 llmsglit (" /*@fallthrough@*/ - fall-through case");
1824 llmsglit ("Break:");
1825 llmsglit (" /*@innerbreak@*/ - break is breaking an inner loop or switch");
1826 llmsglit (" /*@loopbreak@*/ - break is breaking a loop");
1827 llmsglit (" /*@switchbreak@*/ - break is breaking a switch");
1828 llmsglit (" /*@innercontinue@*/ - continue is continuing an inner loop");
1830 llmsglit ("Unreachable Code:");
1831 llmsglit (" /*@notreached@*/ - statement may be unreachable.");
1833 llmsglit ("Special Functions:");
1834 llmsglit (" /*@printflike@*/ - check variable arguments like printf");
1835 llmsglit (" /*@scanflike@*/ - check variable arguments like scanf");
1839 printComments (void)
1841 llmsglit ("Control Comments");
1842 llmsglit ("----------------");
1844 llmsglit ("Setting Flags");
1846 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.");
1848 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,");
1849 llmsglit (" /*@+boolint -modifies =showfunc@*/");
1850 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).");
1852 llmsglit ("Error Suppression");
1854 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.");
1856 llmsglit ("/*@ignore@*/ ... /*@end@*/");
1858 (cstring_makeLiteral
1859 ("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."));
1860 llmsglit ("/*@i@*/");
1862 (cstring_makeLiteral
1863 ("No errors will be reported from an /*@i@*/ comment to the end of the line."));
1864 llmsglit ("/*@i<n>@*/");
1866 (cstring_makeLiteral
1867 ("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."));
1868 llmsglit ("/*@t@*/, /*@t<n>@*/");
1870 (cstring_makeLiteral
1871 ("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."));
1873 llmsglit ("Type Access");
1875 llmsglit ("/*@access <type>@*/");
1876 llmsglit (" Allows the following code to access the representation of <type>");
1877 llmsglit ("/*@noaccess <type>@*/");
1878 llmsglit (" Hides the representation of <type>");
1880 llmsglit ("Macro Expansion");
1882 llmsglit ("/*@notfunction@*/");
1884 (cstring_makeLiteral
1885 ("Indicates that the next macro definition is not intended to be a "
1886 "function, and should be expanded in line instead of checked as a "
1887 "macro function definition."));
1894 llmsglit ("Flag Categories");
1895 llmsglit ("---------------");
1896 listAllCategories ();
1897 llmsglit ("\nTo see the flags in a flag category, do\n lclint -help flags <category>");
1898 llmsglit ("To see a list of all flags in alphabetical order, do\n lclint -help flags alpha");
1899 llmsglit ("To see a full description of all flags, do\n lclint -help flags full");
1903 printMaintainer (void)
1905 llmsg (message ("Maintainer: %s", cstring_makeLiteralTemp (LCLINT_MAINTAINER)));
1906 llmsglit (LCL_COMPILE);
1912 llmsglit ("Mailing Lists");
1913 llmsglit ("-------------");
1915 llmsglit ("There are two mailing lists associated with LCLint: ");
1917 llmsglit (" lclint-announce@virginia.edu");
1919 llmsglit (" Reserved for announcements of new releases and bug fixes.");
1920 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
1921 llmsglit (" subscribe lclint-announce");
1923 llmsglit (" lclint-interest@virginia.edu");
1925 llmsglit (" Informal discussions on the use and development of lclint.");
1926 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
1927 llmsglit (" subscribe lclint-interest");
1931 printReferences (void)
1933 llmsglit ("References");
1934 llmsglit ("----------");
1936 llmsglit ("The LCLint web site is http://lclint.cs.virginia.edu");
1938 llmsglit ("Technical papers relating to LCLint include:");
1940 llmsglit (" David Evans. \"Static Detection of Dynamic Memory Errors\".");
1941 llmsglit (" SIGPLAN Conference on Programming Language Design and ");
1942 llmsglit (" Implementation (PLDI '96), Philadelphia, PA, May 1996.");
1944 llmsglit (" David Evans, John Guttag, Jim Horning and Yang Meng Tan. ");
1945 llmsglit (" \"LCLint: A Tool for Using Specifications to Check Code\".");
1946 llmsglit (" SIGSOFT Symposium on the Foundations of Software Engineering,");
1947 llmsglit (" December 1994.");
1949 llmsglit ("A general book on Larch is:");
1951 llmsglit (" Guttag, John V., Horning, James J., (with Garland, S. J., Jones, ");
1952 llmsglit (" K. D., Modet, A., and Wing, J. M.), \"Larch: Languages and Tools ");
1953 llmsglit (" for Formal Specification\", Springer-Verlag, 1993.");
1957 describePrefixCodes (void)
1959 llmsglit ("Prefix Codes");
1960 llmsglit ("------------");
1962 llmsglit ("These characters have special meaning in name prefixes:");
1964 llmsg (message (" %h Any uppercase letter [A-Z]", PFX_UPPERCASE));
1965 llmsg (message (" %h Any lowercase letter [a-z]", PFX_LOWERCASE));
1966 llmsg (message (" %h Any character (valid in a C identifier)", PFX_ANY));
1967 llmsg (message (" %h Any digit [0-9]", PFX_DIGIT));
1968 llmsg (message (" %h Any non-uppercase letter [a-z0-9_]", PFX_NOTUPPER));
1969 llmsg (message (" %h Any non-lowercase letter [A-Z0-9_]", PFX_NOTLOWER));
1970 llmsg (message (" %h Any letter [A-Za-z]", PFX_ANYLETTER));
1971 llmsg (message (" %h Any letter or digit [A-Za-z0-9]", PFX_ANYLETTERDIGIT));
1972 llmsglit (" * Zero or more repetitions of the previous character class until the end of the name");
1981 eval = context_getLarchPath ();
1982 def = osd_getEnvironmentVariable (LARCH_PATH);
1984 if (cstring_isDefined (def) ||
1985 !cstring_equal (eval, cstring_fromChars (DEFAULT_LARCHPATH)))
1987 llmsg (message ("LARCH_PATH = %s", eval));
1991 llmsg (message ("LARCH_PATH = <not set> (default = %s)",
1992 cstring_fromChars (DEFAULT_LARCHPATH)));
1995 llmsglit (" --- path used to find larch initialization files and LSL traits");
1997 eval = context_getLCLImportDir ();
1998 def = osd_getEnvironmentVariable (cstring_makeLiteralTemp (LCLIMPORTDIR));
2000 if (cstring_isDefined (def) ||
2001 !cstring_equal (eval, cstring_fromChars (DEFAULT_LCLIMPORTDIR)))
2003 llmsg (message ("%q = %s", cstring_makeLiteral (LCLIMPORTDIR), eval));
2007 llmsg (message ("%s = <not set, default: %s>", cstring_makeLiteralTemp (LCLIMPORTDIR),
2008 cstring_makeLiteralTemp (DEFAULT_LCLIMPORTDIR)));
2011 llmsglit (" --- directory containing lcl standard library files "
2012 "(import with < ... >)");;
2015 cstring dirs = context_getString (FLG_SYSTEMDIRS);
2017 ("systemdirs = %s (set by include envirnoment variable or -systemdirs)",
2029 fprintf (stderr, "*** Interrupt\n");
2030 llexit (LLINTERRUPT);
2035 /* Cheat when there are parse errors */
2038 fprintf (stderr, "*** Segmentation Violation\n");
2040 /* Don't catch it if fileloc_unparse causes a signal */
2041 (void) signal (SIGSEGV, NULL);
2043 loc = fileloc_unparse (g_currentloc);
2045 fprintf (stderr, "*** Location (not trusted): %s\n",
2046 cstring_toCharsSafe (loc));
2049 fprintf (stderr, "*** Please report bug to %s\n", LCLINT_MAINTAINER);
2053 fprintf (stderr, "*** Signal: %d\n", i);
2055 fprintf (stderr, "*** Location (not trusted): %s\n",
2056 cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
2059 fprintf (stderr, "*** Please report bug to %s ***\n", LCLINT_MAINTAINER);
2067 static bool doneCleanup = FALSE;
2069 /* make sure this is only called once! */
2071 if (doneCleanup) return;
2075 if (context_getFlag (FLG_KEEP))
2077 check (fputs ("Temporary files kept:\n", stderr) != EOF);
2078 fileTable_printTemps (context_fileTable ());
2083 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
2087 llbug (message ("Files unclosed: %d", nfiles));
2090 fileTable_cleanup (context_fileTable ());
2097 ** cleans up temp files (if necessary)
2104 DPRINTF (("llexit: %d", status));
2107 if (status == LLFAILURE)
2115 if (status != LLFAILURE)
2117 context_destroyMod ();
2118 exprNode_destroyMod ();
2121 uentry_destroyMod ();
2122 typeIdSet_destroyMod ();
2125 dmalloc_shutdown ();
2129 exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
2133 loadrc (/*@open@*/ FILE *rcfile, cstringSList *passThroughArgs)
2134 // /*@ensures closed rcfile@*/
2136 char *s = mstring_create (MAX_LINE_LENGTH);
2139 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2143 while (reader_readLine (rcfile, s, MAX_LINE_LENGTH) != NULL)
2150 DPRINTF (("Line: %s", s));
2151 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2153 while (*s == ' ' || *s == '\t')
2161 bool escaped = FALSE;
2162 bool quoted = FALSE;
2165 DPRINTF (("Process: %s", s));
2166 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2167 /* comment characters */
2168 if (c == '#' || c == ';' || c == '\n')
2174 if (c == '-' || c == '+')
2181 llerror (FLG_SYNTAX,
2182 message ("Bad flag syntax (+ or - expected, "
2183 "+ is assumed): %s",
2184 cstring_fromChars (s)));
2194 while ((c = *s) != '\0')
2195 { /* remember to handle spaces and quotes in -D and -U ... */
2221 if (c == ' ' || c == '\t' || c == '\n')
2223 /*@innerbreak@*/ break;
2231 DPRINTF (("Nulling: %c", *s));
2234 if (mstring_isEmpty (thisflag))
2236 llfatalerror (message ("Missing flag: %s",
2237 cstring_fromChars (os)));
2240 DPRINTF (("Flag: %s", thisflag));
2242 opt = identifyFlag (cstring_fromChars (thisflag));
2244 if (flagcode_isSkip (opt))
2248 else if (flagcode_isInvalid (opt))
2250 DPRINTF (("Invalid: %s", thisflag));
2252 if (isMode (cstring_fromChars (thisflag)))
2254 context_setMode (cstring_fromChars (thisflag));
2258 llerror (FLG_BADFLAG,
2259 message ("Unrecognized option: %s",
2260 cstring_fromChars (thisflag)));
2265 context_userSetFlag (opt, set);
2267 if (flagcode_hasArgument (opt))
2269 if (opt == FLG_HELP)
2272 llerror (FLG_BADFLAG,
2273 message ("Cannot use help in rc files"));
2275 else if (flagcode_isPassThrough (opt)) /* -D or -U */
2277 cstring arg = cstring_fromCharsNew (thisflag);
2278 cstring_markOwned (arg);
2279 *passThroughArgs = cstringSList_add (*passThroughArgs, arg);
2280 DPRINTF (("Pass through: %s",
2281 cstringSList_unparse (*passThroughArgs)));
2283 else if (opt == FLG_INCLUDEPATH
2284 || opt == FLG_SPECPATH)
2286 cstring dir = cstring_suffix (cstring_fromChars (thisflag), 1); /* skip over I/S */
2290 case FLG_INCLUDEPATH:
2291 cppAddIncludeDir (dir);
2292 /*@switchbreak@*/ break;
2295 g_localSpecPath = cstring_toCharsSafe
2296 (message ("%s:%s", cstring_fromChars (g_localSpecPath), dir));
2298 /*@switchbreak@*/ break;
2302 else if (flagcode_hasString (opt)
2303 || flagcode_hasValue (opt)
2304 || opt == FLG_INIT || opt == FLG_OPTF)
2306 cstring extra = cstring_undefined;
2311 rest = mstring_copy (s);
2312 DPRINTF (("Here: rest = %s", rest));
2316 while ((rchar = *rest) != '\0'
2317 && (isspace ((int) rchar)))
2323 DPRINTF (("Yo: %s", rest));
2325 while ((rchar = *rest) != '\0'
2326 && !isspace ((int) rchar))
2328 extra = cstring_appendChar (extra, rchar);
2333 DPRINTF (("Yo: %s", extra));
2336 if (cstring_isUndefined (extra))
2342 ("Flag %s must be followed by an argument",
2343 flagcode_unparse (opt)));
2349 DPRINTF (("Here we are: %s", extra));
2351 if (flagcode_hasValue (opt))
2353 DPRINTF (("Set value flag: %s", extra));
2354 setValueFlag (opt, extra);
2355 cstring_free (extra);
2357 else if (opt == FLG_OPTF)
2359 FILE *innerf = fopen (cstring_toCharsSafe (extra), "r");
2360 cstring_markOwned (extra);
2364 fileloc fc = g_currentloc;
2365 g_currentloc = fileloc_createRc (extra);
2366 loadrc (innerf, passThroughArgs);
2367 fileloc_reallyFree (g_currentloc);
2375 message ("Options file not found: %s",
2379 else if (opt == FLG_INIT)
2382 llassert (inputStream_isUndefined (initFile));
2384 initFile = inputStream_create
2386 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
2389 cstring_free (extra);
2392 else if (flagcode_hasString (opt))
2394 if (cstring_firstChar (extra) == '"')
2396 if (cstring_lastChar (extra) == '"')
2398 char *extras = cstring_toCharsSafe (extra);
2400 llassert (extras[strlen(extras) - 1] == '"');
2401 extras[strlen(extras) - 1] = '\0';
2402 extra = cstring_fromChars (extras + 1);
2403 DPRINTF (("Remove quites: %s", extra));
2409 message ("Unmatched \" in option string: %s",
2414 setStringFlag (opt, extra);
2418 cstring_free (extra);
2431 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2432 while ((c == ' ') || (c == '\t'))
2438 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2442 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2444 check (fclose (rcfile) == 0);
2447 static fileIdList preprocessFiles (fileIdList fl, bool xhfiles)
2448 /*@modifies fileSystem@*/
2450 bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
2451 int skip = (fileIdList_size (fl) / 5);
2452 int filesprocessed = 0;
2453 fileIdList dfiles = fileIdList_create ();
2455 fileloc_free (g_currentloc);
2456 g_currentloc = fileloc_createBuiltin ();
2458 fileIdList_elements (fl, fid)
2460 cstring ppfname = fileName (fid);
2466 if (osd_findOnLarchPath (ppfname, &fpath) == OSD_FILEFOUND)
2468 if (cstring_equal (ppfname, fpath))
2474 DPRINTF (("xh file: %s", fpath));
2476 fileTable_setFilePath (context_fileTable (), fid, fpath);
2481 lldiagmsg (message ("Cannot find .xh file on LARCH_PATH: %s", ppfname));
2482 lldiagmsg (cstring_makeLiteral (" Check LARCH_PATH environment variable."));
2483 ppfname = cstring_undefined;
2488 if (!(osd_fileIsReadable (ppfname)))
2490 lldiagmsg (message ("Cannot open file: %s", ppfname));
2491 ppfname = cstring_undefined;
2495 if (cstring_isDefined (ppfname))
2497 fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
2499 llassert (cstring_isNonEmpty (ppfname));
2503 if ((filesprocessed % skip) == 0)
2505 if (filesprocessed == 0) {
2506 fprintf (stderr, " ");
2509 fprintf (stderr, ".");
2512 (void) fflush (stderr);
2517 if (cppProcess (ppfname, fileName (dfile)) != 0)
2519 llfatalerror (message ("Preprocessing error for file: %s",
2520 rootFileName (fid)));
2523 fileIdList_add (dfiles, dfile);
2525 } end_fileIdList_elements;
2530 /* This should be in an lclUtils.c file... */
2532 char *specFullName (char *specfile, /*@out@*/ char **inpath)
2534 /* extract the path and the specname associated with the given file */
2535 char *specname = (char *) dmalloc (sizeof (*specname)
2536 * (strlen (specfile) + 9));
2537 char *ospecname = specname;
2538 char *path = (char *) dmalloc (sizeof (*path) * (strlen (specfile)));
2542 /* initialized path to empty string or may have accidental garbage */
2545 /*@-mayaliasunique@*/
2546 strcpy (specname, specfile);
2547 /*@=mayaliasunique@*/
2549 /* trim off pathnames in specfile */
2550 size = strlen (specname);
2552 for (i = size_toInt (size) - 1; i >= 0; i--)
2554 if (specname[i] == CONNECTCHAR)
2556 /* strcpy (specname, (char *)specname+i+1); */
2557 for (j = 0; j <= i; j++) /* include '/' */
2559 path[j] = specname[j];
2569 ** also remove .lcl file extension, assume it's the last extension
2573 size = strlen (specname);
2575 for (i = size_toInt (size) - 1; i >= 0; i--)
2577 if (specname[i] == '.')
2587 ** If specname no longer points to the original char,
2588 ** we need to allocate a new pointer and copy the string.
2591 if (specname != ospecname) {
2592 char *rspecname = (char *) dmalloc (sizeof (*rspecname) * (strlen (specname) + 1));
2593 strcpy (rspecname, specname); /* evs 2000-05-16: Bug: was ospecname! */