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@*/
691 else /* 2001-09-09: herbert */
693 /* Put C_INCLUDE_PATH directories in sysdirs */
694 cstring cincval = osd_getEnvironmentVariable (cstring_makeLiteralTemp ("C_INCLUDE_PATH"));
695 if (cstring_isDefined (cincval))
697 context_setString (FLG_SYSTEMDIRS, cstring_copy (cincval));
702 cstring_free (oincval);
706 ** check RCFILE for default flags
710 cstring home = osd_getHomeDir ();
713 bool defaultf = TRUE;
716 for (i = 1; i < argc; i++)
721 if (*thisarg == '-' || *thisarg == '+')
725 if (mstring_equal (thisarg, "nof"))
729 else if (mstring_equal (thisarg, "f"))
735 rcfile = fopen (fname, "r");
739 fileloc oloc = g_currentloc;
741 g_currentloc = fileloc_createRc (cstring_fromChars (fname));
742 loadrc (rcfile, &passThroughArgs);
743 fileloc_reallyFree (g_currentloc);
749 lldiagmsg (message ("Options file not found: %s",
750 cstring_fromChars (fname)));
755 (cstring_makeLiteral ("Flag f to select options file "
756 "requires an argument"));
760 ; /* wait to process later */
767 if (!cstring_isEmpty (home)) {
768 fname = cstring_toCharsSafe (message ("%s%h%s", home, CONNECTCHAR,
769 cstring_fromChars (RCFILE)));
770 mstring_markFree (fname);
776 if (!nof && defaultf)
778 if (!mstring_isEmpty (fname)) {
779 rcfile = fopen (fname, "r");
783 fileloc oloc = g_currentloc;
785 g_currentloc = fileloc_createRc (cstring_fromChars (fname));
786 loadrc (rcfile, &passThroughArgs);
787 fileloc_reallyFree (g_currentloc);
792 # if defined(MSDOS) || defined(OS2)
793 fname = cstring_toCharsSafe (message ("%s",
794 cstring_fromChars (RCFILE)));
796 fname = cstring_toCharsSafe (message ("./%s",
797 cstring_fromChars (RCFILE)));
800 rcfile = fopen (fname, "r");
804 fileloc oloc = g_currentloc;
806 g_currentloc = fileloc_createRc (cstring_fromChars (fname));
807 loadrc (rcfile, &passThroughArgs);
808 fileloc_reallyFree (g_currentloc);
818 for (i = 1; i < argc; i++)
834 if (*thisarg == '-' || *thisarg == '+')
836 thisarg++; /* skip '-' */
838 if (mstring_equal (thisarg, "modes"))
840 llmsg (describeModes ());
842 else if (mstring_equal (thisarg, "vars")
843 || mstring_equal (thisarg, "env"))
847 else if (mstring_equal (thisarg, "annotations"))
851 else if (mstring_equal (thisarg, "parseerrors"))
855 else if (mstring_equal (thisarg, "comments"))
859 else if (mstring_equal (thisarg, "prefixcodes"))
861 describePrefixCodes ();
863 else if (mstring_equal (thisarg, "references")
864 || mstring_equal (thisarg, "refs"))
868 else if (mstring_equal (thisarg, "mail"))
872 else if (mstring_equal (thisarg, "maintainer")
873 || mstring_equal (thisarg, "version"))
877 else if (mstring_equal (thisarg, "flags"))
881 char *next = argv[i + 1];
883 if (specialFlagsHelp (next))
889 flagkind k = identifyCategory (cstring_fromChars (next));
905 cstring s = describeFlag (cstring_fromChars (thisarg));
907 if (cstring_isDefined (s))
915 if (*thisarg == '-' || *thisarg == '+')
917 bool set = (*thisarg == '+');
920 thisarg++; /* skip '-' */
921 flagname = cstring_fromChars (thisarg);
923 DPRINTF (("Flag: %s", flagname));
924 opt = identifyFlag (flagname);
925 DPRINTF (("Flag: %s", flagcode_unparse (opt)));
927 if (flagcode_isSkip (opt))
929 DPRINTF (("Skipping!"));
931 else if (flagcode_isInvalid (opt))
933 DPRINTF (("Invalid: %s", flagname));
935 if (isMode (flagname))
937 context_setMode (flagname);
941 DPRINTF (("Error!"));
942 voptgenerror (FLG_BADFLAG,
943 message ("Unrecognized option: %s",
944 cstring_fromChars (thisarg)),
950 context_userSetFlag (opt, set);
952 if (flagcode_hasArgument (opt))
958 else if (flagcode_isPassThrough (opt)) /* -D or -U */
960 passThroughArgs = cstringSList_add
961 (passThroughArgs, cstring_fromChars (thisarg));
963 else if (flagcode_hasValue (opt))
967 setValueFlag (opt, cstring_fromChars (argv[i]));
973 ("Flag %s must be followed by a number",
974 flagcode_unparse (opt)));
977 else if (opt == FLG_INCLUDEPATH || opt == FLG_SPECPATH)
979 cstring dir = cstring_suffix (cstring_fromChars (thisarg), 1); /* skip over I */
983 case FLG_INCLUDEPATH:
984 cppAddIncludeDir (dir);
985 /*@switchbreak@*/ break;
988 g_localSpecPath = cstring_toCharsSafe
990 cstring_fromChars (g_localSpecPath),
994 /*@switchbreak@*/ break;
998 else if (flagcode_hasString (opt)
999 || opt == FLG_INIT || opt == FLG_OPTF)
1003 cstring arg = cstring_fromChars (argv[i]);
1005 if (opt == FLG_OPTF)
1007 ; /* -f already processed */
1009 else if (opt == FLG_INIT)
1012 initFile = inputStream_create
1014 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
1021 DPRINTF (("String flag: %s / %s",
1022 flagcode_unparse (opt), arg));
1023 if (opt == FLG_MTSFILE)
1026 ** arg identifies mts files
1029 addFile (mtfiles, message ("%s%s", arg, MTS_EXTENSION));
1030 addXHFile (xfiles, message ("%s%s", arg, XH_EXTENSION));
1034 setStringFlag (opt, arg);
1042 ("Flag %s must be followed by a string",
1043 flagcode_unparse (opt)));
1053 else /* its a filename */
1055 DPRINTF (("Adding filename: %s", thisarg));
1056 fl = cstringSList_add (fl, cstring_fromChars (thisarg));
1064 ** create lists of C and LCL files
1067 cstringSList_elements (fl, current)
1069 cstring ext = fileLib_getExtension (current);
1071 if (cstring_isUndefined (ext))
1073 /* no extension --- both C and LCL with default extensions */
1075 addFile (cfiles, message ("%s%s", current, C_EXTENSION));
1076 addFile (lclfiles, message ("%s%s", current, LCL_EXTENSION));
1078 else if (cstring_equal (ext, XH_EXTENSION))
1080 addXHFile (xfiles, cstring_copy (current));
1082 else if (cstring_equal (ext, PP_EXTENSION))
1084 if (!context_getFlag (FLG_NOPP))
1087 (FLG_FILEEXTENSIONS,
1088 message ("File extension %s used without +nopp flag (will be processed as C source code): %s",
1093 addFile (cfiles, cstring_copy (current));
1095 else if (cstring_equal (ext, LCL_EXTENSION))
1097 addFile (lclfiles, cstring_copy (current));
1099 else if (fileLib_isCExtension (ext))
1101 addFile (cfiles, cstring_copy (current));
1103 else if (cstring_equal (ext, MTS_EXTENSION))
1105 addFile (mtfiles, cstring_copy (current));
1110 (FLG_FILEEXTENSIONS,
1111 message ("Unrecognized file extension: %s (assuming %s is C source code)",
1115 addFile (cfiles, cstring_copy (current));
1117 } end_cstringSList_elements;
1119 showHerald (); /*@i723 move earlier? */
1127 fprintf (g_msgstream, "\n");
1129 fileIdList_free (cfiles);
1130 fileIdList_free (xfiles);
1131 fileIdList_free (lclfiles);
1140 inittime = clock ();
1142 context_resetErrors ();
1143 context_clearInCommandLine ();
1145 anylcl = !fileIdList_isEmpty (lclfiles);
1147 if (context_doMerge ())
1149 cstring m = context_getMerge ();
1151 if (context_getFlag (FLG_SHOWSCAN))
1153 fprintf (g_msgstream, "< loading %s ", cstring_toCharsSafe (m));
1158 if (context_getFlag (FLG_SHOWSCAN))
1160 fprintf (g_msgstream, " >\n");
1163 if (!usymtab_existsType (context_getBoolName ()))
1165 usymtab_initBool ();
1170 if (!context_getFlag (FLG_NOLIB) && loadStandardState ())
1179 /* setup bool type and constants */
1180 usymtab_initBool ();
1183 fileloc_free (g_currentloc);
1184 g_currentloc = fileloc_createBuiltin ();
1187 ** Read metastate files (must happen before loading libraries)
1190 fileIdList_elements (mtfiles, mtfile)
1192 context_setFileId (mtfile);
1194 if (context_getFlag (FLG_SHOWSCAN))
1196 lldiagmsg (message ("< processing %s >", rootFileName (mtfile)));
1199 mtreader_readFile (cstring_copy (fileName (mtfile)));
1200 } end_fileIdList_elements;
1207 llfatalerror (cstring_makeLiteral ("This version of LCLint does not handle LCL files."));
1209 lslProcess (lclfiles);
1213 usymtab_initGlobalMarker ();
1218 ** call the pre-preprocessor and /lib/cpp to generate appropriate
1223 context_setInCommandLine ();
1225 DPRINTF (("Pass through: %s", cstringSList_unparse (passThroughArgs)));
1227 cstringSList_elements (passThroughArgs, thisarg) {
1228 handlePassThroughFlag (cstring_toCharsSafe (thisarg));
1229 } end_cstringSList_elements;
1231 cstringSList_free (passThroughArgs);
1235 DPRINTF (("Initializing cpp reader!"));
1236 cppReader_initialize ();
1237 cppReader_saveDefinitions ();
1239 context_clearInCommandLine ();
1241 if (!context_getFlag (FLG_NOPP))
1247 if (context_getFlag (FLG_SHOWSCAN))
1249 fprintf (stderr, "< preprocessing");
1254 context_setPreprocessing ();
1255 dercfiles = preprocessFiles (xfiles, TRUE);
1256 tfiles = preprocessFiles (cfiles, FALSE);
1257 dercfiles = fileIdList_append (dercfiles, tfiles);
1258 fileIdList_free (tfiles);
1260 context_clearPreprocessing ();
1262 fileIdList_free (cfiles);
1264 if (context_getFlag (FLG_SHOWSCAN))
1266 fprintf (stderr, " >\n");
1274 dercfiles = fileIdList_append (cfiles, xfiles);
1279 ** now, check all the corresponding C files
1281 ** (for now these are just <file>.c, but after pre-processing
1282 ** will be <tmpprefix>.<file>.c)
1287 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1291 llbug (message ("Files unclosed: %d", nfiles));
1296 DPRINTF (("Initializing..."));
1298 exprNode_initMod ();
1300 DPRINTF (("Okay..."));
1302 fileIdList_elements (dercfiles, fid)
1304 sourceFile = inputStream_create (cstring_copy (fileName (fid)), C_EXTENSION, TRUE);
1305 context_setFileId (fid);
1307 /* Open source file */
1309 if (inputStream_isUndefined (sourceFile) || (!inputStream_open (sourceFile)))
1311 /* previously, this was ignored ?! */
1312 llbug (message ("Could not open temp file: %s", fileName (fid)));
1316 yyin = inputStream_getFile (sourceFile); /*< shared <- only */
1318 llassert (yyin != NULL);
1320 if (context_getFlag (FLG_SHOWSCAN))
1322 lldiagmsg (message ("< checking %s >", rootFileName (fid)));
1326 ** Every time, except the first time, through the loop,
1327 ** need to call yyrestart to clean up the parse buffer.
1332 (void) yyrestart (yyin);
1339 DPRINTF (("Entering..."));
1340 context_enterFile ();
1342 context_exitCFile ();
1344 (void) inputStream_close (sourceFile);
1346 } end_fileIdList_elements;
1350 /* process any leftover macros */
1352 context_processAllMacros ();
1354 /* check everything that was specified was defined */
1356 /* don't check if no c files were processed ?
1357 ** is this correct behaviour?
1360 if (context_getFlag (FLG_SHOWSCAN))
1362 lldiagmsg (cstring_makeLiteral ("< global checks >"));
1367 if (context_getLinesProcessed () > 0)
1369 usymtab_allDefined ();
1372 if (context_maybeSet (FLG_TOPUNUSED))
1374 uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main"));
1376 if (uentry_isValid (ue))
1378 uentry_setUsed (ue, fileloc_observeBuiltin ());
1384 if (context_maybeSet (FLG_EXPORTLOCAL))
1386 usymtab_exportLocal ();
1390 if (context_maybeSet (FLG_EXPORTHEADER))
1392 usymtab_exportHeader ();
1395 if (context_getFlag (FLG_SHOWUSES))
1397 usymtab_displayAllUses ();
1400 context_checkSuppressCounts ();
1402 if (context_doDump ())
1404 cstring dump = context_getDump ();
1415 if (context_getFlag (FLG_SHOWSUMMARY))
1422 bool isQuiet = context_getFlag (FLG_QUIET);
1423 cstring specErrors = cstring_undefined;
1425 int nspecErrors = lclNumberErrors ();
1430 if (context_neednl ())
1431 fprintf (g_msgstream, "\n");
1434 if (nspecErrors > 0)
1436 if (nspecErrors == context_getLCLExpect ())
1439 message ("%d spec error%& found, as expected\n ",
1444 if (context_getLCLExpect () > 0)
1447 message ("%d spec error%& found, expected %d\n ",
1449 (int) context_getLCLExpect ());
1453 specErrors = message ("%d spec error%& found\n ",
1461 if (context_getLCLExpect () > 0)
1463 specErrors = message ("No spec errors found, expected %d\n ",
1464 (int) context_getLCLExpect ());
1470 if (context_anyErrors ())
1472 if (context_numErrors () == context_getExpect ())
1475 llmsg (message ("Finished LCLint checking --- "
1476 "%s%d code error%& found, as expected",
1477 specErrors, context_numErrors ()));
1482 if (context_getExpect () > 0)
1486 ("Finished LCLint checking --- "
1487 "%s%d code error%& found, expected %d",
1488 specErrors, context_numErrors (),
1489 (int) context_getExpect ()));
1499 llmsg (message ("Finished LCLint checking --- "
1500 "%s%d code error%& found",
1501 specErrors, context_numErrors ()));
1510 if (context_getExpect () > 0)
1514 ("Finished LCLint checking --- "
1515 "%sno code errors found, expected %d",
1517 (int) context_getExpect ()));
1524 if (context_getLinesProcessed () > 0)
1527 llmsg (message ("Finished LCLint checking --- %sno code errors found",
1534 llmsg (message ("Finished LCLint checking --- %sno code processed",
1541 cstring_free (specErrors);
1544 if (context_getFlag (FLG_STATS))
1546 clock_t ttime = clock () - before;
1547 int specLines = context_getSpecLinesProcessed ();
1553 fprintf (g_msgstream, "%d spec, ", specLines);
1556 # ifndef CLOCKS_PER_SEC
1557 fprintf (g_msgstream, "%d source lines in %ld time steps (steps/sec unknown)\n",
1558 context_getLinesProcessed (),
1561 fprintf (g_msgstream, "%d source lines in %.2f s.\n",
1562 context_getLinesProcessed (),
1563 (double) ttime / CLOCKS_PER_SEC);
1571 if (context_getFlag (FLG_TIMEDIST))
1573 clock_t ttime = clock () - before;
1577 char *msg = (char *) dmalloc (256 * sizeof (*msg));
1582 "Time distribution (percent): initialize %.2f / lcl %.2f / "
1583 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1584 (100.0 * (double) (libtime - before) / ttime),
1585 (100.0 * (double) (lcltime - libtime) / ttime),
1586 (100.0 * (double) (pptime - lcltime) / ttime),
1587 (100.0 * (double) (cptime - pptime) / ttime),
1588 (100.0 * (double) (rstime - cptime) / ttime));
1593 "Time distribution (percent): initialize %.2f / "
1594 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1595 (100.0 * (double) (libtime - before) / ttime),
1596 (100.0 * (double) (pptime - libtime) / ttime),
1597 (100.0 * (double) (cptime - pptime) / ttime),
1598 (100.0 * (double) (rstime - cptime) / ttime));
1601 llgenindentmsgnoloc (cstring_fromCharsO (msg));
1605 llexit (expsuccess ? LLSUCCESS : LLFAILURE);
1610 ** Reenable return value warnings.
1612 # pragma warning (default:4035)
1620 llmsg (message ("Source files are .c, .h and %s files. If there is no suffix,",
1622 llmsg (message (" LCLint will look for <file>.c and <file>%s.", LCL_EXTENSION));
1624 llmsglit ("Use lclint -help <topic or flag name> for more information");
1626 llmsglit ("Topics:");
1628 llmsglit (" annotations (describes source-code annotations)");
1629 llmsglit (" comments (describes control comments)");
1630 llmsglit (" flags (describes flag categories)");
1631 llmsglit (" flags <category> (describes flags in category)");
1632 llmsglit (" flags all (short description of all flags)");
1633 llmsglit (" flags alpha (list all flags alphabetically)");
1634 llmsglit (" flags full (full description of all flags)");
1635 llmsglit (" mail (information on mailing lists)");
1636 llmsglit (" modes (show mode settings)");
1637 llmsglit (" parseerrors (help on handling parser errors)");
1638 llmsglit (" prefixcodes (character codes in namespace prefixes)");
1639 llmsglit (" references (sources for more information)");
1640 llmsglit (" vars (environment variables)");
1641 llmsglit (" version (information on compilation, maintainer)");
1646 specialFlagsHelp (char *next)
1648 if ((next != NULL) && (*next != '-') && (*next != '+'))
1650 if (mstring_equal (next, "alpha"))
1655 else if (mstring_equal (next, "all"))
1657 printAllFlags (TRUE, FALSE);
1660 else if (mstring_equal (next, "categories")
1661 || mstring_equal (next, "cats"))
1663 listAllCategories ();
1666 else if (mstring_equal (next, "full"))
1668 printAllFlags (FALSE, TRUE);
1683 printParseErrors (void)
1685 llmsglit ("Parse Errors");
1686 llmsglit ("------------");
1688 llmsglit ("LCLint will sometimes encounter a parse error for code that "
1689 "can be parsed with a local compiler. There are a few likely "
1690 "causes for this and a number of techniques that can be used "
1691 "to work around the problem.");
1693 llmsglit ("Compiler extensions --- compilers sometimes extend the C "
1694 "language with compiler-specific keywords and syntax. While "
1695 "it is not advisible to use these, oftentimes one has no choice "
1696 "when the system header files use compiler extensions. ");
1698 llmsglit ("LCLint supports some of the GNU (gcc) compiler extensions, "
1699 "if the +gnuextensions flag is set. You may be able to workaround "
1700 "other compiler extensions by using a pre-processor define. "
1701 "Alternately, you can surround the unparseable code with");
1703 llmsglit (" # ifndef __LCLINT__");
1705 llmsglit (" # endif");
1707 /* evans 2000-12-21 fixed typo reported by Jeroen Ruigrok/Asmodai */
1708 llmsglit ("Missing type definitions --- an undefined type name will usually "
1709 "lead to a parse error. This often occurs when a standard header "
1710 "file defines some type that is not part of the standard library. ");
1711 llmsglit ("By default, LCLint does not process the local files corresponding "
1712 "to standard library headers, but uses a library specification "
1713 "instead so dependencies on local system headers can be detected. "
1714 "If another system header file that does not correspond to a "
1715 "standard library header uses one of these superfluous types, "
1716 "a parse error will result.");
1718 llmsglit ("If the parse error is inside a posix standard header file, the "
1719 "first thing to try is +posixlib. This make LCLint use "
1720 "the posix library specification instead of reading the posix "
1723 llmsglit ("Otherwise, you may need to either manually define the problematic "
1724 "type (e.g., add -Dmlink_t=int to your .lclintrc file) or force "
1725 "lclint to process the header file that defines it. This is done "
1726 "by setting -skipansiheaders or -skipposixheaders before "
1727 "the file that defines the type is #include'd.");
1728 llmsglit ("(See lclint -help "
1729 "skipansiheaders and lclint -help skipposixheaders for a list of "
1730 "standard headers.) For example, if <sys/local.h> uses a type "
1731 "defined by posix header <sys/types.h> but not defined by the "
1732 "posix library, we might do: ");
1734 llmsglit (" /*@-skipposixheaders@*/");
1735 llmsglit (" # include <sys/types.h>");
1736 llmsglit (" /*@=skipposixheaders@*/");
1737 llmsglit (" # include <sys/local.h>");
1739 llmsglit ("to force LCLint to process <sys/types.h>.");
1741 llmsglit ("At last resort, +trytorecover can be used to make LCLint attempt "
1742 "to continue after a parse error. This is usually not successful "
1743 "and the author does not consider assertion failures when +trytorecover "
1744 "is used to be bugs.");
1748 printAnnotations (void)
1750 llmsglit ("Annotations");
1751 llmsglit ("-----------");
1753 llmsglit ("Annotations are semantic comments that document certain "
1754 "assumptions about functions, variables, parameters, and types. ");
1756 llmsglit ("They may be used to indicate where the representation of a "
1757 "user-defined type is hidden, to limit where a global variable may "
1758 "be used or modified, to constrain what a function implementation "
1759 "may do to its parameters, and to express checked assumptions about "
1760 "variables, types, structure fields, function parameters, and "
1761 "function results.");
1763 llmsglit ("Annotations are introduced by \"/*@\". The role of the @ may be "
1764 "played by any printable character, selected using -commentchar <char>.");
1766 llmsglit ("Consult the User's Guide for descriptions of checking associated with each annotation.");
1768 llmsglit ("Globals: (in function declarations)");
1769 llmsglit (" /*@globals <globitem>,+ @*/");
1770 llmsglit (" globitem is an identifier, internalState or fileSystem");
1772 llmsglit ("Modifies: (in function declarations)");
1773 llmsglit (" /*@modifies <moditem>,+ @*/");
1774 llmsglit (" moditem is an lvalue");
1775 llmsglit (" /*@modifies nothing @*/");
1776 llmsglit (" /*@*/ (Abbreviation for no globals and modifies nothing.)");
1778 llmsglit ("Iterators:");
1779 llmsglit (" /*@iter <identifier> (<parameter-type-list>) @*/ - declare an iterator");
1781 llmsglit ("Constants:");
1782 llmsglit (" /*@constant <declaration> @*/ - declares a constant");
1784 llmsglit ("Alternate Types:");
1785 llmsglit (" /*@alt <basic-type>,+ @*/");
1786 llmsglit (" (e.g., int /*@alt char@*/ is a type matching either int or char)");
1788 llmsglit ("Declarator Annotations");
1790 llmsglit ("Type Definitions:");
1791 llmsglit (" /*@abstract@*/ - representation is hidden from clients");
1792 llmsglit (" /*@concrete@*/ - representation is visible to clients");
1793 llmsglit (" /*@immutable@*/ - instances of the type cannot change value");
1794 llmsglit (" /*@mutable@*/ - instances of the type can change value");
1795 llmsglit (" /*@refcounted@*/ - reference counted type");
1797 llmsglit ("Global Variables:");
1798 llmsglit (" /*@unchecked@*/ - weakest checking for global use");
1799 llmsglit (" /*@checkmod@*/ - check modification by not use of global");
1800 llmsglit (" /*@checked@*/ - check use and modification of global");
1801 llmsglit (" /*@checkedstrict@*/ - check use of global strictly");
1803 llmsglit ("Memory Management:");
1804 llmsglit (" /*@dependent@*/ - a reference to externally-owned storage");
1805 llmsglit (" /*@keep@*/ - a parameter that is kept by the called function");
1806 llmsglit (" /*@killref@*/ - a refcounted parameter, killed by the call");
1807 llmsglit (" /*@only@*/ - an unshared reference");
1808 llmsglit (" /*@owned@*/ - owner of storage that may be shared by /*@dependent@*/ references");
1809 llmsglit (" /*@shared@*/ - shared reference that is never deallocated");
1810 llmsglit (" /*@temp@*/ - temporary parameter");
1812 llmsglit ("Aliasing:");
1813 llmsglit (" /*@unique@*/ - may not be aliased by any other visible reference");
1814 llmsglit (" /*@returned@*/ - may be aliased by the return value");
1816 llmsglit ("Exposure:");
1817 llmsglit (" /*@observer@*/ - reference that cannot be modified");
1818 llmsglit (" /*@exposed@*/ - exposed reference to storage in another object");
1820 llmsglit ("Definition State:");
1821 llmsglit (" /*@out@*/ - storage reachable from reference need not be defined");
1822 llmsglit (" /*@in@*/ - all storage reachable from reference must be defined");
1823 llmsglit (" /*@partial@*/ - partially defined, may have undefined fields");
1824 llmsglit (" /*@reldef@*/ - relax definition checking");
1826 llmsglit ("Global State: (for globals lists, no /*@, since list is already in /*@\'s)");
1827 llmsglit (" undef - variable is undefined before the call");
1828 llmsglit (" killed - variable is undefined after the call");
1830 llmsglit ("Null State:");
1831 llmsglit (" /*@null@*/ - possibly null pointer");
1832 llmsglit (" /*@notnull@*/ - non-null pointer");
1833 llmsglit (" /*@relnull@*/ - relax null checking");
1835 llmsglit ("Null Predicates:");
1836 llmsglit (" /*@truenull@*/ - if result is TRUE, first parameter is NULL");
1837 llmsglit (" /*@falsenull@*/ - if result is TRUE, first parameter is not NULL");
1839 llmsglit ("Execution:");
1840 llmsglit (" /*@exits@*/ - function never returns");
1841 llmsglit (" /*@mayexit@*/ - function may or may not return");
1842 llmsglit (" /*@trueexit@*/ - function does not return if first parameter is TRUE");
1843 llmsglit (" /*@falseexit@*/ - function does not return if first parameter if FALSE");
1844 llmsglit (" /*@neverexit@*/ - function always returns");
1846 llmsglit ("Side-Effects:");
1847 llmsglit (" /*@sef@*/ - corresponding actual parameter has no side effects");
1849 llmsglit ("Declaration:");
1850 llmsglit (" /*@unused@*/ - need not be used (no unused errors reported)");
1851 llmsglit (" /*@external@*/ - defined externally (no undefined error reported)");
1854 llmsglit (" /*@fallthrough@*/ - fall-through case");
1856 llmsglit ("Break:");
1857 llmsglit (" /*@innerbreak@*/ - break is breaking an inner loop or switch");
1858 llmsglit (" /*@loopbreak@*/ - break is breaking a loop");
1859 llmsglit (" /*@switchbreak@*/ - break is breaking a switch");
1860 llmsglit (" /*@innercontinue@*/ - continue is continuing an inner loop");
1862 llmsglit ("Unreachable Code:");
1863 llmsglit (" /*@notreached@*/ - statement may be unreachable.");
1865 llmsglit ("Special Functions:");
1866 llmsglit (" /*@printflike@*/ - check variable arguments like printf");
1867 llmsglit (" /*@scanflike@*/ - check variable arguments like scanf");
1871 printComments (void)
1873 llmsglit ("Control Comments");
1874 llmsglit ("----------------");
1876 llmsglit ("Setting Flags");
1878 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.");
1880 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,");
1881 llmsglit (" /*@+boolint -modifies =showfunc@*/");
1882 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).");
1884 llmsglit ("Error Suppression");
1886 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.");
1888 llmsglit ("/*@ignore@*/ ... /*@end@*/");
1890 (cstring_makeLiteral
1891 ("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."));
1892 llmsglit ("/*@i@*/");
1894 (cstring_makeLiteral
1895 ("No errors will be reported from an /*@i@*/ comment to the end of the line."));
1896 llmsglit ("/*@i<n>@*/");
1898 (cstring_makeLiteral
1899 ("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."));
1900 llmsglit ("/*@t@*/, /*@t<n>@*/");
1902 (cstring_makeLiteral
1903 ("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."));
1905 llmsglit ("Type Access");
1907 llmsglit ("/*@access <type>@*/");
1908 llmsglit (" Allows the following code to access the representation of <type>");
1909 llmsglit ("/*@noaccess <type>@*/");
1910 llmsglit (" Hides the representation of <type>");
1912 llmsglit ("Macro Expansion");
1914 llmsglit ("/*@notfunction@*/");
1916 (cstring_makeLiteral
1917 ("Indicates that the next macro definition is not intended to be a "
1918 "function, and should be expanded in line instead of checked as a "
1919 "macro function definition."));
1926 llmsglit ("Flag Categories");
1927 llmsglit ("---------------");
1928 listAllCategories ();
1929 llmsglit ("\nTo see the flags in a flag category, do\n lclint -help flags <category>");
1930 llmsglit ("To see a list of all flags in alphabetical order, do\n lclint -help flags alpha");
1931 llmsglit ("To see a full description of all flags, do\n lclint -help flags full");
1935 printMaintainer (void)
1937 llmsg (message ("Maintainer: %s", cstring_makeLiteralTemp (LCLINT_MAINTAINER)));
1938 llmsglit (LCL_COMPILE);
1944 llmsglit ("Mailing Lists");
1945 llmsglit ("-------------");
1947 llmsglit ("There are two mailing lists associated with LCLint: ");
1949 llmsglit (" lclint-announce@virginia.edu");
1951 llmsglit (" Reserved for announcements of new releases and bug fixes.");
1952 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
1953 llmsglit (" subscribe lclint-announce");
1955 llmsglit (" lclint-interest@virginia.edu");
1957 llmsglit (" Informal discussions on the use and development of lclint.");
1958 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
1959 llmsglit (" subscribe lclint-interest");
1963 printReferences (void)
1965 llmsglit ("References");
1966 llmsglit ("----------");
1968 llmsglit ("The LCLint web site is http://lclint.cs.virginia.edu");
1970 llmsglit ("Technical papers relating to LCLint include:");
1972 llmsglit (" David Evans. \"Static Detection of Dynamic Memory Errors\".");
1973 llmsglit (" SIGPLAN Conference on Programming Language Design and ");
1974 llmsglit (" Implementation (PLDI '96), Philadelphia, PA, May 1996.");
1976 llmsglit (" David Evans, John Guttag, Jim Horning and Yang Meng Tan. ");
1977 llmsglit (" \"LCLint: A Tool for Using Specifications to Check Code\".");
1978 llmsglit (" SIGSOFT Symposium on the Foundations of Software Engineering,");
1979 llmsglit (" December 1994.");
1981 llmsglit ("A general book on Larch is:");
1983 llmsglit (" Guttag, John V., Horning, James J., (with Garland, S. J., Jones, ");
1984 llmsglit (" K. D., Modet, A., and Wing, J. M.), \"Larch: Languages and Tools ");
1985 llmsglit (" for Formal Specification\", Springer-Verlag, 1993.");
1989 describePrefixCodes (void)
1991 llmsglit ("Prefix Codes");
1992 llmsglit ("------------");
1994 llmsglit ("These characters have special meaning in name prefixes:");
1996 llmsg (message (" %h Any uppercase letter [A-Z]", PFX_UPPERCASE));
1997 llmsg (message (" %h Any lowercase letter [a-z]", PFX_LOWERCASE));
1998 llmsg (message (" %h Any character (valid in a C identifier)", PFX_ANY));
1999 llmsg (message (" %h Any digit [0-9]", PFX_DIGIT));
2000 llmsg (message (" %h Any non-uppercase letter [a-z0-9_]", PFX_NOTUPPER));
2001 llmsg (message (" %h Any non-lowercase letter [A-Z0-9_]", PFX_NOTLOWER));
2002 llmsg (message (" %h Any letter [A-Za-z]", PFX_ANYLETTER));
2003 llmsg (message (" %h Any letter or digit [A-Za-z0-9]", PFX_ANYLETTERDIGIT));
2004 llmsglit (" * Zero or more repetitions of the previous character class until the end of the name");
2013 eval = context_getLarchPath ();
2014 def = osd_getEnvironmentVariable (LARCH_PATH);
2016 if (cstring_isDefined (def) ||
2017 !cstring_equal (eval, cstring_fromChars (DEFAULT_LARCHPATH)))
2019 llmsg (message ("LARCH_PATH = %s", eval));
2023 llmsg (message ("LARCH_PATH = <not set> (default = %s)",
2024 cstring_fromChars (DEFAULT_LARCHPATH)));
2027 llmsglit (" --- path used to find larch initialization files and LSL traits");
2029 eval = context_getLCLImportDir ();
2030 def = osd_getEnvironmentVariable (cstring_makeLiteralTemp (LCLIMPORTDIR));
2032 if (cstring_isDefined (def) ||
2033 !cstring_equal (eval, cstring_fromChars (DEFAULT_LCLIMPORTDIR)))
2035 llmsg (message ("%q = %s", cstring_makeLiteral (LCLIMPORTDIR), eval));
2039 llmsg (message ("%s = <not set, default: %s>", cstring_makeLiteralTemp (LCLIMPORTDIR),
2040 cstring_makeLiteralTemp (DEFAULT_LCLIMPORTDIR)));
2043 llmsglit (" --- directory containing lcl standard library files "
2044 "(import with < ... >)");;
2047 ("include path = %q (set by environment variable %s and -I flags)",
2048 cppReader_getIncludePath (), INCLUDEPATH_VAR));
2050 llmsglit (" --- path used to find #include'd files");
2053 ("systemdirs = %s (set by -systemdirs or environment variable %s)", /*@i413223@*/
2054 context_getString (FLG_SYSTEMDIRS),
2057 llmsglit (" --- if file is found on this path, it is treated as a system file for error reporting");
2066 fprintf (stderr, "*** Interrupt\n");
2067 llexit (LLINTERRUPT);
2072 /* Cheat when there are parse errors */
2075 fprintf (stderr, "*** Segmentation Violation\n");
2077 /* Don't catch it if fileloc_unparse causes a signal */
2078 (void) signal (SIGSEGV, NULL);
2080 loc = fileloc_unparse (g_currentloc);
2082 fprintf (stderr, "*** Location (not trusted): %s\n",
2083 cstring_toCharsSafe (loc));
2086 fprintf (stderr, "*** Please report bug to %s\n", LCLINT_MAINTAINER);
2090 fprintf (stderr, "*** Signal: %d\n", i);
2092 fprintf (stderr, "*** Location (not trusted): %s\n",
2093 cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
2096 fprintf (stderr, "*** Please report bug to %s ***\n", LCLINT_MAINTAINER);
2104 static bool doneCleanup = FALSE;
2106 /* make sure this is only called once! */
2108 if (doneCleanup) return;
2112 if (context_getFlag (FLG_KEEP))
2114 check (fputs ("Temporary files kept:\n", stderr) != EOF);
2115 fileTable_printTemps (context_fileTable ());
2120 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
2124 llbug (message ("Files unclosed: %d", nfiles));
2127 fileTable_cleanup (context_fileTable ());
2134 ** cleans up temp files (if necessary)
2141 DPRINTF (("llexit: %d", status));
2144 if (status == LLFAILURE)
2152 if (status != LLFAILURE)
2154 context_destroyMod ();
2155 exprNode_destroyMod ();
2158 uentry_destroyMod ();
2159 typeIdSet_destroyMod ();
2162 dmalloc_shutdown ();
2166 exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
2170 loadrc (/*:open:*/ FILE *rcfile, cstringSList *passThroughArgs)
2171 /*@ensures closed rcfile@*/
2173 char *s = mstring_create (MAX_LINE_LENGTH);
2176 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2180 while (reader_readLine (rcfile, s, MAX_LINE_LENGTH) != NULL)
2187 DPRINTF (("Line: %s", s));
2188 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2190 while (*s == ' ' || *s == '\t')
2198 bool escaped = FALSE;
2199 bool quoted = FALSE;
2202 DPRINTF (("Process: %s", s));
2203 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2204 /* comment characters */
2205 if (c == '#' || c == ';' || c == '\n')
2211 if (c == '-' || c == '+')
2218 voptgenerror (FLG_BADFLAG,
2219 message ("Bad flag syntax (+ or - expected, "
2220 "+ is assumed): %s",
2221 cstring_fromChars (s)),
2232 while ((c = *s) != '\0')
2233 { /* remember to handle spaces and quotes in -D and -U ... */
2259 if (c == ' ' || c == '\t' || c == '\n')
2261 /*@innerbreak@*/ break;
2269 DPRINTF (("Nulling: %c", *s));
2272 if (mstring_isEmpty (thisflag))
2274 llfatalerror (message ("Missing flag: %s",
2275 cstring_fromChars (os)));
2278 DPRINTF (("Flag: %s", thisflag));
2280 opt = identifyFlag (cstring_fromChars (thisflag));
2282 if (flagcode_isSkip (opt))
2286 else if (flagcode_isInvalid (opt))
2288 DPRINTF (("Invalid: %s", thisflag));
2290 if (isMode (cstring_fromChars (thisflag)))
2292 context_setMode (cstring_fromChars (thisflag));
2296 voptgenerror (FLG_BADFLAG,
2297 message ("Unrecognized option: %s",
2298 cstring_fromChars (thisflag)),
2304 context_userSetFlag (opt, set);
2306 if (flagcode_hasArgument (opt))
2308 if (opt == FLG_HELP)
2311 voptgenerror (FLG_BADFLAG,
2312 message ("Cannot use help in rc files"),
2315 else if (flagcode_isPassThrough (opt)) /* -D or -U */
2317 cstring arg = cstring_fromCharsNew (thisflag);
2318 cstring_markOwned (arg);
2319 *passThroughArgs = cstringSList_add (*passThroughArgs, arg);
2320 DPRINTF (("Pass through: %s",
2321 cstringSList_unparse (*passThroughArgs)));
2323 else if (opt == FLG_INCLUDEPATH
2324 || opt == FLG_SPECPATH)
2326 cstring dir = cstring_suffix (cstring_fromChars (thisflag), 1); /* skip over I/S */
2330 case FLG_INCLUDEPATH:
2331 cppAddIncludeDir (dir);
2332 /*@switchbreak@*/ break;
2335 g_localSpecPath = cstring_toCharsSafe
2336 (message ("%s:%s", cstring_fromChars (g_localSpecPath), dir));
2338 /*@switchbreak@*/ break;
2342 else if (flagcode_hasString (opt)
2343 || flagcode_hasValue (opt)
2344 || opt == FLG_INIT || opt == FLG_OPTF)
2346 cstring extra = cstring_undefined;
2351 rest = mstring_copy (s);
2352 DPRINTF (("Here: rest = %s", rest));
2356 while ((rchar = *rest) != '\0'
2357 && (isspace ((int) rchar)))
2363 DPRINTF (("Yo: %s", rest));
2365 while ((rchar = *rest) != '\0'
2366 && !isspace ((int) rchar))
2368 extra = cstring_appendChar (extra, rchar);
2373 DPRINTF (("Yo: %s", extra));
2376 if (cstring_isUndefined (extra))
2382 ("Flag %s must be followed by an argument",
2383 flagcode_unparse (opt)),
2390 DPRINTF (("Here we are: %s", extra));
2392 if (flagcode_hasValue (opt))
2394 DPRINTF (("Set value flag: %s", extra));
2395 setValueFlag (opt, extra);
2396 cstring_free (extra);
2398 else if (opt == FLG_OPTF)
2400 FILE *innerf = fopen (cstring_toCharsSafe (extra), "r");
2401 cstring_markOwned (extra);
2405 fileloc fc = g_currentloc;
2406 g_currentloc = fileloc_createRc (extra);
2407 loadrc (innerf, passThroughArgs);
2408 fileloc_reallyFree (g_currentloc);
2416 message ("Options file not found: %s",
2421 else if (opt == FLG_INIT)
2424 llassert (inputStream_isUndefined (initFile));
2426 initFile = inputStream_create
2428 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
2431 cstring_free (extra);
2434 else if (flagcode_hasString (opt))
2436 if (cstring_firstChar (extra) == '"')
2438 if (cstring_lastChar (extra) == '"')
2440 char *extras = cstring_toCharsSafe (extra);
2442 llassert (extras[strlen(extras) - 1] == '"');
2443 extras[strlen(extras) - 1] = '\0';
2444 extra = cstring_fromChars (extras + 1);
2445 DPRINTF (("Remove quites: %s", extra));
2451 message ("Unmatched \" in option string: %s",
2457 setStringFlag (opt, extra);
2461 cstring_free (extra);
2474 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2475 while ((c == ' ') || (c == '\t'))
2481 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2485 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2487 check (fclose (rcfile) == 0);
2490 static fileIdList preprocessFiles (fileIdList fl, bool xhfiles)
2491 /*@modifies fileSystem@*/
2493 bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
2494 int skip = (fileIdList_size (fl) / 5);
2495 int filesprocessed = 0;
2496 fileIdList dfiles = fileIdList_create ();
2498 fileloc_free (g_currentloc);
2499 g_currentloc = fileloc_createBuiltin ();
2501 fileIdList_elements (fl, fid)
2503 cstring ppfname = fileName (fid);
2509 if (osd_findOnLarchPath (ppfname, &fpath) == OSD_FILEFOUND)
2511 if (cstring_equal (ppfname, fpath))
2517 DPRINTF (("xh file: %s", fpath));
2519 fileTable_setFilePath (context_fileTable (), fid, fpath);
2524 lldiagmsg (message ("Cannot find .xh file on LARCH_PATH: %s", ppfname));
2525 lldiagmsg (cstring_makeLiteral (" Check LARCH_PATH environment variable."));
2526 ppfname = cstring_undefined;
2531 if (!(osd_fileIsReadable (ppfname)))
2533 lldiagmsg (message ("Cannot open file: %s", ppfname));
2534 ppfname = cstring_undefined;
2538 if (cstring_isDefined (ppfname))
2540 fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
2542 llassert (cstring_isNonEmpty (ppfname));
2546 if ((filesprocessed % skip) == 0)
2548 if (filesprocessed == 0) {
2549 fprintf (stderr, " ");
2552 fprintf (stderr, ".");
2555 (void) fflush (stderr);
2560 if (cppProcess (ppfname, fileName (dfile)) != 0)
2562 llfatalerror (message ("Preprocessing error for file: %s",
2563 rootFileName (fid)));
2566 fileIdList_add (dfiles, dfile);
2568 } end_fileIdList_elements;
2573 /* This should be in an lclUtils.c file... */
2575 char *specFullName (char *specfile, /*@out@*/ char **inpath)
2577 /* extract the path and the specname associated with the given file */
2578 char *specname = (char *) dmalloc (sizeof (*specname)
2579 * (strlen (specfile) + 9));
2580 char *ospecname = specname;
2581 char *path = (char *) dmalloc (sizeof (*path) * (strlen (specfile)));
2585 /* initialized path to empty string or may have accidental garbage */
2588 /*@-mayaliasunique@*/
2589 strcpy (specname, specfile);
2590 /*@=mayaliasunique@*/
2592 /* trim off pathnames in specfile */
2593 size = strlen (specname);
2595 for (i = size_toInt (size) - 1; i >= 0; i--)
2597 if (specname[i] == CONNECTCHAR)
2599 /* strcpy (specname, (char *)specname+i+1); */
2600 for (j = 0; j <= i; j++) /* include '/' */
2602 path[j] = specname[j];
2612 ** also remove .lcl file extension, assume it's the last extension
2616 size = strlen (specname);
2618 for (i = size_toInt (size) - 1; i >= 0; i--)
2620 if (specname[i] == '.')
2630 ** If specname no longer points to the original char,
2631 ** we need to allocate a new pointer and copy the string.
2634 if (specname != ospecname) {
2635 char *rspecname = (char *) dmalloc (sizeof (*rspecname) * (strlen (specname) + 1));
2636 strcpy (rspecname, specname); /* evs 2000-05-16: Bug: was ospecname! */