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"
81 extern /*@external@*/ int yydebug;
83 static void printMail (void);
84 static void printMaintainer (void);
85 static void printReferences (void);
86 static void printFlags (void);
87 static void printAnnotations (void);
88 static void printParseErrors (void);
89 static void printComments (void);
90 static void describePrefixCodes (void);
91 static void cleanupFiles (void);
92 static void showHelp (void);
93 static void interrupt (int p_i);
95 static void loadrc (FILE *p_rcfile, cstringSList *p_passThroughArgs)
96 /*@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, '\"');
436 char *freearg = NULL;
438 while (quotechar != NULL)
440 if (*(quotechar - 1) == '\\')
442 char *tp = quotechar - 2;
453 curarg = quotechar + 1;
454 quotechar = strchr (curarg, '\"');
459 llassert (quotechar != NULL);
461 offset = (quotechar - arg) + 2;
465 arg = cstring_toCharsSafe
466 (message ("%s\"\'%s",
467 cstring_fromChars (arg),
468 cstring_fromChars (quotechar + 1)));
474 arg = cstring_toCharsSafe
475 (message ("%s\'\"%s",
476 cstring_fromChars (arg),
477 cstring_fromChars (quotechar + 1)));
482 curarg = arg + offset;
483 quotechar = strchr (curarg, '\"');
489 voptgenerror (FLG_BADFLAG,
490 message ("Unclosed quote in flag: %s",
491 cstring_fromChars (arg)),
500 ** If the value is surrounded by single quotes ('), remove
501 ** them. This is an artifact of UNIX command line?
504 def = osd_fixDefine (cstring_fromChars (arg + 1));
505 DPRINTF (("Do define: %s", def));
507 DPRINTF (("After define"));
509 } else if (arg[0] == 'U') {
510 cppDoUndefine (cstring_fromChars (arg + 1));
519 void showHerald (void)
521 if (hasShownHerald || context_getFlag (FLG_QUIET)) return;
525 fprintf (g_msgstream, "%s\n\n", LCL_VERSION);
526 hasShownHerald = TRUE;
531 static void addFile (fileIdList files, /*@only@*/ cstring s)
533 if (fileTable_exists (context_fileTable (), s))
536 lldiagmsg (message ("File listed multiple times: %s", s));
541 fileIdList_add (files, fileTable_addFileOnly (context_fileTable (), s));
545 static void addXHFile (fileIdList files, /*@only@*/ cstring s)
547 if (fileTable_exists (context_fileTable (), s))
550 lldiagmsg (message ("File listed multiple times: %s", s));
555 fileIdList_add (files, fileTable_addXHFile (context_fileTable (), s));
561 ** Disable MSVC++ warning about return value. Methinks humbly lclint control
562 ** comments are a mite more legible.
566 # pragma warning (disable:4035)
569 int main (int argc, char *argv[])
571 /*@globals killed undef g_currentloc,
575 /*@modifies g_currentloc, fileSystem,
579 /*@globals killed undef g_currentloc,
580 killed undef initFile,
581 killed g_localSpecPath,
582 killed undef g_currentSpec,
583 killed undef g_currentSpecName,
587 /*@modifies g_currentloc, initFile,
588 g_localSpecPath, g_currentSpec, g_currentSpecName, fileSystem,
593 bool first_time = TRUE;
594 bool showhelp = FALSE;
597 inputStream sourceFile = inputStream_undefined;
599 fileIdList dercfiles;
600 cstringSList fl = cstringSList_undefined;
601 cstringSList passThroughArgs = cstringSList_undefined;
602 fileIdList cfiles, xfiles, lclfiles, mtfiles;
603 clock_t before, lcltime, libtime, pptime, cptime, rstime;
606 g_msgstream = stdout;
608 (void) signal (SIGINT, interrupt);
609 (void) signal (SIGSEGV, interrupt);
611 cfiles = fileIdList_create ();
612 xfiles = fileIdList_create ();
613 lclfiles = fileIdList_create ();
614 mtfiles = fileIdList_create ();
617 clabstract_initMod ();
618 typeIdSet_initMod ();
619 cppReader_initMod ();
622 g_currentloc = fileloc_createBuiltin ();
627 context_setInCommandLine ();
639 ** Add include directories from environment.
643 cstring incval = cstring_copy (osd_getEnvironmentVariable (INCLUDEPATH_VAR));
644 cstring oincval = incval;
646 if (cstring_isDefined (incval))
649 ** Each directory on the include path is a system include directory.
652 DPRINTF (("include: %s", incval));
653 context_setString (FLG_SYSTEMDIRS, cstring_copy (incval));
655 while (cstring_isDefined (incval))
658 char *nextsep = strchr (incval, PATH_SEPARATOR);
664 dir = cstring_copy (incval);
666 if (cstring_length (dir) == 0
667 || !isalpha ((int) cstring_firstChar (dir)))
670 ** win32 environment values can have special values,
676 cppAddIncludeDir (dir);
679 *nextsep = PATH_SEPARATOR;
680 incval = cstring_fromChars (nextsep + 1);
688 /*@noaccess cstring@*/
692 cstring_free (oincval);
696 ** check RCFILE for default flags
700 cstring home = osd_getHomeDir ();
703 bool defaultf = TRUE;
706 for (i = 1; i < argc; i++)
711 if (*thisarg == '-' || *thisarg == '+')
715 if (mstring_equal (thisarg, "nof"))
719 else if (mstring_equal (thisarg, "f"))
725 rcfile = fopen (fname, "r");
729 fileloc oloc = g_currentloc;
731 g_currentloc = fileloc_createRc (cstring_fromChars (fname));
732 loadrc (rcfile, &passThroughArgs);
733 fileloc_reallyFree (g_currentloc);
739 lldiagmsg (message ("Options file not found: %s",
740 cstring_fromChars (fname)));
745 (cstring_makeLiteral ("Flag f to select options file "
746 "requires an argument"));
750 ; /* wait to process later */
757 if (!cstring_isEmpty (home)) {
758 fname = cstring_toCharsSafe (message ("%s%h%s", home, CONNECTCHAR,
759 cstring_fromChars (RCFILE)));
760 mstring_markFree (fname);
766 if (!nof && defaultf)
768 if (!mstring_isEmpty (fname)) {
769 rcfile = fopen (fname, "r");
773 fileloc oloc = g_currentloc;
775 g_currentloc = fileloc_createRc (cstring_fromChars (fname));
776 loadrc (rcfile, &passThroughArgs);
777 fileloc_reallyFree (g_currentloc);
782 # if defined(MSDOS) || defined(OS2)
783 fname = cstring_toCharsSafe (message ("%s",
784 cstring_fromChars (RCFILE)));
786 fname = cstring_toCharsSafe (message ("./%s",
787 cstring_fromChars (RCFILE)));
790 rcfile = fopen (fname, "r");
794 fileloc oloc = g_currentloc;
796 g_currentloc = fileloc_createRc (cstring_fromChars (fname));
797 loadrc (rcfile, &passThroughArgs);
798 fileloc_reallyFree (g_currentloc);
808 for (i = 1; i < argc; i++)
824 if (*thisarg == '-' || *thisarg == '+')
826 thisarg++; /* skip '-' */
828 if (mstring_equal (thisarg, "modes"))
830 llmsg (describeModes ());
832 else if (mstring_equal (thisarg, "vars")
833 || mstring_equal (thisarg, "env"))
837 else if (mstring_equal (thisarg, "annotations"))
841 else if (mstring_equal (thisarg, "parseerrors"))
845 else if (mstring_equal (thisarg, "comments"))
849 else if (mstring_equal (thisarg, "prefixcodes"))
851 describePrefixCodes ();
853 else if (mstring_equal (thisarg, "references")
854 || mstring_equal (thisarg, "refs"))
858 else if (mstring_equal (thisarg, "mail"))
862 else if (mstring_equal (thisarg, "maintainer")
863 || mstring_equal (thisarg, "version"))
867 else if (mstring_equal (thisarg, "flags"))
871 char *next = argv[i + 1];
873 if (specialFlagsHelp (next))
879 flagkind k = identifyCategory (cstring_fromChars (next));
895 cstring s = describeFlag (cstring_fromChars (thisarg));
897 if (cstring_isDefined (s))
905 if (*thisarg == '-' || *thisarg == '+')
907 bool set = (*thisarg == '+');
910 thisarg++; /* skip '-' */
911 flagname = cstring_fromChars (thisarg);
913 DPRINTF (("Flag: %s", flagname));
914 opt = identifyFlag (flagname);
915 DPRINTF (("Flag: %s", flagcode_unparse (opt)));
917 if (flagcode_isSkip (opt))
919 DPRINTF (("Skipping!"));
921 else if (flagcode_isInvalid (opt))
923 DPRINTF (("Invalid: %s", flagname));
925 if (isMode (flagname))
927 context_setMode (flagname);
931 DPRINTF (("Error!"));
932 voptgenerror (FLG_BADFLAG,
933 message ("Unrecognized option: %s",
934 cstring_fromChars (thisarg)),
940 context_userSetFlag (opt, set);
942 if (flagcode_hasArgument (opt))
948 else if (flagcode_isPassThrough (opt)) /* -D or -U */
950 passThroughArgs = cstringSList_add
951 (passThroughArgs, cstring_fromChars (thisarg));
953 else if (flagcode_hasValue (opt))
957 setValueFlag (opt, cstring_fromChars (argv[i]));
963 ("Flag %s must be followed by a number",
964 flagcode_unparse (opt)));
967 else if (opt == FLG_INCLUDEPATH || opt == FLG_SPECPATH)
969 cstring dir = cstring_suffix (cstring_fromChars (thisarg), 1); /* skip over I */
973 case FLG_INCLUDEPATH:
974 cppAddIncludeDir (dir);
975 /*@switchbreak@*/ break;
978 g_localSpecPath = cstring_toCharsSafe
980 cstring_fromChars (g_localSpecPath),
984 /*@switchbreak@*/ break;
988 else if (flagcode_hasString (opt)
989 || opt == FLG_INIT || opt == FLG_OPTF)
993 cstring arg = cstring_fromChars (argv[i]);
997 ; /* -f already processed */
999 else if (opt == FLG_INIT)
1002 initFile = inputStream_create
1004 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
1011 DPRINTF (("String flag: %s / %s",
1012 flagcode_unparse (opt), arg));
1013 if (opt == FLG_MTSFILE)
1016 ** arg identifies mts files
1019 addFile (mtfiles, message ("%s%s", arg, MTS_EXTENSION));
1020 addXHFile (xfiles, message ("%s%s", arg, XH_EXTENSION));
1024 setStringFlag (opt, arg);
1032 ("Flag %s must be followed by a string",
1033 flagcode_unparse (opt)));
1043 else /* its a filename */
1045 DPRINTF (("Adding filename: %s", thisarg));
1046 fl = cstringSList_add (fl, cstring_fromChars (thisarg));
1054 ** create lists of C and LCL files
1057 cstringSList_elements (fl, current)
1059 cstring ext = fileLib_getExtension (current);
1061 if (cstring_isUndefined (ext))
1063 /* no extension --- both C and LCL with default extensions */
1065 addFile (cfiles, message ("%s%s", current, C_EXTENSION));
1066 addFile (lclfiles, message ("%s%s", current, LCL_EXTENSION));
1068 else if (cstring_equal (ext, XH_EXTENSION))
1070 addXHFile (xfiles, cstring_copy (current));
1072 else if (cstring_equal (ext, LCL_EXTENSION))
1074 addFile (lclfiles, cstring_copy (current));
1076 else if (fileLib_isCExtension (ext))
1078 addFile (cfiles, cstring_copy (current));
1080 else if (cstring_equal (ext, MTS_EXTENSION))
1082 addFile (mtfiles, cstring_copy (current));
1087 (FLG_FILEEXTENSIONS,
1088 message ("Unrecognized file extension: %s (assuming %s is C source code)",
1092 addFile (cfiles, cstring_copy (current));
1094 } end_cstringSList_elements;
1096 showHerald (); /*@i723 move earlier? */
1104 fprintf (g_msgstream, "\n");
1106 fileIdList_free (cfiles);
1107 fileIdList_free (xfiles);
1108 fileIdList_free (lclfiles);
1117 inittime = clock ();
1119 context_resetErrors ();
1120 context_clearInCommandLine ();
1122 anylcl = !fileIdList_isEmpty (lclfiles);
1124 if (context_doMerge ())
1126 cstring m = context_getMerge ();
1128 if (context_getFlag (FLG_SHOWSCAN))
1130 fprintf (g_msgstream, "< loading %s ", cstring_toCharsSafe (m));
1135 if (context_getFlag (FLG_SHOWSCAN))
1137 fprintf (g_msgstream, " >\n");
1140 if (!usymtab_existsType (context_getBoolName ()))
1142 usymtab_initBool ();
1147 if (!context_getFlag (FLG_NOLIB) && loadStandardState ())
1156 /* setup bool type and constants */
1157 usymtab_initBool ();
1160 fileloc_free (g_currentloc);
1161 g_currentloc = fileloc_createBuiltin ();
1164 ** Read metastate files (must happen before loading libraries)
1167 fileIdList_elements (mtfiles, mtfile)
1169 context_setFileId (mtfile);
1171 if (context_getFlag (FLG_SHOWSCAN))
1173 lldiagmsg (message ("< processing %s >", rootFileName (mtfile)));
1176 mtreader_readFile (cstring_copy (fileName (mtfile)));
1177 } end_fileIdList_elements;
1184 llfatalerror (cstring_makeLiteral ("This version of LCLint does not handle LCL files."));
1186 lslProcess (lclfiles);
1190 usymtab_initGlobalMarker ();
1195 ** call the pre-preprocessor and /lib/cpp to generate appropriate
1200 context_setInCommandLine ();
1202 DPRINTF (("Pass through: %s", cstringSList_unparse (passThroughArgs)));
1204 cstringSList_elements (passThroughArgs, thisarg) {
1205 handlePassThroughFlag (cstring_toCharsSafe (thisarg));
1206 } end_cstringSList_elements;
1208 cstringSList_free (passThroughArgs);
1212 DPRINTF (("Initializing cpp reader!"));
1213 cppReader_initialize ();
1214 cppReader_saveDefinitions ();
1216 context_clearInCommandLine ();
1218 if (!context_getFlag (FLG_NOPP))
1224 if (context_getFlag (FLG_SHOWSCAN))
1226 fprintf (stderr, "< preprocessing");
1231 context_setPreprocessing ();
1232 dercfiles = preprocessFiles (xfiles, TRUE);
1233 tfiles = preprocessFiles (cfiles, FALSE);
1234 dercfiles = fileIdList_append (dercfiles, tfiles);
1235 fileIdList_free (tfiles);
1237 context_clearPreprocessing ();
1239 fileIdList_free (cfiles);
1241 if (context_getFlag (FLG_SHOWSCAN))
1243 fprintf (stderr, " >\n");
1251 dercfiles = fileIdList_append (cfiles, xfiles);
1256 ** now, check all the corresponding C files
1258 ** (for now these are just <file>.c, but after pre-processing
1259 ** will be <tmpprefix>.<file>.c)
1264 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1268 llbug (message ("Files unclosed: %d", nfiles));
1273 DPRINTF (("Initializing..."));
1275 exprNode_initMod ();
1277 DPRINTF (("Okay..."));
1279 fileIdList_elements (dercfiles, fid)
1281 sourceFile = inputStream_create (cstring_copy (fileName (fid)), C_EXTENSION, TRUE);
1282 context_setFileId (fid);
1284 /* Open source file */
1286 if (inputStream_isUndefined (sourceFile) || (!inputStream_open (sourceFile)))
1288 /* previously, this was ignored ?! */
1289 llbug (message ("Could not open temp file: %s", fileName (fid)));
1293 yyin = inputStream_getFile (sourceFile); /*< shared <- only */
1295 llassert (yyin != NULL);
1297 if (context_getFlag (FLG_SHOWSCAN))
1299 lldiagmsg (message ("< checking %s >", rootFileName (fid)));
1303 ** Every time, except the first time, through the loop,
1304 ** need to call yyrestart to clean up the parse buffer.
1309 (void) yyrestart (yyin);
1316 DPRINTF (("Entering..."));
1317 context_enterFile ();
1319 context_exitCFile ();
1321 (void) inputStream_close (sourceFile);
1323 } end_fileIdList_elements;
1327 /* process any leftover macros */
1329 context_processAllMacros ();
1331 /* check everything that was specified was defined */
1333 /* don't check if no c files were processed ?
1334 ** is this correct behaviour?
1337 if (context_getFlag (FLG_SHOWSCAN))
1339 lldiagmsg (cstring_makeLiteral ("< global checks >"));
1344 if (context_getLinesProcessed () > 0)
1346 usymtab_allDefined ();
1349 if (context_maybeSet (FLG_TOPUNUSED))
1351 uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main"));
1353 if (uentry_isValid (ue))
1355 uentry_setUsed (ue, fileloc_observeBuiltin ());
1361 if (context_maybeSet (FLG_EXPORTLOCAL))
1363 usymtab_exportLocal ();
1367 if (context_maybeSet (FLG_EXPORTHEADER))
1369 usymtab_exportHeader ();
1372 if (context_getFlag (FLG_SHOWUSES))
1374 usymtab_displayAllUses ();
1377 context_checkSuppressCounts ();
1379 if (context_doDump ())
1381 cstring dump = context_getDump ();
1392 if (context_getFlag (FLG_SHOWSUMMARY))
1399 bool isQuiet = context_getFlag (FLG_QUIET);
1400 cstring specErrors = cstring_undefined;
1402 int nspecErrors = lclNumberErrors ();
1407 if (context_neednl ())
1408 fprintf (g_msgstream, "\n");
1411 if (nspecErrors > 0)
1413 if (nspecErrors == context_getLCLExpect ())
1416 message ("%d spec error%& found, as expected\n ",
1421 if (context_getLCLExpect () > 0)
1424 message ("%d spec error%& found, expected %d\n ",
1426 (int) context_getLCLExpect ());
1430 specErrors = message ("%d spec error%& found\n ",
1438 if (context_getLCLExpect () > 0)
1440 specErrors = message ("No spec errors found, expected %d\n ",
1441 (int) context_getLCLExpect ());
1447 if (context_anyErrors ())
1449 if (context_numErrors () == context_getExpect ())
1452 llmsg (message ("Finished LCLint checking --- "
1453 "%s%d code error%& found, as expected",
1454 specErrors, context_numErrors ()));
1459 if (context_getExpect () > 0)
1463 ("Finished LCLint checking --- "
1464 "%s%d code error%& found, expected %d",
1465 specErrors, context_numErrors (),
1466 (int) context_getExpect ()));
1476 llmsg (message ("Finished LCLint checking --- "
1477 "%s%d code error%& found",
1478 specErrors, context_numErrors ()));
1487 if (context_getExpect () > 0)
1491 ("Finished LCLint checking --- "
1492 "%sno code errors found, expected %d",
1494 (int) context_getExpect ()));
1501 if (context_getLinesProcessed () > 0)
1504 llmsg (message ("Finished LCLint checking --- %sno code errors found",
1511 llmsg (message ("Finished LCLint checking --- %sno code processed",
1518 cstring_free (specErrors);
1521 if (context_getFlag (FLG_STATS))
1523 clock_t ttime = clock () - before;
1524 int specLines = context_getSpecLinesProcessed ();
1530 fprintf (g_msgstream, "%d spec, ", specLines);
1533 # ifndef CLOCKS_PER_SEC
1534 fprintf (g_msgstream, "%d source lines in %ld time steps (steps/sec unknown)\n",
1535 context_getLinesProcessed (),
1538 fprintf (g_msgstream, "%d source lines in %.2f s.\n",
1539 context_getLinesProcessed (),
1540 (double) ttime / CLOCKS_PER_SEC);
1548 if (context_getFlag (FLG_TIMEDIST))
1550 clock_t ttime = clock () - before;
1554 char *msg = (char *) dmalloc (256 * sizeof (*msg));
1559 "Time distribution (percent): initialize %.2f / lcl %.2f / "
1560 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1561 (100.0 * (double) (libtime - before) / ttime),
1562 (100.0 * (double) (lcltime - libtime) / ttime),
1563 (100.0 * (double) (pptime - lcltime) / ttime),
1564 (100.0 * (double) (cptime - pptime) / ttime),
1565 (100.0 * (double) (rstime - cptime) / ttime));
1570 "Time distribution (percent): initialize %.2f / "
1571 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1572 (100.0 * (double) (libtime - before) / ttime),
1573 (100.0 * (double) (pptime - libtime) / ttime),
1574 (100.0 * (double) (cptime - pptime) / ttime),
1575 (100.0 * (double) (rstime - cptime) / ttime));
1578 llgenindentmsgnoloc (cstring_fromCharsO (msg));
1582 llexit (expsuccess ? LLSUCCESS : LLFAILURE);
1587 ** Reenable return value warnings.
1589 # pragma warning (default:4035)
1597 llmsg (message ("Source files are .c, .h and %s files. If there is no suffix,",
1599 llmsg (message (" LCLint will look for <file>.c and <file>%s.", LCL_EXTENSION));
1601 llmsglit ("Use lclint -help <topic or flag name> for more information");
1603 llmsglit ("Topics:");
1605 llmsglit (" annotations (describes source-code annotations)");
1606 llmsglit (" comments (describes control comments)");
1607 llmsglit (" flags (describes flag categories)");
1608 llmsglit (" flags <category> (describes flags in category)");
1609 llmsglit (" flags all (short description of all flags)");
1610 llmsglit (" flags alpha (list all flags alphabetically)");
1611 llmsglit (" flags full (full description of all flags)");
1612 llmsglit (" mail (information on mailing lists)");
1613 llmsglit (" modes (show mode settings)");
1614 llmsglit (" parseerrors (help on handling parser errors)");
1615 llmsglit (" prefixcodes (character codes in namespace prefixes)");
1616 llmsglit (" references (sources for more information)");
1617 llmsglit (" vars (environment variables)");
1618 llmsglit (" version (information on compilation, maintainer)");
1623 specialFlagsHelp (char *next)
1625 if ((next != NULL) && (*next != '-') && (*next != '+'))
1627 if (mstring_equal (next, "alpha"))
1632 else if (mstring_equal (next, "all"))
1634 printAllFlags (TRUE, FALSE);
1637 else if (mstring_equal (next, "categories")
1638 || mstring_equal (next, "cats"))
1640 listAllCategories ();
1643 else if (mstring_equal (next, "full"))
1645 printAllFlags (FALSE, TRUE);
1660 printParseErrors (void)
1662 llmsglit ("Parse Errors");
1663 llmsglit ("------------");
1665 llmsglit ("LCLint will sometimes encounter a parse error for code that "
1666 "can be parsed with a local compiler. There are a few likely "
1667 "causes for this and a number of techniques that can be used "
1668 "to work around the problem.");
1670 llmsglit ("Compiler extensions --- compilers sometimes extend the C "
1671 "language with compiler-specific keywords and syntax. While "
1672 "it is not advisible to use these, oftentimes one has no choice "
1673 "when the system header files use compiler extensions. ");
1675 llmsglit ("LCLint supports some of the GNU (gcc) compiler extensions, "
1676 "if the +gnuextensions flag is set. You may be able to workaround "
1677 "other compiler extensions by using a pre-processor define. "
1678 "Alternately, you can surround the unparseable code with");
1680 llmsglit (" # ifndef __LCLINT__");
1682 llmsglit (" # endif");
1684 /* evans 2000-12-21 fixed typo reported by Jeroen Ruigrok/Asmodai */
1685 llmsglit ("Missing type definitions --- an undefined type name will usually "
1686 "lead to a parse error. This often occurs when a standard header "
1687 "file defines some type that is not part of the standard library. ");
1688 llmsglit ("By default, LCLint does not process the local files corresponding "
1689 "to standard library headers, but uses a library specification "
1690 "instead so dependencies on local system headers can be detected. "
1691 "If another system header file that does not correspond to a "
1692 "standard library header uses one of these superfluous types, "
1693 "a parse error will result.");
1695 llmsglit ("If the parse error is inside a posix standard header file, the "
1696 "first thing to try is +posixlib. This make LCLint use "
1697 "the posix library specification instead of reading the posix "
1700 llmsglit ("Otherwise, you may need to either manually define the problematic "
1701 "type (e.g., add -Dmlink_t=int to your .lclintrc file) or force "
1702 "lclint to process the header file that defines it. This is done "
1703 "by setting -skipansiheaders or -skipposixheaders before "
1704 "the file that defines the type is #include'd.");
1705 llmsglit ("(See lclint -help "
1706 "skipansiheaders and lclint -help skipposixheaders for a list of "
1707 "standard headers.) For example, if <sys/local.h> uses a type "
1708 "defined by posix header <sys/types.h> but not defined by the "
1709 "posix library, we might do: ");
1711 llmsglit (" /*@-skipposixheaders@*/");
1712 llmsglit (" # include <sys/types.h>");
1713 llmsglit (" /*@=skipposixheaders@*/");
1714 llmsglit (" # include <sys/local.h>");
1716 llmsglit ("to force LCLint to process <sys/types.h>.");
1718 llmsglit ("At last resort, +trytorecover can be used to make LCLint attempt "
1719 "to continue after a parse error. This is usually not successful "
1720 "and the author does not consider assertion failures when +trytorecover "
1721 "is used to be bugs.");
1725 printAnnotations (void)
1727 llmsglit ("Annotations");
1728 llmsglit ("-----------");
1730 llmsglit ("Annotations are semantic comments that document certain "
1731 "assumptions about functions, variables, parameters, and types. ");
1733 llmsglit ("They may be used to indicate where the representation of a "
1734 "user-defined type is hidden, to limit where a global variable may "
1735 "be used or modified, to constrain what a function implementation "
1736 "may do to its parameters, and to express checked assumptions about "
1737 "variables, types, structure fields, function parameters, and "
1738 "function results.");
1740 llmsglit ("Annotations are introduced by \"/*@\". The role of the @ may be "
1741 "played by any printable character, selected using -commentchar <char>.");
1743 llmsglit ("Consult the User's Guide for descriptions of checking associated with each annotation.");
1745 llmsglit ("Globals: (in function declarations)");
1746 llmsglit (" /*@globals <globitem>,+ @*/");
1747 llmsglit (" globitem is an identifier, internalState or fileSystem");
1749 llmsglit ("Modifies: (in function declarations)");
1750 llmsglit (" /*@modifies <moditem>,+ @*/");
1751 llmsglit (" moditem is an lvalue");
1752 llmsglit (" /*@modifies nothing @*/");
1753 llmsglit (" /*@*/ (Abbreviation for no globals and modifies nothing.)");
1755 llmsglit ("Iterators:");
1756 llmsglit (" /*@iter <identifier> (<parameter-type-list>) @*/ - declare an iterator");
1758 llmsglit ("Constants:");
1759 llmsglit (" /*@constant <declaration> @*/ - declares a constant");
1761 llmsglit ("Alternate Types:");
1762 llmsglit (" /*@alt <basic-type>,+ @*/");
1763 llmsglit (" (e.g., int /*@alt char@*/ is a type matching either int or char)");
1765 llmsglit ("Declarator Annotations");
1767 llmsglit ("Type Definitions:");
1768 llmsglit (" /*@abstract@*/ - representation is hidden from clients");
1769 llmsglit (" /*@concrete@*/ - representation is visible to clients");
1770 llmsglit (" /*@immutable@*/ - instances of the type cannot change value");
1771 llmsglit (" /*@mutable@*/ - instances of the type can change value");
1772 llmsglit (" /*@refcounted@*/ - reference counted type");
1774 llmsglit ("Global Variables:");
1775 llmsglit (" /*@unchecked@*/ - weakest checking for global use");
1776 llmsglit (" /*@checkmod@*/ - check modification by not use of global");
1777 llmsglit (" /*@checked@*/ - check use and modification of global");
1778 llmsglit (" /*@checkedstrict@*/ - check use of global strictly");
1780 llmsglit ("Memory Management:");
1781 llmsglit (" /*@dependent@*/ - a reference to externally-owned storage");
1782 llmsglit (" /*@keep@*/ - a parameter that is kept by the called function");
1783 llmsglit (" /*@killref@*/ - a refcounted parameter, killed by the call");
1784 llmsglit (" /*@only@*/ - an unshared reference");
1785 llmsglit (" /*@owned@*/ - owner of storage that may be shared by /*@dependent@*/ references");
1786 llmsglit (" /*@shared@*/ - shared reference that is never deallocated");
1787 llmsglit (" /*@temp@*/ - temporary parameter");
1789 llmsglit ("Aliasing:");
1790 llmsglit (" /*@unique@*/ - may not be aliased by any other visible reference");
1791 llmsglit (" /*@returned@*/ - may be aliased by the return value");
1793 llmsglit ("Exposure:");
1794 llmsglit (" /*@observer@*/ - reference that cannot be modified");
1795 llmsglit (" /*@exposed@*/ - exposed reference to storage in another object");
1797 llmsglit ("Definition State:");
1798 llmsglit (" /*@out@*/ - storage reachable from reference need not be defined");
1799 llmsglit (" /*@in@*/ - all storage reachable from reference must be defined");
1800 llmsglit (" /*@partial@*/ - partially defined, may have undefined fields");
1801 llmsglit (" /*@reldef@*/ - relax definition checking");
1803 llmsglit ("Global State: (for globals lists, no /*@, since list is already in /*@\'s)");
1804 llmsglit (" undef - variable is undefined before the call");
1805 llmsglit (" killed - variable is undefined after the call");
1807 llmsglit ("Null State:");
1808 llmsglit (" /*@null@*/ - possibly null pointer");
1809 llmsglit (" /*@notnull@*/ - non-null pointer");
1810 llmsglit (" /*@relnull@*/ - relax null checking");
1812 llmsglit ("Null Predicates:");
1813 llmsglit (" /*@truenull@*/ - if result is TRUE, first parameter is NULL");
1814 llmsglit (" /*@falsenull@*/ - if result is TRUE, first parameter is not NULL");
1816 llmsglit ("Execution:");
1817 llmsglit (" /*@exits@*/ - function never returns");
1818 llmsglit (" /*@mayexit@*/ - function may or may not return");
1819 llmsglit (" /*@trueexit@*/ - function does not return if first parameter is TRUE");
1820 llmsglit (" /*@falseexit@*/ - function does not return if first parameter if FALSE");
1821 llmsglit (" /*@neverexit@*/ - function always returns");
1823 llmsglit ("Side-Effects:");
1824 llmsglit (" /*@sef@*/ - corresponding actual parameter has no side effects");
1826 llmsglit ("Declaration:");
1827 llmsglit (" /*@unused@*/ - need not be used (no unused errors reported)");
1828 llmsglit (" /*@external@*/ - defined externally (no undefined error reported)");
1831 llmsglit (" /*@fallthrough@*/ - fall-through case");
1833 llmsglit ("Break:");
1834 llmsglit (" /*@innerbreak@*/ - break is breaking an inner loop or switch");
1835 llmsglit (" /*@loopbreak@*/ - break is breaking a loop");
1836 llmsglit (" /*@switchbreak@*/ - break is breaking a switch");
1837 llmsglit (" /*@innercontinue@*/ - continue is continuing an inner loop");
1839 llmsglit ("Unreachable Code:");
1840 llmsglit (" /*@notreached@*/ - statement may be unreachable.");
1842 llmsglit ("Special Functions:");
1843 llmsglit (" /*@printflike@*/ - check variable arguments like printf");
1844 llmsglit (" /*@scanflike@*/ - check variable arguments like scanf");
1848 printComments (void)
1850 llmsglit ("Control Comments");
1851 llmsglit ("----------------");
1853 llmsglit ("Setting Flags");
1855 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.");
1857 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,");
1858 llmsglit (" /*@+boolint -modifies =showfunc@*/");
1859 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).");
1861 llmsglit ("Error Suppression");
1863 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.");
1865 llmsglit ("/*@ignore@*/ ... /*@end@*/");
1867 (cstring_makeLiteral
1868 ("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."));
1869 llmsglit ("/*@i@*/");
1871 (cstring_makeLiteral
1872 ("No errors will be reported from an /*@i@*/ comment to the end of the line."));
1873 llmsglit ("/*@i<n>@*/");
1875 (cstring_makeLiteral
1876 ("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."));
1877 llmsglit ("/*@t@*/, /*@t<n>@*/");
1879 (cstring_makeLiteral
1880 ("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."));
1882 llmsglit ("Type Access");
1884 llmsglit ("/*@access <type>@*/");
1885 llmsglit (" Allows the following code to access the representation of <type>");
1886 llmsglit ("/*@noaccess <type>@*/");
1887 llmsglit (" Hides the representation of <type>");
1889 llmsglit ("Macro Expansion");
1891 llmsglit ("/*@notfunction@*/");
1893 (cstring_makeLiteral
1894 ("Indicates that the next macro definition is not intended to be a "
1895 "function, and should be expanded in line instead of checked as a "
1896 "macro function definition."));
1903 llmsglit ("Flag Categories");
1904 llmsglit ("---------------");
1905 listAllCategories ();
1906 llmsglit ("\nTo see the flags in a flag category, do\n lclint -help flags <category>");
1907 llmsglit ("To see a list of all flags in alphabetical order, do\n lclint -help flags alpha");
1908 llmsglit ("To see a full description of all flags, do\n lclint -help flags full");
1912 printMaintainer (void)
1914 llmsg (message ("Maintainer: %s", cstring_makeLiteralTemp (LCLINT_MAINTAINER)));
1915 llmsglit (LCL_COMPILE);
1921 llmsglit ("Mailing Lists");
1922 llmsglit ("-------------");
1924 llmsglit ("There are two mailing lists associated with LCLint: ");
1926 llmsglit (" lclint-announce@virginia.edu");
1928 llmsglit (" Reserved for announcements of new releases and bug fixes.");
1929 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
1930 llmsglit (" subscribe lclint-announce");
1932 llmsglit (" lclint-interest@virginia.edu");
1934 llmsglit (" Informal discussions on the use and development of lclint.");
1935 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
1936 llmsglit (" subscribe lclint-interest");
1940 printReferences (void)
1942 llmsglit ("References");
1943 llmsglit ("----------");
1945 llmsglit ("The LCLint web site is http://lclint.cs.virginia.edu");
1947 llmsglit ("Technical papers relating to LCLint include:");
1949 llmsglit (" David Evans. \"Static Detection of Dynamic Memory Errors\".");
1950 llmsglit (" SIGPLAN Conference on Programming Language Design and ");
1951 llmsglit (" Implementation (PLDI '96), Philadelphia, PA, May 1996.");
1953 llmsglit (" David Evans, John Guttag, Jim Horning and Yang Meng Tan. ");
1954 llmsglit (" \"LCLint: A Tool for Using Specifications to Check Code\".");
1955 llmsglit (" SIGSOFT Symposium on the Foundations of Software Engineering,");
1956 llmsglit (" December 1994.");
1958 llmsglit ("A general book on Larch is:");
1960 llmsglit (" Guttag, John V., Horning, James J., (with Garland, S. J., Jones, ");
1961 llmsglit (" K. D., Modet, A., and Wing, J. M.), \"Larch: Languages and Tools ");
1962 llmsglit (" for Formal Specification\", Springer-Verlag, 1993.");
1966 describePrefixCodes (void)
1968 llmsglit ("Prefix Codes");
1969 llmsglit ("------------");
1971 llmsglit ("These characters have special meaning in name prefixes:");
1973 llmsg (message (" %h Any uppercase letter [A-Z]", PFX_UPPERCASE));
1974 llmsg (message (" %h Any lowercase letter [a-z]", PFX_LOWERCASE));
1975 llmsg (message (" %h Any character (valid in a C identifier)", PFX_ANY));
1976 llmsg (message (" %h Any digit [0-9]", PFX_DIGIT));
1977 llmsg (message (" %h Any non-uppercase letter [a-z0-9_]", PFX_NOTUPPER));
1978 llmsg (message (" %h Any non-lowercase letter [A-Z0-9_]", PFX_NOTLOWER));
1979 llmsg (message (" %h Any letter [A-Za-z]", PFX_ANYLETTER));
1980 llmsg (message (" %h Any letter or digit [A-Za-z0-9]", PFX_ANYLETTERDIGIT));
1981 llmsglit (" * Zero or more repetitions of the previous character class until the end of the name");
1990 eval = context_getLarchPath ();
1991 def = osd_getEnvironmentVariable (LARCH_PATH);
1993 if (cstring_isDefined (def) ||
1994 !cstring_equal (eval, cstring_fromChars (DEFAULT_LARCHPATH)))
1996 llmsg (message ("LARCH_PATH = %s", eval));
2000 llmsg (message ("LARCH_PATH = <not set> (default = %s)",
2001 cstring_fromChars (DEFAULT_LARCHPATH)));
2004 llmsglit (" --- path used to find larch initialization files and LSL traits");
2006 eval = context_getLCLImportDir ();
2007 def = osd_getEnvironmentVariable (cstring_makeLiteralTemp (LCLIMPORTDIR));
2009 if (cstring_isDefined (def) ||
2010 !cstring_equal (eval, cstring_fromChars (DEFAULT_LCLIMPORTDIR)))
2012 llmsg (message ("%q = %s", cstring_makeLiteral (LCLIMPORTDIR), eval));
2016 llmsg (message ("%s = <not set, default: %s>", cstring_makeLiteralTemp (LCLIMPORTDIR),
2017 cstring_makeLiteralTemp (DEFAULT_LCLIMPORTDIR)));
2020 llmsglit (" --- directory containing lcl standard library files "
2021 "(import with < ... >)");;
2024 ("include path = %q (set by environment variable %s and -I flags)",
2025 cppReader_getIncludePath (), INCLUDEPATH_VAR));
2027 llmsglit (" --- path used to find #include'd files");
2030 ("systemdirs = %s (set by -systemdirs or envirnoment variable %s)", /*@i413223@*/
2031 context_getString (FLG_SYSTEMDIRS),
2034 llmsglit (" --- if file is found on this path, it is treated as a system file for error reporting");
2043 fprintf (stderr, "*** Interrupt\n");
2044 llexit (LLINTERRUPT);
2049 /* Cheat when there are parse errors */
2052 fprintf (stderr, "*** Segmentation Violation\n");
2054 /* Don't catch it if fileloc_unparse causes a signal */
2055 (void) signal (SIGSEGV, NULL);
2057 loc = fileloc_unparse (g_currentloc);
2059 fprintf (stderr, "*** Location (not trusted): %s\n",
2060 cstring_toCharsSafe (loc));
2063 fprintf (stderr, "*** Please report bug to %s\n", LCLINT_MAINTAINER);
2067 fprintf (stderr, "*** Signal: %d\n", i);
2069 fprintf (stderr, "*** Location (not trusted): %s\n",
2070 cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
2073 fprintf (stderr, "*** Please report bug to %s ***\n", LCLINT_MAINTAINER);
2081 static bool doneCleanup = FALSE;
2083 /* make sure this is only called once! */
2085 if (doneCleanup) return;
2089 if (context_getFlag (FLG_KEEP))
2091 check (fputs ("Temporary files kept:\n", stderr) != EOF);
2092 fileTable_printTemps (context_fileTable ());
2097 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
2101 llbug (message ("Files unclosed: %d", nfiles));
2104 fileTable_cleanup (context_fileTable ());
2111 ** cleans up temp files (if necessary)
2118 DPRINTF (("llexit: %d", status));
2121 if (status == LLFAILURE)
2129 if (status != LLFAILURE)
2131 context_destroyMod ();
2132 exprNode_destroyMod ();
2135 uentry_destroyMod ();
2136 typeIdSet_destroyMod ();
2139 dmalloc_shutdown ();
2143 exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
2147 loadrc (/*:open:*/ FILE *rcfile, cstringSList *passThroughArgs)
2148 /*@ensures closed rcfile@*/
2150 char *s = mstring_create (MAX_LINE_LENGTH);
2153 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2157 while (reader_readLine (rcfile, s, MAX_LINE_LENGTH) != NULL)
2164 DPRINTF (("Line: %s", s));
2165 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2167 while (*s == ' ' || *s == '\t')
2175 bool escaped = FALSE;
2176 bool quoted = FALSE;
2179 DPRINTF (("Process: %s", s));
2180 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2181 /* comment characters */
2182 if (c == '#' || c == ';' || c == '\n')
2188 if (c == '-' || c == '+')
2195 voptgenerror (FLG_BADFLAG,
2196 message ("Bad flag syntax (+ or - expected, "
2197 "+ is assumed): %s",
2198 cstring_fromChars (s)),
2209 while ((c = *s) != '\0')
2210 { /* remember to handle spaces and quotes in -D and -U ... */
2236 if (c == ' ' || c == '\t' || c == '\n')
2238 /*@innerbreak@*/ break;
2246 DPRINTF (("Nulling: %c", *s));
2249 if (mstring_isEmpty (thisflag))
2251 llfatalerror (message ("Missing flag: %s",
2252 cstring_fromChars (os)));
2255 DPRINTF (("Flag: %s", thisflag));
2257 opt = identifyFlag (cstring_fromChars (thisflag));
2259 if (flagcode_isSkip (opt))
2263 else if (flagcode_isInvalid (opt))
2265 DPRINTF (("Invalid: %s", thisflag));
2267 if (isMode (cstring_fromChars (thisflag)))
2269 context_setMode (cstring_fromChars (thisflag));
2273 voptgenerror (FLG_BADFLAG,
2274 message ("Unrecognized option: %s",
2275 cstring_fromChars (thisflag)),
2281 context_userSetFlag (opt, set);
2283 if (flagcode_hasArgument (opt))
2285 if (opt == FLG_HELP)
2288 voptgenerror (FLG_BADFLAG,
2289 message ("Cannot use help in rc files"),
2292 else if (flagcode_isPassThrough (opt)) /* -D or -U */
2294 cstring arg = cstring_fromCharsNew (thisflag);
2295 cstring_markOwned (arg);
2296 *passThroughArgs = cstringSList_add (*passThroughArgs, arg);
2297 DPRINTF (("Pass through: %s",
2298 cstringSList_unparse (*passThroughArgs)));
2300 else if (opt == FLG_INCLUDEPATH
2301 || opt == FLG_SPECPATH)
2303 cstring dir = cstring_suffix (cstring_fromChars (thisflag), 1); /* skip over I/S */
2307 case FLG_INCLUDEPATH:
2308 cppAddIncludeDir (dir);
2309 /*@switchbreak@*/ break;
2312 g_localSpecPath = cstring_toCharsSafe
2313 (message ("%s:%s", cstring_fromChars (g_localSpecPath), dir));
2315 /*@switchbreak@*/ break;
2319 else if (flagcode_hasString (opt)
2320 || flagcode_hasValue (opt)
2321 || opt == FLG_INIT || opt == FLG_OPTF)
2323 cstring extra = cstring_undefined;
2328 rest = mstring_copy (s);
2329 DPRINTF (("Here: rest = %s", rest));
2333 while ((rchar = *rest) != '\0'
2334 && (isspace ((int) rchar)))
2340 DPRINTF (("Yo: %s", rest));
2342 while ((rchar = *rest) != '\0'
2343 && !isspace ((int) rchar))
2345 extra = cstring_appendChar (extra, rchar);
2350 DPRINTF (("Yo: %s", extra));
2353 if (cstring_isUndefined (extra))
2359 ("Flag %s must be followed by an argument",
2360 flagcode_unparse (opt)),
2367 DPRINTF (("Here we are: %s", extra));
2369 if (flagcode_hasValue (opt))
2371 DPRINTF (("Set value flag: %s", extra));
2372 setValueFlag (opt, extra);
2373 cstring_free (extra);
2375 else if (opt == FLG_OPTF)
2377 FILE *innerf = fopen (cstring_toCharsSafe (extra), "r");
2378 cstring_markOwned (extra);
2382 fileloc fc = g_currentloc;
2383 g_currentloc = fileloc_createRc (extra);
2384 loadrc (innerf, passThroughArgs);
2385 fileloc_reallyFree (g_currentloc);
2393 message ("Options file not found: %s",
2398 else if (opt == FLG_INIT)
2401 llassert (inputStream_isUndefined (initFile));
2403 initFile = inputStream_create
2405 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
2408 cstring_free (extra);
2411 else if (flagcode_hasString (opt))
2413 if (cstring_firstChar (extra) == '"')
2415 if (cstring_lastChar (extra) == '"')
2417 char *extras = cstring_toCharsSafe (extra);
2419 llassert (extras[strlen(extras) - 1] == '"');
2420 extras[strlen(extras) - 1] = '\0';
2421 extra = cstring_fromChars (extras + 1);
2422 DPRINTF (("Remove quites: %s", extra));
2428 message ("Unmatched \" in option string: %s",
2434 setStringFlag (opt, extra);
2438 cstring_free (extra);
2451 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2452 while ((c == ' ') || (c == '\t'))
2458 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2462 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2464 check (fclose (rcfile) == 0);
2467 static fileIdList preprocessFiles (fileIdList fl, bool xhfiles)
2468 /*@modifies fileSystem@*/
2470 bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
2471 int skip = (fileIdList_size (fl) / 5);
2472 int filesprocessed = 0;
2473 fileIdList dfiles = fileIdList_create ();
2475 fileloc_free (g_currentloc);
2476 g_currentloc = fileloc_createBuiltin ();
2478 fileIdList_elements (fl, fid)
2480 cstring ppfname = fileName (fid);
2486 if (osd_findOnLarchPath (ppfname, &fpath) == OSD_FILEFOUND)
2488 if (cstring_equal (ppfname, fpath))
2494 DPRINTF (("xh file: %s", fpath));
2496 fileTable_setFilePath (context_fileTable (), fid, fpath);
2501 lldiagmsg (message ("Cannot find .xh file on LARCH_PATH: %s", ppfname));
2502 lldiagmsg (cstring_makeLiteral (" Check LARCH_PATH environment variable."));
2503 ppfname = cstring_undefined;
2508 if (!(osd_fileIsReadable (ppfname)))
2510 lldiagmsg (message ("Cannot open file: %s", ppfname));
2511 ppfname = cstring_undefined;
2515 if (cstring_isDefined (ppfname))
2517 fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
2519 llassert (cstring_isNonEmpty (ppfname));
2523 if ((filesprocessed % skip) == 0)
2525 if (filesprocessed == 0) {
2526 fprintf (stderr, " ");
2529 fprintf (stderr, ".");
2532 (void) fflush (stderr);
2537 if (cppProcess (ppfname, fileName (dfile)) != 0)
2539 llfatalerror (message ("Preprocessing error for file: %s",
2540 rootFileName (fid)));
2543 fileIdList_add (dfiles, dfile);
2545 } end_fileIdList_elements;
2550 /* This should be in an lclUtils.c file... */
2552 char *specFullName (char *specfile, /*@out@*/ char **inpath)
2554 /* extract the path and the specname associated with the given file */
2555 char *specname = (char *) dmalloc (sizeof (*specname)
2556 * (strlen (specfile) + 9));
2557 char *ospecname = specname;
2558 char *path = (char *) dmalloc (sizeof (*path) * (strlen (specfile)));
2562 /* initialized path to empty string or may have accidental garbage */
2565 /*@-mayaliasunique@*/
2566 strcpy (specname, specfile);
2567 /*@=mayaliasunique@*/
2569 /* trim off pathnames in specfile */
2570 size = strlen (specname);
2572 for (i = size_toInt (size) - 1; i >= 0; i--)
2574 if (specname[i] == CONNECTCHAR)
2576 /* strcpy (specname, (char *)specname+i+1); */
2577 for (j = 0; j <= i; j++) /* include '/' */
2579 path[j] = specname[j];
2589 ** also remove .lcl file extension, assume it's the last extension
2593 size = strlen (specname);
2595 for (i = size_toInt (size) - 1; i >= 0; i--)
2597 if (specname[i] == '.')
2607 ** If specname no longer points to the original char,
2608 ** we need to allocate a new pointer and copy the string.
2611 if (specname != ospecname) {
2612 char *rspecname = (char *) dmalloc (sizeof (*rspecname) * (strlen (specname) + 1));
2613 strcpy (rspecname, specname); /* evs 2000-05-16: Bug: was ospecname! */