3 ** LCLint - annotation-assisted static program checker
4 ** Copyright (C) 1994-2001 University of Virginia,
5 ** Massachusetts Institute of Technology
7 ** This program is free software; you can redistribute it and/or modify it
8 ** under the terms of the GNU General Public License as published by the
9 ** Free Software Foundation; either version 2 of the License, or (at your
10 ** option) any later version.
12 ** This program is distributed in the hope that it will be useful, but
13 ** WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 ** General Public License for more details.
17 ** The GNU General Public License is available from http://www.gnu.org/ or
18 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
19 ** MA 02111-1307, USA.
21 ** For information on lclint: lclint-request@cs.virginia.edu
22 ** To report a bug: lclint-bug@cs.virginia.edu
23 ** For more information: http://lclint.cs.virginia.edu
28 ** Main module for LCLint checker
34 ** Ensure that WIN32 and _WIN32 are both defined or both undefined.
39 # error "Inconsistent definitions."
43 # error "Inconsistent definitions."
52 # include "lclintMacros.nf"
59 # include "scanline.h"
60 # include "lclscanline.h"
61 # include "lclsyntable.h"
62 # include "lcltokentable.h"
63 # include "lslparse.h"
65 # include "syntable.h"
66 # include "tokentable.h"
75 # include "fileIdList.h"
77 # include "cgrammar.h"
82 extern /*@external@*/ int yydebug;
84 static void printMail (void);
85 static void printMaintainer (void);
86 static void printReferences (void);
87 static void printFlags (void);
88 static void printAnnotations (void);
89 static void printParseErrors (void);
90 static void printComments (void);
91 static void describePrefixCodes (void);
92 static void cleanupFiles (void);
93 static void showHelp (void);
94 static void interrupt (int p_i);
96 static void loadrc (/*@open@*/ FILE *p_rcfile, cstringSList *p_passThroughArgs)
97 /*@ensures closed p_rcfile@*/ ;
99 static void describeVars (void);
100 static bool specialFlagsHelp (char *p_next);
101 static bool hasShownHerald = FALSE;
102 static char *specFullName (char *p_specfile, /*@out@*/ char **p_inpath)
103 /*@modifies *p_inpath@*/ ;
105 static bool anylcl = FALSE;
106 static clock_t inittime;
108 static /*@only@*/ /*@null@*/ inputStream initFile = inputStream_undefined;
110 static fileIdList preprocessFiles (fileIdList, bool)
111 /*@modifies fileSystem@*/ ;
116 void lslCleanup (void)
117 /*@globals killed g_symtab@*/
118 /*@modifies internalState, g_symtab@*/
121 ** Cleanup all the LCL/LSL.
124 static bool didCleanup = FALSE;
126 llassert (!didCleanup);
131 lsymbol_destroyMod ();
132 LCLSynTableCleanup ();
133 LCLTokenTableCleanup ();
134 LCLScanLineCleanup ();
137 /* clean up LSL parsing */
140 ltokenTableCleanup ();
144 symtable_free (g_symtab);
150 /*@globals undef g_symtab; @*/
151 /*@modifies g_symtab, internalState, fileSystem; @*/
154 ** Open init file provided by user, or use the default LCL init file
157 cstring larchpath = context_getLarchPath ();
158 inputStream LSLinitFile = inputStream_undefined;
162 if (inputStream_isUndefined (initFile))
164 initFile = inputStream_create (cstring_makeLiteral (INITFILENAME),
165 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
168 if (!inputStream_getPath (larchpath, initFile))
170 lldiagmsg (message ("Continuing without LCL init file: %s",
171 inputStream_fileName (initFile)));
175 if (!inputStream_open (initFile))
177 lldiagmsg (message ("Continuing without LCL init file: %s",
178 inputStream_fileName (initFile)));
184 if (!inputStream_open (initFile))
186 lldiagmsg (message ("Continuing without LCL init file: %s",
187 inputStream_fileName (initFile)));
191 /* Initialize checker */
199 LCLTokenTableInit ();
211 /* need this to initialize LCL checker */
213 llassert (inputStream_isDefined (initFile));
214 if (inputStream_isOpen (initFile))
218 LCLScanReset (initFile);
219 LCLProcessInitFileInit ();
220 LCLProcessInitFileReset ();
223 LCLProcessInitFile ();
224 LCLProcessInitFileCleanup ();
227 check (inputStream_close (initFile));
230 /* Initialize LSL init files, for parsing LSL signatures from LSL */
232 LSLinitFile = inputStream_create (cstring_makeLiteral ("lslinit.lsi"),
233 cstring_makeLiteralTemp (".lsi"),
236 if (!inputStream_getPath (larchpath, LSLinitFile))
238 lldiagmsg (message ("Continuing without LSL init file: %s",
239 inputStream_fileName (LSLinitFile)));
243 if (!inputStream_open (LSLinitFile))
245 lldiagmsg (message ("Continuing without LSL init file: %s",
246 inputStream_fileName (LSLinitFile)));
262 if (inputStream_isOpen (LSLinitFile))
265 LSLScanReset (LSLinitFile);
266 LSLProcessInitFileInit ();
268 LSLProcessInitFile ();
270 check (inputStream_close (LSLinitFile));
273 inputStream_free (LSLinitFile);
278 (cstring_makeLiteral ("LSL init file error. Attempting to continue."));
282 g_symtab = symtable_new ();
285 ** sort_init must come after symtab has been initialized
294 ** Equivalent to importing old spec_csupport.lcl
295 ** define immutable LCL type "bool" and bool constants TRUE and FALSE
296 ** and initialized them to be equal to LSL's "true" and "false".
298 ** Reads in CTrait.syms (derived from CTrait.lsl) on LARCH_PATH.
302 LCLReportEolTokens (FALSE);
306 lslProcess (fileIdList lclfiles)
307 /*@globals undef g_currentSpec, undef g_currentSpecName, g_currentloc,
308 undef killed g_symtab; @*/
309 /*@modifies g_currentSpec, g_currentSpecName, g_currentloc, internalState, fileSystem; @*/
312 bool parser_status = FALSE;
313 bool overallStatus = FALSE;
317 context_resetSpecLines ();
319 fileIdList_elements (lclfiles, fid)
321 cstring actualName = cstring_undefined;
322 cstring fname = fileName (fid);
324 if (osd_getPath (cstring_fromChars (g_localSpecPath),
325 fname, &actualName) == OSD_FILENOTFOUND)
327 if (mstring_equal (g_localSpecPath, "."))
329 lldiagmsg (message ("Spec file not found: %s", fname));
333 lldiagmsg (message ("Spec file not found: %s (on %s)",
335 cstring_fromChars (g_localSpecPath)));
340 inputStream specFile;
342 char *namePtr = actualName;
344 while (*namePtr == '.' && *(namePtr + 1) == CONNECTCHAR)
348 /*@noaccess cstring@*/
350 g_currentSpec = cstring_fromCharsNew (namePtr);
352 specFile = inputStream_create (cstring_copy (g_currentSpec),
353 LCL_EXTENSION, TRUE);
355 llassert (inputStream_isDefined (specFile));
357 g_currentSpecName = specFullName
358 (cstring_toCharsSafe (g_currentSpec),
363 if (context_getFlag (FLG_SHOWSCAN))
365 lldiagmsg (message ("< reading spec %s >", g_currentSpec));
368 /* Open source file */
370 if (!inputStream_open (specFile))
372 lldiagmsg (message ("Cannot open file: %s",
373 inputStream_fileName (specFile)));
374 inputStream_free (specFile);
378 scopeInfo dummy_scope = (scopeInfo) dmalloc (sizeof (*dummy_scope));
379 dummy_scope->kind = SPE_INVALID;
382 LCLScanReset (specFile);
385 ** Minor hacks to allow more than one LCL file to
386 ** be scanned, while keeping initializations
389 symtable_enterScope (g_symtab, dummy_scope);
390 resetImports (cstring_fromChars (g_currentSpecName));
391 context_enterLCLfile ();
392 (void) lclHadNewError ();
394 parser_status = (ylparse () != 0);
395 context_exitLCLfile ();
397 overallStatus = parser_status || lclHadNewError ();
399 if (context_getFlag (FLG_DOLCS))
403 outputLCSFile (path, "%FAILED Output from ",
408 outputLCSFile (path, "%PASSED Output from ",
413 (void) inputStream_close (specFile);
414 inputStream_free (specFile);
416 symtable_exitScope (g_symtab);
419 cstring_free (actualName);
420 } end_fileIdList_elements;
422 /* Can cleanup lsl stuff right away */
426 g_currentSpec = cstring_undefined;
427 g_currentSpecName = NULL;
431 static void handlePassThroughFlag (char *arg)
434 char *quotechar = strchr (curarg, '\"');
437 char *freearg = NULL;
439 while (quotechar != NULL)
441 if (*(quotechar - 1) == '\\')
443 char *tp = quotechar - 2;
454 curarg = quotechar + 1;
455 quotechar = strchr (curarg, '\"');
460 llassert (quotechar != NULL);
462 offset = (quotechar - arg) + 2;
466 arg = cstring_toCharsSafe
467 (message ("%s\"\'%s",
468 cstring_fromChars (arg),
469 cstring_fromChars (quotechar + 1)));
475 arg = cstring_toCharsSafe
476 (message ("%s\'\"%s",
477 cstring_fromChars (arg),
478 cstring_fromChars (quotechar + 1)));
483 curarg = arg + offset;
484 quotechar = strchr (curarg, '\"');
490 llerror (FLG_BADFLAG,
491 message ("Unclosed quote in flag: %s",
492 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 llgloberror (message ("Unrecognized option: %s",
933 cstring_fromChars (thisarg)));
938 context_userSetFlag (opt, set);
940 if (flagcode_hasArgument (opt))
946 else if (flagcode_isPassThrough (opt)) /* -D or -U */
948 passThroughArgs = cstringSList_add
949 (passThroughArgs, cstring_fromChars (thisarg));
951 else if (flagcode_hasValue (opt))
955 setValueFlag (opt, cstring_fromChars (argv[i]));
961 ("Flag %s must be followed by a number",
962 flagcode_unparse (opt)));
965 else if (opt == FLG_INCLUDEPATH || opt == FLG_SPECPATH)
967 cstring dir = cstring_suffix (cstring_fromChars (thisarg), 1); /* skip over I */
971 case FLG_INCLUDEPATH:
972 cppAddIncludeDir (dir);
973 /*@switchbreak@*/ break;
976 g_localSpecPath = cstring_toCharsSafe
978 cstring_fromChars (g_localSpecPath),
982 /*@switchbreak@*/ break;
986 else if (flagcode_hasString (opt)
987 || opt == FLG_INIT || opt == FLG_OPTF)
991 cstring arg = cstring_fromChars (argv[i]);
995 ; /* -f already processed */
997 else if (opt == FLG_INIT)
1000 initFile = inputStream_create
1002 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
1009 DPRINTF (("String flag: %s / %s",
1010 flagcode_unparse (opt), arg));
1011 if (opt == FLG_MTSFILE)
1014 ** arg identifies mts files
1017 addFile (mtfiles, message ("%s%s", arg, MTS_EXTENSION));
1018 addXHFile (xfiles, message ("%s%s", arg, XH_EXTENSION));
1022 setStringFlag (opt, arg);
1030 ("Flag %s must be followed by a string",
1031 flagcode_unparse (opt)));
1041 else /* its a filename */
1043 DPRINTF (("Adding filename: %s", thisarg));
1044 fl = cstringSList_add (fl, cstring_fromChars (thisarg));
1052 ** create lists of C and LCL files
1055 cstringSList_elements (fl, current)
1057 cstring ext = fileLib_getExtension (current);
1059 if (cstring_isUndefined (ext))
1061 /* no extension --- both C and LCL with default extensions */
1063 addFile (cfiles, message ("%s%s", current, C_EXTENSION));
1064 addFile (lclfiles, message ("%s%s", current, LCL_EXTENSION));
1066 else if (cstring_equal (ext, XH_EXTENSION))
1068 addXHFile (xfiles, cstring_copy (current));
1070 else if (cstring_equal (ext, LCL_EXTENSION))
1072 addFile (lclfiles, cstring_copy (current));
1074 else if (fileLib_isCExtension (ext))
1076 addFile (cfiles, cstring_copy (current));
1078 else if (cstring_equal (ext, MTS_EXTENSION))
1080 addFile (mtfiles, cstring_copy (current));
1085 (FLG_FILEEXTENSIONS,
1086 message ("Unrecognized file extension: %s (assuming %s is C source code)",
1090 addFile (cfiles, cstring_copy (current));
1092 } end_cstringSList_elements;
1094 showHerald (); /*@i723 move earlier? */
1102 fprintf (g_msgstream, "\n");
1104 fileIdList_free (cfiles);
1105 fileIdList_free (xfiles);
1106 fileIdList_free (lclfiles);
1115 inittime = clock ();
1117 context_resetErrors ();
1118 context_clearInCommandLine ();
1120 anylcl = !fileIdList_isEmpty (lclfiles);
1122 if (context_doMerge ())
1124 cstring m = context_getMerge ();
1126 if (context_getFlag (FLG_SHOWSCAN))
1128 fprintf (g_msgstream, "< loading %s ", cstring_toCharsSafe (m));
1133 if (context_getFlag (FLG_SHOWSCAN))
1135 fprintf (g_msgstream, " >\n");
1138 if (!usymtab_existsType (context_getBoolName ()))
1140 usymtab_initBool ();
1145 if (!context_getFlag (FLG_NOLIB) && loadStandardState ())
1154 /* setup bool type and constants */
1155 usymtab_initBool ();
1158 fileloc_free (g_currentloc);
1159 g_currentloc = fileloc_createBuiltin ();
1162 ** Read metastate files (must happen before loading libraries)
1165 fileIdList_elements (mtfiles, mtfile)
1167 context_setFileId (mtfile);
1169 if (context_getFlag (FLG_SHOWSCAN))
1171 lldiagmsg (message ("< processing %s >", rootFileName (mtfile)));
1174 mtreader_readFile (cstring_copy (fileName (mtfile)));
1175 } end_fileIdList_elements;
1182 llfatalerror (cstring_makeLiteral ("This version of LCLint does not handle LCL files."));
1184 lslProcess (lclfiles);
1188 usymtab_initGlobalMarker ();
1193 ** call the pre-preprocessor and /lib/cpp to generate appropriate
1198 context_setInCommandLine ();
1200 DPRINTF (("Pass through: %s", cstringSList_unparse (passThroughArgs)));
1202 cstringSList_elements (passThroughArgs, thisarg) {
1203 handlePassThroughFlag (cstring_toCharsSafe (thisarg));
1204 } end_cstringSList_elements;
1206 cstringSList_free (passThroughArgs);
1210 DPRINTF (("Initializing cpp reader!"));
1211 cppReader_initialize ();
1212 cppReader_saveDefinitions ();
1214 context_clearInCommandLine ();
1216 if (!context_getFlag (FLG_NOPP))
1222 if (context_getFlag (FLG_SHOWSCAN))
1224 fprintf (stderr, "< preprocessing");
1229 context_setPreprocessing ();
1230 dercfiles = preprocessFiles (xfiles, TRUE);
1231 tfiles = preprocessFiles (cfiles, FALSE);
1232 dercfiles = fileIdList_append (dercfiles, tfiles);
1233 fileIdList_free (tfiles);
1235 context_clearPreprocessing ();
1237 fileIdList_free (cfiles);
1239 if (context_getFlag (FLG_SHOWSCAN))
1241 fprintf (stderr, " >\n");
1249 dercfiles = fileIdList_append (cfiles, xfiles);
1254 ** now, check all the corresponding C files
1256 ** (for now these are just <file>.c, but after pre-processing
1257 ** will be <tmpprefix>.<file>.c)
1262 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1266 llbug (message ("Files unclosed: %d", nfiles));
1271 DPRINTF (("Initializing..."));
1273 exprNode_initMod ();
1275 DPRINTF (("Okay..."));
1277 fileIdList_elements (dercfiles, fid)
1279 sourceFile = inputStream_create (cstring_copy (fileName (fid)), C_EXTENSION, TRUE);
1280 context_setFileId (fid);
1282 /* Open source file */
1284 if (inputStream_isUndefined (sourceFile) || (!inputStream_open (sourceFile)))
1286 /* previously, this was ignored ?! */
1287 llbug (message ("Could not open temp file: %s", fileName (fid)));
1291 yyin = inputStream_getFile (sourceFile); /*< shared <- only */
1293 llassert (yyin != NULL);
1295 if (context_getFlag (FLG_SHOWSCAN))
1297 lldiagmsg (message ("< checking %s >", rootFileName (fid)));
1301 ** Every time, except the first time, through the loop,
1302 ** need to call yyrestart to clean up the parse buffer.
1307 (void) yyrestart (yyin);
1314 DPRINTF (("Entering..."));
1315 context_enterFile ();
1317 context_exitCFile ();
1319 (void) inputStream_close (sourceFile);
1321 } end_fileIdList_elements;
1325 /* process any leftover macros */
1327 context_processAllMacros ();
1329 /* check everything that was specified was defined */
1331 /* don't check if no c files were processed ?
1332 ** is this correct behaviour?
1335 if (context_getFlag (FLG_SHOWSCAN))
1337 lldiagmsg (cstring_makeLiteral ("< global checks >"));
1342 if (context_getLinesProcessed () > 0)
1344 usymtab_allDefined ();
1347 if (context_maybeSet (FLG_TOPUNUSED))
1349 uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main"));
1351 if (uentry_isValid (ue))
1353 uentry_setUsed (ue, fileloc_observeBuiltin ());
1359 if (context_maybeSet (FLG_EXPORTLOCAL))
1361 usymtab_exportLocal ();
1365 if (context_maybeSet (FLG_EXPORTHEADER))
1367 usymtab_exportHeader ();
1370 if (context_getFlag (FLG_SHOWUSES))
1372 usymtab_displayAllUses ();
1375 context_checkSuppressCounts ();
1377 if (context_doDump ())
1379 cstring dump = context_getDump ();
1390 if (context_getFlag (FLG_SHOWSUMMARY))
1397 bool isQuiet = context_getFlag (FLG_QUIET);
1398 cstring specErrors = cstring_undefined;
1400 int nspecErrors = lclNumberErrors ();
1405 if (context_neednl ())
1406 fprintf (g_msgstream, "\n");
1409 if (nspecErrors > 0)
1411 if (nspecErrors == context_getLCLExpect ())
1414 message ("%d spec error%& found, as expected\n ",
1419 if (context_getLCLExpect () > 0)
1422 message ("%d spec error%& found, expected %d\n ",
1424 (int) context_getLCLExpect ());
1428 specErrors = message ("%d spec error%& found\n ",
1436 if (context_getLCLExpect () > 0)
1438 specErrors = message ("No spec errors found, expected %d\n ",
1439 (int) context_getLCLExpect ());
1445 if (context_anyErrors ())
1447 if (context_numErrors () == context_getExpect ())
1450 llmsg (message ("Finished LCLint checking --- "
1451 "%s%d code error%& found, as expected",
1452 specErrors, context_numErrors ()));
1457 if (context_getExpect () > 0)
1461 ("Finished LCLint checking --- "
1462 "%s%d code error%& found, expected %d",
1463 specErrors, context_numErrors (),
1464 (int) context_getExpect ()));
1474 llmsg (message ("Finished LCLint checking --- "
1475 "%s%d code error%& found",
1476 specErrors, context_numErrors ()));
1485 if (context_getExpect () > 0)
1489 ("Finished LCLint checking --- "
1490 "%sno code errors found, expected %d",
1492 (int) context_getExpect ()));
1499 if (context_getLinesProcessed () > 0)
1502 llmsg (message ("Finished LCLint checking --- %sno code errors found",
1509 llmsg (message ("Finished LCLint checking --- %sno code processed",
1516 cstring_free (specErrors);
1519 if (context_getFlag (FLG_STATS))
1521 clock_t ttime = clock () - before;
1522 int specLines = context_getSpecLinesProcessed ();
1528 fprintf (g_msgstream, "%d spec, ", specLines);
1531 # ifndef CLOCKS_PER_SEC
1532 fprintf (g_msgstream, "%d source lines in %ld time steps (steps/sec unknown)\n",
1533 context_getLinesProcessed (),
1536 fprintf (g_msgstream, "%d source lines in %.2f s.\n",
1537 context_getLinesProcessed (),
1538 (double) ttime / CLOCKS_PER_SEC);
1546 if (context_getFlag (FLG_TIMEDIST))
1548 clock_t ttime = clock () - before;
1552 char *msg = (char *) dmalloc (256 * sizeof (*msg));
1557 "Time distribution (percent): initialize %.2f / lcl %.2f / "
1558 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1559 (100.0 * (double) (libtime - before) / ttime),
1560 (100.0 * (double) (lcltime - libtime) / ttime),
1561 (100.0 * (double) (pptime - lcltime) / ttime),
1562 (100.0 * (double) (cptime - pptime) / ttime),
1563 (100.0 * (double) (rstime - cptime) / ttime));
1568 "Time distribution (percent): initialize %.2f / "
1569 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1570 (100.0 * (double) (libtime - before) / ttime),
1571 (100.0 * (double) (pptime - libtime) / ttime),
1572 (100.0 * (double) (cptime - pptime) / ttime),
1573 (100.0 * (double) (rstime - cptime) / ttime));
1576 llgenindentmsgnoloc (cstring_fromCharsO (msg));
1580 llexit (expsuccess ? LLSUCCESS : LLFAILURE);
1585 ** Reenable return value warnings.
1587 # pragma warning (default:4035)
1595 llmsg (message ("Source files are .c, .h and %s files. If there is no suffix,",
1597 llmsg (message (" LCLint will look for <file>.c and <file>%s.", LCL_EXTENSION));
1599 llmsglit ("Use lclint -help <topic or flag name> for more information");
1601 llmsglit ("Topics:");
1603 llmsglit (" annotations (describes source-code annotations)");
1604 llmsglit (" comments (describes control comments)");
1605 llmsglit (" flags (describes flag categories)");
1606 llmsglit (" flags <category> (describes flags in category)");
1607 llmsglit (" flags all (short description of all flags)");
1608 llmsglit (" flags alpha (list all flags alphabetically)");
1609 llmsglit (" flags full (full description of all flags)");
1610 llmsglit (" mail (information on mailing lists)");
1611 llmsglit (" modes (show mode settings)");
1612 llmsglit (" parseerrors (help on handling parser errors)");
1613 llmsglit (" prefixcodes (character codes in namespace prefixes)");
1614 llmsglit (" references (sources for more information)");
1615 llmsglit (" vars (environment variables)");
1616 llmsglit (" version (information on compilation, maintainer)");
1621 specialFlagsHelp (char *next)
1623 if ((next != NULL) && (*next != '-') && (*next != '+'))
1625 if (mstring_equal (next, "alpha"))
1630 else if (mstring_equal (next, "all"))
1632 printAllFlags (TRUE, FALSE);
1635 else if (mstring_equal (next, "categories")
1636 || mstring_equal (next, "cats"))
1638 listAllCategories ();
1641 else if (mstring_equal (next, "full"))
1643 printAllFlags (FALSE, TRUE);
1658 printParseErrors (void)
1660 llmsglit ("Parse Errors");
1661 llmsglit ("------------");
1663 llmsglit ("LCLint will sometimes encounter a parse error for code that "
1664 "can be parsed with a local compiler. There are a few likely "
1665 "causes for this and a number of techniques that can be used "
1666 "to work around the problem.");
1668 llmsglit ("Compiler extensions --- compilers sometimes extend the C "
1669 "language with compiler-specific keywords and syntax. While "
1670 "it is not advisible to use these, oftentimes one has no choice "
1671 "when the system header files use compiler extensions. ");
1673 llmsglit ("LCLint supports some of the GNU (gcc) compiler extensions, "
1674 "if the +gnuextensions flag is set. You may be able to workaround "
1675 "other compiler extensions by using a pre-processor define. "
1676 "Alternately, you can surround the unparseable code with");
1678 llmsglit (" # ifndef __LCLINT__");
1680 llmsglit (" # endif");
1682 /* evans 2000-12-21 fixed typo reported by Jeroen Ruigrok/Asmodai */
1683 llmsglit ("Missing type definitions --- an undefined type name will usually "
1684 "lead to a parse error. This often occurs when a standard header "
1685 "file defines some type that is not part of the standard library. ");
1686 llmsglit ("By default, LCLint does not process the local files corresponding "
1687 "to standard library headers, but uses a library specification "
1688 "instead so dependencies on local system headers can be detected. "
1689 "If another system header file that does not correspond to a "
1690 "standard library header uses one of these superfluous types, "
1691 "a parse error will result.");
1693 llmsglit ("If the parse error is inside a posix standard header file, the "
1694 "first thing to try is +posixlib. This make LCLint use "
1695 "the posix library specification instead of reading the posix "
1698 llmsglit ("Otherwise, you may need to either manually define the problematic "
1699 "type (e.g., add -Dmlink_t=int to your .lclintrc file) or force "
1700 "lclint to process the header file that defines it. This is done "
1701 "by setting -skipansiheaders or -skipposixheaders before "
1702 "the file that defines the type is #include'd.");
1703 llmsglit ("(See lclint -help "
1704 "skipansiheaders and lclint -help skipposixheaders for a list of "
1705 "standard headers.) For example, if <sys/local.h> uses a type "
1706 "defined by posix header <sys/types.h> but not defined by the "
1707 "posix library, we might do: ");
1709 llmsglit (" /*@-skipposixheaders@*/");
1710 llmsglit (" # include <sys/types.h>");
1711 llmsglit (" /*@=skipposixheaders@*/");
1712 llmsglit (" # include <sys/local.h>");
1714 llmsglit ("to force LCLint to process <sys/types.h>.");
1716 llmsglit ("At last resort, +trytorecover can be used to make LCLint attempt "
1717 "to continue after a parse error. This is usually not successful "
1718 "and the author does not consider assertion failures when +trytorecover "
1719 "is used to be bugs.");
1723 printAnnotations (void)
1725 llmsglit ("Annotations");
1726 llmsglit ("-----------");
1728 llmsglit ("Annotations are semantic comments that document certain "
1729 "assumptions about functions, variables, parameters, and types. ");
1731 llmsglit ("They may be used to indicate where the representation of a "
1732 "user-defined type is hidden, to limit where a global variable may "
1733 "be used or modified, to constrain what a function implementation "
1734 "may do to its parameters, and to express checked assumptions about "
1735 "variables, types, structure fields, function parameters, and "
1736 "function results.");
1738 llmsglit ("Annotations are introduced by \"/*@\". The role of the @ may be "
1739 "played by any printable character, selected using -commentchar <char>.");
1741 llmsglit ("Consult the User's Guide for descriptions of checking associated with each annotation.");
1743 llmsglit ("Globals: (in function declarations)");
1744 llmsglit (" /*@globals <globitem>,+ @*/");
1745 llmsglit (" globitem is an identifier, internalState or fileSystem");
1747 llmsglit ("Modifies: (in function declarations)");
1748 llmsglit (" /*@modifies <moditem>,+ @*/");
1749 llmsglit (" moditem is an lvalue");
1750 llmsglit (" /*@modifies nothing @*/");
1751 llmsglit (" /*@*/ (Abbreviation for no globals and modifies nothing.)");
1753 llmsglit ("Iterators:");
1754 llmsglit (" /*@iter <identifier> (<parameter-type-list>) @*/ - declare an iterator");
1756 llmsglit ("Constants:");
1757 llmsglit (" /*@constant <declaration> @*/ - declares a constant");
1759 llmsglit ("Alternate Types:");
1760 llmsglit (" /*@alt <basic-type>,+ @*/");
1761 llmsglit (" (e.g., int /*@alt char@*/ is a type matching either int or char)");
1763 llmsglit ("Declarator Annotations");
1765 llmsglit ("Type Definitions:");
1766 llmsglit (" /*@abstract@*/ - representation is hidden from clients");
1767 llmsglit (" /*@concrete@*/ - representation is visible to clients");
1768 llmsglit (" /*@immutable@*/ - instances of the type cannot change value");
1769 llmsglit (" /*@mutable@*/ - instances of the type can change value");
1770 llmsglit (" /*@refcounted@*/ - reference counted type");
1772 llmsglit ("Global Variables:");
1773 llmsglit (" /*@unchecked@*/ - weakest checking for global use");
1774 llmsglit (" /*@checkmod@*/ - check modification by not use of global");
1775 llmsglit (" /*@checked@*/ - check use and modification of global");
1776 llmsglit (" /*@checkedstrict@*/ - check use of global strictly");
1778 llmsglit ("Memory Management:");
1779 llmsglit (" /*@dependent@*/ - a reference to externally-owned storage");
1780 llmsglit (" /*@keep@*/ - a parameter that is kept by the called function");
1781 llmsglit (" /*@killref@*/ - a refcounted parameter, killed by the call");
1782 llmsglit (" /*@only@*/ - an unshared reference");
1783 llmsglit (" /*@owned@*/ - owner of storage that may be shared by /*@dependent@*/ references");
1784 llmsglit (" /*@shared@*/ - shared reference that is never deallocated");
1785 llmsglit (" /*@temp@*/ - temporary parameter");
1787 llmsglit ("Aliasing:");
1788 llmsglit (" /*@unique@*/ - may not be aliased by any other visible reference");
1789 llmsglit (" /*@returned@*/ - may be aliased by the return value");
1791 llmsglit ("Exposure:");
1792 llmsglit (" /*@observer@*/ - reference that cannot be modified");
1793 llmsglit (" /*@exposed@*/ - exposed reference to storage in another object");
1795 llmsglit ("Definition State:");
1796 llmsglit (" /*@out@*/ - storage reachable from reference need not be defined");
1797 llmsglit (" /*@in@*/ - all storage reachable from reference must be defined");
1798 llmsglit (" /*@partial@*/ - partially defined, may have undefined fields");
1799 llmsglit (" /*@reldef@*/ - relax definition checking");
1801 llmsglit ("Global State: (for globals lists, no /*@, since list is already in /*@\'s)");
1802 llmsglit (" undef - variable is undefined before the call");
1803 llmsglit (" killed - variable is undefined after the call");
1805 llmsglit ("Null State:");
1806 llmsglit (" /*@null@*/ - possibly null pointer");
1807 llmsglit (" /*@notnull@*/ - non-null pointer");
1808 llmsglit (" /*@relnull@*/ - relax null checking");
1810 llmsglit ("Null Predicates:");
1811 llmsglit (" /*@truenull@*/ - if result is TRUE, first parameter is NULL");
1812 llmsglit (" /*@falsenull@*/ - if result is TRUE, first parameter is not NULL");
1814 llmsglit ("Execution:");
1815 llmsglit (" /*@exits@*/ - function never returns");
1816 llmsglit (" /*@mayexit@*/ - function may or may not return");
1817 llmsglit (" /*@trueexit@*/ - function does not return if first parameter is TRUE");
1818 llmsglit (" /*@falseexit@*/ - function does not return if first parameter if FALSE");
1819 llmsglit (" /*@neverexit@*/ - function always returns");
1821 llmsglit ("Side-Effects:");
1822 llmsglit (" /*@sef@*/ - corresponding actual parameter has no side effects");
1824 llmsglit ("Declaration:");
1825 llmsglit (" /*@unused@*/ - need not be used (no unused errors reported)");
1826 llmsglit (" /*@external@*/ - defined externally (no undefined error reported)");
1829 llmsglit (" /*@fallthrough@*/ - fall-through case");
1831 llmsglit ("Break:");
1832 llmsglit (" /*@innerbreak@*/ - break is breaking an inner loop or switch");
1833 llmsglit (" /*@loopbreak@*/ - break is breaking a loop");
1834 llmsglit (" /*@switchbreak@*/ - break is breaking a switch");
1835 llmsglit (" /*@innercontinue@*/ - continue is continuing an inner loop");
1837 llmsglit ("Unreachable Code:");
1838 llmsglit (" /*@notreached@*/ - statement may be unreachable.");
1840 llmsglit ("Special Functions:");
1841 llmsglit (" /*@printflike@*/ - check variable arguments like printf");
1842 llmsglit (" /*@scanflike@*/ - check variable arguments like scanf");
1846 printComments (void)
1848 llmsglit ("Control Comments");
1849 llmsglit ("----------------");
1851 llmsglit ("Setting Flags");
1853 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.");
1855 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,");
1856 llmsglit (" /*@+boolint -modifies =showfunc@*/");
1857 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).");
1859 llmsglit ("Error Suppression");
1861 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.");
1863 llmsglit ("/*@ignore@*/ ... /*@end@*/");
1865 (cstring_makeLiteral
1866 ("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."));
1867 llmsglit ("/*@i@*/");
1869 (cstring_makeLiteral
1870 ("No errors will be reported from an /*@i@*/ comment to the end of the line."));
1871 llmsglit ("/*@i<n>@*/");
1873 (cstring_makeLiteral
1874 ("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."));
1875 llmsglit ("/*@t@*/, /*@t<n>@*/");
1877 (cstring_makeLiteral
1878 ("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."));
1880 llmsglit ("Type Access");
1882 llmsglit ("/*@access <type>@*/");
1883 llmsglit (" Allows the following code to access the representation of <type>");
1884 llmsglit ("/*@noaccess <type>@*/");
1885 llmsglit (" Hides the representation of <type>");
1887 llmsglit ("Macro Expansion");
1889 llmsglit ("/*@notfunction@*/");
1891 (cstring_makeLiteral
1892 ("Indicates that the next macro definition is not intended to be a "
1893 "function, and should be expanded in line instead of checked as a "
1894 "macro function definition."));
1901 llmsglit ("Flag Categories");
1902 llmsglit ("---------------");
1903 listAllCategories ();
1904 llmsglit ("\nTo see the flags in a flag category, do\n lclint -help flags <category>");
1905 llmsglit ("To see a list of all flags in alphabetical order, do\n lclint -help flags alpha");
1906 llmsglit ("To see a full description of all flags, do\n lclint -help flags full");
1910 printMaintainer (void)
1912 llmsg (message ("Maintainer: %s", cstring_makeLiteralTemp (LCLINT_MAINTAINER)));
1913 llmsglit (LCL_COMPILE);
1919 llmsglit ("Mailing Lists");
1920 llmsglit ("-------------");
1922 llmsglit ("There are two mailing lists associated with LCLint: ");
1924 llmsglit (" lclint-announce@virginia.edu");
1926 llmsglit (" Reserved for announcements of new releases and bug fixes.");
1927 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
1928 llmsglit (" subscribe lclint-announce");
1930 llmsglit (" lclint-interest@virginia.edu");
1932 llmsglit (" Informal discussions on the use and development of lclint.");
1933 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
1934 llmsglit (" subscribe lclint-interest");
1938 printReferences (void)
1940 llmsglit ("References");
1941 llmsglit ("----------");
1943 llmsglit ("The LCLint web site is http://lclint.cs.virginia.edu");
1945 llmsglit ("Technical papers relating to LCLint include:");
1947 llmsglit (" David Evans. \"Static Detection of Dynamic Memory Errors\".");
1948 llmsglit (" SIGPLAN Conference on Programming Language Design and ");
1949 llmsglit (" Implementation (PLDI '96), Philadelphia, PA, May 1996.");
1951 llmsglit (" David Evans, John Guttag, Jim Horning and Yang Meng Tan. ");
1952 llmsglit (" \"LCLint: A Tool for Using Specifications to Check Code\".");
1953 llmsglit (" SIGSOFT Symposium on the Foundations of Software Engineering,");
1954 llmsglit (" December 1994.");
1956 llmsglit ("A general book on Larch is:");
1958 llmsglit (" Guttag, John V., Horning, James J., (with Garland, S. J., Jones, ");
1959 llmsglit (" K. D., Modet, A., and Wing, J. M.), \"Larch: Languages and Tools ");
1960 llmsglit (" for Formal Specification\", Springer-Verlag, 1993.");
1964 describePrefixCodes (void)
1966 llmsglit ("Prefix Codes");
1967 llmsglit ("------------");
1969 llmsglit ("These characters have special meaning in name prefixes:");
1971 llmsg (message (" %h Any uppercase letter [A-Z]", PFX_UPPERCASE));
1972 llmsg (message (" %h Any lowercase letter [a-z]", PFX_LOWERCASE));
1973 llmsg (message (" %h Any character (valid in a C identifier)", PFX_ANY));
1974 llmsg (message (" %h Any digit [0-9]", PFX_DIGIT));
1975 llmsg (message (" %h Any non-uppercase letter [a-z0-9_]", PFX_NOTUPPER));
1976 llmsg (message (" %h Any non-lowercase letter [A-Z0-9_]", PFX_NOTLOWER));
1977 llmsg (message (" %h Any letter [A-Za-z]", PFX_ANYLETTER));
1978 llmsg (message (" %h Any letter or digit [A-Za-z0-9]", PFX_ANYLETTERDIGIT));
1979 llmsglit (" * Zero or more repetitions of the previous character class until the end of the name");
1988 eval = context_getLarchPath ();
1989 def = osd_getEnvironmentVariable (LARCH_PATH);
1991 if (cstring_isDefined (def) ||
1992 !cstring_equal (eval, cstring_fromChars (DEFAULT_LARCHPATH)))
1994 llmsg (message ("LARCH_PATH = %s", eval));
1998 llmsg (message ("LARCH_PATH = <not set> (default = %s)",
1999 cstring_fromChars (DEFAULT_LARCHPATH)));
2002 llmsglit (" --- path used to find larch initialization files and LSL traits");
2004 eval = context_getLCLImportDir ();
2005 def = osd_getEnvironmentVariable (cstring_makeLiteralTemp (LCLIMPORTDIR));
2007 if (cstring_isDefined (def) ||
2008 !cstring_equal (eval, cstring_fromChars (DEFAULT_LCLIMPORTDIR)))
2010 llmsg (message ("%q = %s", cstring_makeLiteral (LCLIMPORTDIR), eval));
2014 llmsg (message ("%s = <not set, default: %s>", cstring_makeLiteralTemp (LCLIMPORTDIR),
2015 cstring_makeLiteralTemp (DEFAULT_LCLIMPORTDIR)));
2018 llmsglit (" --- directory containing lcl standard library files "
2019 "(import with < ... >)");;
2022 ("include path = %q (set by environment variable %s and -I flags)",
2023 cppReader_getIncludePath (), INCLUDEPATH_VAR));
2025 llmsglit (" --- path used to find #include'd files");
2028 ("systemdirs = %s (set by -systemdirs or envirnoment variable %s)", /*@i413223@*/
2029 context_getString (FLG_SYSTEMDIRS),
2032 llmsglit (" --- if file is found on this path, it is treated as a system file for error reporting");
2041 fprintf (stderr, "*** Interrupt\n");
2042 llexit (LLINTERRUPT);
2047 /* Cheat when there are parse errors */
2050 fprintf (stderr, "*** Segmentation Violation\n");
2052 /* Don't catch it if fileloc_unparse causes a signal */
2053 (void) signal (SIGSEGV, NULL);
2055 loc = fileloc_unparse (g_currentloc);
2057 fprintf (stderr, "*** Location (not trusted): %s\n",
2058 cstring_toCharsSafe (loc));
2061 fprintf (stderr, "*** Please report bug to %s\n", LCLINT_MAINTAINER);
2065 fprintf (stderr, "*** Signal: %d\n", i);
2067 fprintf (stderr, "*** Location (not trusted): %s\n",
2068 cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
2071 fprintf (stderr, "*** Please report bug to %s ***\n", LCLINT_MAINTAINER);
2079 static bool doneCleanup = FALSE;
2081 /* make sure this is only called once! */
2083 if (doneCleanup) return;
2087 if (context_getFlag (FLG_KEEP))
2089 check (fputs ("Temporary files kept:\n", stderr) != EOF);
2090 fileTable_printTemps (context_fileTable ());
2095 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
2099 llbug (message ("Files unclosed: %d", nfiles));
2102 fileTable_cleanup (context_fileTable ());
2109 ** cleans up temp files (if necessary)
2116 DPRINTF (("llexit: %d", status));
2119 if (status == LLFAILURE)
2127 if (status != LLFAILURE)
2129 context_destroyMod ();
2130 exprNode_destroyMod ();
2133 uentry_destroyMod ();
2134 typeIdSet_destroyMod ();
2137 dmalloc_shutdown ();
2141 exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
2145 loadrc (/*@open@*/ FILE *rcfile, cstringSList *passThroughArgs)
2146 /*@ensures closed rcfile@*/
2148 char *s = mstring_create (MAX_LINE_LENGTH);
2151 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2155 while (reader_readLine (rcfile, s, MAX_LINE_LENGTH) != NULL)
2162 DPRINTF (("Line: %s", s));
2163 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2165 while (*s == ' ' || *s == '\t')
2173 bool escaped = FALSE;
2174 bool quoted = FALSE;
2177 DPRINTF (("Process: %s", s));
2178 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2179 /* comment characters */
2180 if (c == '#' || c == ';' || c == '\n')
2186 if (c == '-' || c == '+')
2193 llerror (FLG_SYNTAX,
2194 message ("Bad flag syntax (+ or - expected, "
2195 "+ is assumed): %s",
2196 cstring_fromChars (s)));
2206 while ((c = *s) != '\0')
2207 { /* remember to handle spaces and quotes in -D and -U ... */
2233 if (c == ' ' || c == '\t' || c == '\n')
2235 /*@innerbreak@*/ break;
2243 DPRINTF (("Nulling: %c", *s));
2246 if (mstring_isEmpty (thisflag))
2248 llfatalerror (message ("Missing flag: %s",
2249 cstring_fromChars (os)));
2252 DPRINTF (("Flag: %s", thisflag));
2254 opt = identifyFlag (cstring_fromChars (thisflag));
2256 if (flagcode_isSkip (opt))
2260 else if (flagcode_isInvalid (opt))
2262 DPRINTF (("Invalid: %s", thisflag));
2264 if (isMode (cstring_fromChars (thisflag)))
2266 context_setMode (cstring_fromChars (thisflag));
2270 llerror (FLG_BADFLAG,
2271 message ("Unrecognized option: %s",
2272 cstring_fromChars (thisflag)));
2277 context_userSetFlag (opt, set);
2279 if (flagcode_hasArgument (opt))
2281 if (opt == FLG_HELP)
2284 llerror (FLG_BADFLAG,
2285 message ("Cannot use help in rc files"));
2287 else if (flagcode_isPassThrough (opt)) /* -D or -U */
2289 cstring arg = cstring_fromCharsNew (thisflag);
2290 cstring_markOwned (arg);
2291 *passThroughArgs = cstringSList_add (*passThroughArgs, arg);
2292 DPRINTF (("Pass through: %s",
2293 cstringSList_unparse (*passThroughArgs)));
2295 else if (opt == FLG_INCLUDEPATH
2296 || opt == FLG_SPECPATH)
2298 cstring dir = cstring_suffix (cstring_fromChars (thisflag), 1); /* skip over I/S */
2302 case FLG_INCLUDEPATH:
2303 cppAddIncludeDir (dir);
2304 /*@switchbreak@*/ break;
2307 g_localSpecPath = cstring_toCharsSafe
2308 (message ("%s:%s", cstring_fromChars (g_localSpecPath), dir));
2310 /*@switchbreak@*/ break;
2314 else if (flagcode_hasString (opt)
2315 || flagcode_hasValue (opt)
2316 || opt == FLG_INIT || opt == FLG_OPTF)
2318 cstring extra = cstring_undefined;
2323 rest = mstring_copy (s);
2324 DPRINTF (("Here: rest = %s", rest));
2328 while ((rchar = *rest) != '\0'
2329 && (isspace ((int) rchar)))
2335 DPRINTF (("Yo: %s", rest));
2337 while ((rchar = *rest) != '\0'
2338 && !isspace ((int) rchar))
2340 extra = cstring_appendChar (extra, rchar);
2345 DPRINTF (("Yo: %s", extra));
2348 if (cstring_isUndefined (extra))
2354 ("Flag %s must be followed by an argument",
2355 flagcode_unparse (opt)));
2361 DPRINTF (("Here we are: %s", extra));
2363 if (flagcode_hasValue (opt))
2365 DPRINTF (("Set value flag: %s", extra));
2366 setValueFlag (opt, extra);
2367 cstring_free (extra);
2369 else if (opt == FLG_OPTF)
2371 FILE *innerf = fopen (cstring_toCharsSafe (extra), "r");
2372 cstring_markOwned (extra);
2376 fileloc fc = g_currentloc;
2377 g_currentloc = fileloc_createRc (extra);
2378 loadrc (innerf, passThroughArgs);
2379 fileloc_reallyFree (g_currentloc);
2387 message ("Options file not found: %s",
2391 else if (opt == FLG_INIT)
2394 llassert (inputStream_isUndefined (initFile));
2396 initFile = inputStream_create
2398 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
2401 cstring_free (extra);
2404 else if (flagcode_hasString (opt))
2406 if (cstring_firstChar (extra) == '"')
2408 if (cstring_lastChar (extra) == '"')
2410 char *extras = cstring_toCharsSafe (extra);
2412 llassert (extras[strlen(extras) - 1] == '"');
2413 extras[strlen(extras) - 1] = '\0';
2414 extra = cstring_fromChars (extras + 1);
2415 DPRINTF (("Remove quites: %s", extra));
2421 message ("Unmatched \" in option string: %s",
2426 setStringFlag (opt, extra);
2430 cstring_free (extra);
2443 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2444 while ((c == ' ') || (c == '\t'))
2450 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2454 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2456 check (fclose (rcfile) == 0);
2459 static fileIdList preprocessFiles (fileIdList fl, bool xhfiles)
2460 /*@modifies fileSystem@*/
2462 bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
2463 int skip = (fileIdList_size (fl) / 5);
2464 int filesprocessed = 0;
2465 fileIdList dfiles = fileIdList_create ();
2467 fileloc_free (g_currentloc);
2468 g_currentloc = fileloc_createBuiltin ();
2470 fileIdList_elements (fl, fid)
2472 cstring ppfname = fileName (fid);
2478 if (osd_findOnLarchPath (ppfname, &fpath) == OSD_FILEFOUND)
2480 if (cstring_equal (ppfname, fpath))
2486 DPRINTF (("xh file: %s", fpath));
2488 fileTable_setFilePath (context_fileTable (), fid, fpath);
2493 lldiagmsg (message ("Cannot find .xh file on LARCH_PATH: %s", ppfname));
2494 lldiagmsg (cstring_makeLiteral (" Check LARCH_PATH environment variable."));
2495 ppfname = cstring_undefined;
2500 if (!(osd_fileIsReadable (ppfname)))
2502 lldiagmsg (message ("Cannot open file: %s", ppfname));
2503 ppfname = cstring_undefined;
2507 if (cstring_isDefined (ppfname))
2509 fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
2511 llassert (cstring_isNonEmpty (ppfname));
2515 if ((filesprocessed % skip) == 0)
2517 if (filesprocessed == 0) {
2518 fprintf (stderr, " ");
2521 fprintf (stderr, ".");
2524 (void) fflush (stderr);
2529 if (cppProcess (ppfname, fileName (dfile)) != 0)
2531 llfatalerror (message ("Preprocessing error for file: %s",
2532 rootFileName (fid)));
2535 fileIdList_add (dfiles, dfile);
2537 } end_fileIdList_elements;
2542 /* This should be in an lclUtils.c file... */
2544 char *specFullName (char *specfile, /*@out@*/ char **inpath)
2546 /* extract the path and the specname associated with the given file */
2547 char *specname = (char *) dmalloc (sizeof (*specname)
2548 * (strlen (specfile) + 9));
2549 char *ospecname = specname;
2550 char *path = (char *) dmalloc (sizeof (*path) * (strlen (specfile)));
2554 /* initialized path to empty string or may have accidental garbage */
2557 /*@-mayaliasunique@*/
2558 strcpy (specname, specfile);
2559 /*@=mayaliasunique@*/
2561 /* trim off pathnames in specfile */
2562 size = strlen (specname);
2564 for (i = size_toInt (size) - 1; i >= 0; i--)
2566 if (specname[i] == CONNECTCHAR)
2568 /* strcpy (specname, (char *)specname+i+1); */
2569 for (j = 0; j <= i; j++) /* include '/' */
2571 path[j] = specname[j];
2581 ** also remove .lcl file extension, assume it's the last extension
2585 size = strlen (specname);
2587 for (i = size_toInt (size) - 1; i >= 0; i--)
2589 if (specname[i] == '.')
2599 ** If specname no longer points to the original char,
2600 ** we need to allocate a new pointer and copy the string.
2603 if (specname != ospecname) {
2604 char *rspecname = (char *) dmalloc (sizeof (*rspecname) * (strlen (specname) + 1));
2605 strcpy (rspecname, specname); /* evs 2000-05-16: Bug: was ospecname! */