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 voptgenerror (FLG_BADFLAG,
491 message ("Unclosed quote in flag: %s",
492 cstring_fromChars (arg)),
501 ** If the value is surrounded by single quotes ('), remove
502 ** them. This is an artifact of UNIX command line?
505 def = osd_fixDefine (cstring_fromChars (arg + 1));
506 DPRINTF (("Do define: %s", def));
508 DPRINTF (("After define"));
510 } else if (arg[0] == 'U') {
511 cppDoUndefine (cstring_fromChars (arg + 1));
520 void showHerald (void)
522 if (hasShownHerald || context_getFlag (FLG_QUIET)) return;
526 fprintf (g_msgstream, "%s\n\n", LCL_VERSION);
527 hasShownHerald = TRUE;
532 static void addFile (fileIdList files, /*@only@*/ cstring s)
534 if (fileTable_exists (context_fileTable (), s))
537 lldiagmsg (message ("File listed multiple times: %s", s));
542 fileIdList_add (files, fileTable_addFileOnly (context_fileTable (), s));
546 static void addXHFile (fileIdList files, /*@only@*/ cstring s)
548 if (fileTable_exists (context_fileTable (), s))
551 lldiagmsg (message ("File listed multiple times: %s", s));
556 fileIdList_add (files, fileTable_addXHFile (context_fileTable (), s));
562 ** Disable MSVC++ warning about return value. Methinks humbly lclint control
563 ** comments are a mite more legible.
567 # pragma warning (disable:4035)
570 int main (int argc, char *argv[])
572 /*@globals killed undef g_currentloc,
576 /*@modifies g_currentloc, fileSystem,
580 /*@globals killed undef g_currentloc,
581 killed undef initFile,
582 killed g_localSpecPath,
583 killed undef g_currentSpec,
584 killed undef g_currentSpecName,
588 /*@modifies g_currentloc, initFile,
589 g_localSpecPath, g_currentSpec, g_currentSpecName, fileSystem,
594 bool first_time = TRUE;
595 bool showhelp = FALSE;
598 inputStream sourceFile = inputStream_undefined;
600 fileIdList dercfiles;
601 cstringSList fl = cstringSList_undefined;
602 cstringSList passThroughArgs = cstringSList_undefined;
603 fileIdList cfiles, xfiles, lclfiles, mtfiles;
604 clock_t before, lcltime, libtime, pptime, cptime, rstime;
607 g_msgstream = stdout;
609 (void) signal (SIGINT, interrupt);
610 (void) signal (SIGSEGV, interrupt);
612 cfiles = fileIdList_create ();
613 xfiles = fileIdList_create ();
614 lclfiles = fileIdList_create ();
615 mtfiles = fileIdList_create ();
618 clabstract_initMod ();
619 typeIdSet_initMod ();
620 cppReader_initMod ();
623 g_currentloc = fileloc_createBuiltin ();
628 context_setInCommandLine ();
640 ** Add include directories from environment.
644 cstring incval = cstring_copy (osd_getEnvironmentVariable (INCLUDEPATH_VAR));
645 cstring oincval = incval;
647 if (cstring_isDefined (incval))
650 ** Each directory on the include path is a system include directory.
653 DPRINTF (("include: %s", incval));
654 context_setString (FLG_SYSTEMDIRS, cstring_copy (incval));
656 while (cstring_isDefined (incval))
659 char *nextsep = strchr (incval, PATH_SEPARATOR);
665 dir = cstring_copy (incval);
667 if (cstring_length (dir) == 0
668 || !isalpha ((int) cstring_firstChar (dir)))
671 ** win32 environment values can have special values,
677 cppAddIncludeDir (dir);
680 *nextsep = PATH_SEPARATOR;
681 incval = cstring_fromChars (nextsep + 1);
689 /*@noaccess cstring@*/
693 cstring_free (oincval);
697 ** check RCFILE for default flags
701 cstring home = osd_getHomeDir ();
704 bool defaultf = TRUE;
707 for (i = 1; i < argc; i++)
712 if (*thisarg == '-' || *thisarg == '+')
716 if (mstring_equal (thisarg, "nof"))
720 else if (mstring_equal (thisarg, "f"))
726 rcfile = fopen (fname, "r");
730 fileloc oloc = g_currentloc;
732 g_currentloc = fileloc_createRc (cstring_fromChars (fname));
733 loadrc (rcfile, &passThroughArgs);
734 fileloc_reallyFree (g_currentloc);
740 lldiagmsg (message ("Options file not found: %s",
741 cstring_fromChars (fname)));
746 (cstring_makeLiteral ("Flag f to select options file "
747 "requires an argument"));
751 ; /* wait to process later */
758 if (!cstring_isEmpty (home)) {
759 fname = cstring_toCharsSafe (message ("%s%h%s", home, CONNECTCHAR,
760 cstring_fromChars (RCFILE)));
761 mstring_markFree (fname);
767 if (!nof && defaultf)
769 if (!mstring_isEmpty (fname)) {
770 rcfile = fopen (fname, "r");
774 fileloc oloc = g_currentloc;
776 g_currentloc = fileloc_createRc (cstring_fromChars (fname));
777 loadrc (rcfile, &passThroughArgs);
778 fileloc_reallyFree (g_currentloc);
783 # if defined(MSDOS) || defined(OS2)
784 fname = cstring_toCharsSafe (message ("%s",
785 cstring_fromChars (RCFILE)));
787 fname = cstring_toCharsSafe (message ("./%s",
788 cstring_fromChars (RCFILE)));
791 rcfile = fopen (fname, "r");
795 fileloc oloc = g_currentloc;
797 g_currentloc = fileloc_createRc (cstring_fromChars (fname));
798 loadrc (rcfile, &passThroughArgs);
799 fileloc_reallyFree (g_currentloc);
809 for (i = 1; i < argc; i++)
825 if (*thisarg == '-' || *thisarg == '+')
827 thisarg++; /* skip '-' */
829 if (mstring_equal (thisarg, "modes"))
831 llmsg (describeModes ());
833 else if (mstring_equal (thisarg, "vars")
834 || mstring_equal (thisarg, "env"))
838 else if (mstring_equal (thisarg, "annotations"))
842 else if (mstring_equal (thisarg, "parseerrors"))
846 else if (mstring_equal (thisarg, "comments"))
850 else if (mstring_equal (thisarg, "prefixcodes"))
852 describePrefixCodes ();
854 else if (mstring_equal (thisarg, "references")
855 || mstring_equal (thisarg, "refs"))
859 else if (mstring_equal (thisarg, "mail"))
863 else if (mstring_equal (thisarg, "maintainer")
864 || mstring_equal (thisarg, "version"))
868 else if (mstring_equal (thisarg, "flags"))
872 char *next = argv[i + 1];
874 if (specialFlagsHelp (next))
880 flagkind k = identifyCategory (cstring_fromChars (next));
896 cstring s = describeFlag (cstring_fromChars (thisarg));
898 if (cstring_isDefined (s))
906 if (*thisarg == '-' || *thisarg == '+')
908 bool set = (*thisarg == '+');
911 thisarg++; /* skip '-' */
912 flagname = cstring_fromChars (thisarg);
914 DPRINTF (("Flag: %s", flagname));
915 opt = identifyFlag (flagname);
916 DPRINTF (("Flag: %s", flagcode_unparse (opt)));
918 if (flagcode_isSkip (opt))
920 DPRINTF (("Skipping!"));
922 else if (flagcode_isInvalid (opt))
924 DPRINTF (("Invalid: %s", flagname));
926 if (isMode (flagname))
928 context_setMode (flagname);
932 DPRINTF (("Error!"));
933 voptgenerror (FLG_BADFLAG,
934 message ("Unrecognized option: %s",
935 cstring_fromChars (thisarg)),
941 context_userSetFlag (opt, set);
943 if (flagcode_hasArgument (opt))
949 else if (flagcode_isPassThrough (opt)) /* -D or -U */
951 passThroughArgs = cstringSList_add
952 (passThroughArgs, cstring_fromChars (thisarg));
954 else if (flagcode_hasValue (opt))
958 setValueFlag (opt, cstring_fromChars (argv[i]));
964 ("Flag %s must be followed by a number",
965 flagcode_unparse (opt)));
968 else if (opt == FLG_INCLUDEPATH || opt == FLG_SPECPATH)
970 cstring dir = cstring_suffix (cstring_fromChars (thisarg), 1); /* skip over I */
974 case FLG_INCLUDEPATH:
975 cppAddIncludeDir (dir);
976 /*@switchbreak@*/ break;
979 g_localSpecPath = cstring_toCharsSafe
981 cstring_fromChars (g_localSpecPath),
985 /*@switchbreak@*/ break;
989 else if (flagcode_hasString (opt)
990 || opt == FLG_INIT || opt == FLG_OPTF)
994 cstring arg = cstring_fromChars (argv[i]);
998 ; /* -f already processed */
1000 else if (opt == FLG_INIT)
1003 initFile = inputStream_create
1005 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
1012 DPRINTF (("String flag: %s / %s",
1013 flagcode_unparse (opt), arg));
1014 if (opt == FLG_MTSFILE)
1017 ** arg identifies mts files
1020 addFile (mtfiles, message ("%s%s", arg, MTS_EXTENSION));
1021 addXHFile (xfiles, message ("%s%s", arg, XH_EXTENSION));
1025 setStringFlag (opt, arg);
1033 ("Flag %s must be followed by a string",
1034 flagcode_unparse (opt)));
1044 else /* its a filename */
1046 DPRINTF (("Adding filename: %s", thisarg));
1047 fl = cstringSList_add (fl, cstring_fromChars (thisarg));
1055 ** create lists of C and LCL files
1058 cstringSList_elements (fl, current)
1060 cstring ext = fileLib_getExtension (current);
1062 if (cstring_isUndefined (ext))
1064 /* no extension --- both C and LCL with default extensions */
1066 addFile (cfiles, message ("%s%s", current, C_EXTENSION));
1067 addFile (lclfiles, message ("%s%s", current, LCL_EXTENSION));
1069 else if (cstring_equal (ext, XH_EXTENSION))
1071 addXHFile (xfiles, cstring_copy (current));
1073 else if (cstring_equal (ext, LCL_EXTENSION))
1075 addFile (lclfiles, cstring_copy (current));
1077 else if (fileLib_isCExtension (ext))
1079 addFile (cfiles, cstring_copy (current));
1081 else if (cstring_equal (ext, MTS_EXTENSION))
1083 addFile (mtfiles, cstring_copy (current));
1088 (FLG_FILEEXTENSIONS,
1089 message ("Unrecognized file extension: %s (assuming %s is C source code)",
1093 addFile (cfiles, cstring_copy (current));
1095 } end_cstringSList_elements;
1097 showHerald (); /*@i723 move earlier? */
1105 fprintf (g_msgstream, "\n");
1107 fileIdList_free (cfiles);
1108 fileIdList_free (xfiles);
1109 fileIdList_free (lclfiles);
1118 inittime = clock ();
1120 context_resetErrors ();
1121 context_clearInCommandLine ();
1123 anylcl = !fileIdList_isEmpty (lclfiles);
1125 if (context_doMerge ())
1127 cstring m = context_getMerge ();
1129 if (context_getFlag (FLG_SHOWSCAN))
1131 fprintf (g_msgstream, "< loading %s ", cstring_toCharsSafe (m));
1136 if (context_getFlag (FLG_SHOWSCAN))
1138 fprintf (g_msgstream, " >\n");
1141 if (!usymtab_existsType (context_getBoolName ()))
1143 usymtab_initBool ();
1148 if (!context_getFlag (FLG_NOLIB) && loadStandardState ())
1157 /* setup bool type and constants */
1158 usymtab_initBool ();
1161 fileloc_free (g_currentloc);
1162 g_currentloc = fileloc_createBuiltin ();
1165 ** Read metastate files (must happen before loading libraries)
1168 fileIdList_elements (mtfiles, mtfile)
1170 context_setFileId (mtfile);
1172 if (context_getFlag (FLG_SHOWSCAN))
1174 lldiagmsg (message ("< processing %s >", rootFileName (mtfile)));
1177 mtreader_readFile (cstring_copy (fileName (mtfile)));
1178 } end_fileIdList_elements;
1185 llfatalerror (cstring_makeLiteral ("This version of LCLint does not handle LCL files."));
1187 lslProcess (lclfiles);
1191 usymtab_initGlobalMarker ();
1196 ** call the pre-preprocessor and /lib/cpp to generate appropriate
1201 context_setInCommandLine ();
1203 DPRINTF (("Pass through: %s", cstringSList_unparse (passThroughArgs)));
1205 cstringSList_elements (passThroughArgs, thisarg) {
1206 handlePassThroughFlag (cstring_toCharsSafe (thisarg));
1207 } end_cstringSList_elements;
1209 cstringSList_free (passThroughArgs);
1213 DPRINTF (("Initializing cpp reader!"));
1214 cppReader_initialize ();
1215 cppReader_saveDefinitions ();
1217 context_clearInCommandLine ();
1219 if (!context_getFlag (FLG_NOPP))
1225 if (context_getFlag (FLG_SHOWSCAN))
1227 fprintf (stderr, "< preprocessing");
1232 context_setPreprocessing ();
1233 dercfiles = preprocessFiles (xfiles, TRUE);
1234 tfiles = preprocessFiles (cfiles, FALSE);
1235 dercfiles = fileIdList_append (dercfiles, tfiles);
1236 fileIdList_free (tfiles);
1238 context_clearPreprocessing ();
1240 fileIdList_free (cfiles);
1242 if (context_getFlag (FLG_SHOWSCAN))
1244 fprintf (stderr, " >\n");
1252 dercfiles = fileIdList_append (cfiles, xfiles);
1257 ** now, check all the corresponding C files
1259 ** (for now these are just <file>.c, but after pre-processing
1260 ** will be <tmpprefix>.<file>.c)
1265 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1269 llbug (message ("Files unclosed: %d", nfiles));
1274 DPRINTF (("Initializing..."));
1276 exprNode_initMod ();
1278 DPRINTF (("Okay..."));
1280 fileIdList_elements (dercfiles, fid)
1282 sourceFile = inputStream_create (cstring_copy (fileName (fid)), C_EXTENSION, TRUE);
1283 context_setFileId (fid);
1285 /* Open source file */
1287 if (inputStream_isUndefined (sourceFile) || (!inputStream_open (sourceFile)))
1289 /* previously, this was ignored ?! */
1290 llbug (message ("Could not open temp file: %s", fileName (fid)));
1294 yyin = inputStream_getFile (sourceFile); /*< shared <- only */
1296 llassert (yyin != NULL);
1298 if (context_getFlag (FLG_SHOWSCAN))
1300 lldiagmsg (message ("< checking %s >", rootFileName (fid)));
1304 ** Every time, except the first time, through the loop,
1305 ** need to call yyrestart to clean up the parse buffer.
1310 (void) yyrestart (yyin);
1317 DPRINTF (("Entering..."));
1318 context_enterFile ();
1320 context_exitCFile ();
1322 (void) inputStream_close (sourceFile);
1324 } end_fileIdList_elements;
1328 /* process any leftover macros */
1330 context_processAllMacros ();
1332 /* check everything that was specified was defined */
1334 /* don't check if no c files were processed ?
1335 ** is this correct behaviour?
1338 if (context_getFlag (FLG_SHOWSCAN))
1340 lldiagmsg (cstring_makeLiteral ("< global checks >"));
1345 if (context_getLinesProcessed () > 0)
1347 usymtab_allDefined ();
1350 if (context_maybeSet (FLG_TOPUNUSED))
1352 uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main"));
1354 if (uentry_isValid (ue))
1356 uentry_setUsed (ue, fileloc_observeBuiltin ());
1362 if (context_maybeSet (FLG_EXPORTLOCAL))
1364 usymtab_exportLocal ();
1368 if (context_maybeSet (FLG_EXPORTHEADER))
1370 usymtab_exportHeader ();
1373 if (context_getFlag (FLG_SHOWUSES))
1375 usymtab_displayAllUses ();
1378 context_checkSuppressCounts ();
1380 if (context_doDump ())
1382 cstring dump = context_getDump ();
1393 if (context_getFlag (FLG_SHOWSUMMARY))
1400 bool isQuiet = context_getFlag (FLG_QUIET);
1401 cstring specErrors = cstring_undefined;
1403 int nspecErrors = lclNumberErrors ();
1408 if (context_neednl ())
1409 fprintf (g_msgstream, "\n");
1412 if (nspecErrors > 0)
1414 if (nspecErrors == context_getLCLExpect ())
1417 message ("%d spec error%& found, as expected\n ",
1422 if (context_getLCLExpect () > 0)
1425 message ("%d spec error%& found, expected %d\n ",
1427 (int) context_getLCLExpect ());
1431 specErrors = message ("%d spec error%& found\n ",
1439 if (context_getLCLExpect () > 0)
1441 specErrors = message ("No spec errors found, expected %d\n ",
1442 (int) context_getLCLExpect ());
1448 if (context_anyErrors ())
1450 if (context_numErrors () == context_getExpect ())
1453 llmsg (message ("Finished LCLint checking --- "
1454 "%s%d code error%& found, as expected",
1455 specErrors, context_numErrors ()));
1460 if (context_getExpect () > 0)
1464 ("Finished LCLint checking --- "
1465 "%s%d code error%& found, expected %d",
1466 specErrors, context_numErrors (),
1467 (int) context_getExpect ()));
1477 llmsg (message ("Finished LCLint checking --- "
1478 "%s%d code error%& found",
1479 specErrors, context_numErrors ()));
1488 if (context_getExpect () > 0)
1492 ("Finished LCLint checking --- "
1493 "%sno code errors found, expected %d",
1495 (int) context_getExpect ()));
1502 if (context_getLinesProcessed () > 0)
1505 llmsg (message ("Finished LCLint checking --- %sno code errors found",
1512 llmsg (message ("Finished LCLint checking --- %sno code processed",
1519 cstring_free (specErrors);
1522 if (context_getFlag (FLG_STATS))
1524 clock_t ttime = clock () - before;
1525 int specLines = context_getSpecLinesProcessed ();
1531 fprintf (g_msgstream, "%d spec, ", specLines);
1534 # ifndef CLOCKS_PER_SEC
1535 fprintf (g_msgstream, "%d source lines in %ld time steps (steps/sec unknown)\n",
1536 context_getLinesProcessed (),
1539 fprintf (g_msgstream, "%d source lines in %.2f s.\n",
1540 context_getLinesProcessed (),
1541 (double) ttime / CLOCKS_PER_SEC);
1549 if (context_getFlag (FLG_TIMEDIST))
1551 clock_t ttime = clock () - before;
1555 char *msg = (char *) dmalloc (256 * sizeof (*msg));
1560 "Time distribution (percent): initialize %.2f / lcl %.2f / "
1561 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1562 (100.0 * (double) (libtime - before) / ttime),
1563 (100.0 * (double) (lcltime - libtime) / ttime),
1564 (100.0 * (double) (pptime - lcltime) / ttime),
1565 (100.0 * (double) (cptime - pptime) / ttime),
1566 (100.0 * (double) (rstime - cptime) / ttime));
1571 "Time distribution (percent): initialize %.2f / "
1572 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1573 (100.0 * (double) (libtime - before) / ttime),
1574 (100.0 * (double) (pptime - libtime) / ttime),
1575 (100.0 * (double) (cptime - pptime) / ttime),
1576 (100.0 * (double) (rstime - cptime) / ttime));
1579 llgenindentmsgnoloc (cstring_fromCharsO (msg));
1583 llexit (expsuccess ? LLSUCCESS : LLFAILURE);
1588 ** Reenable return value warnings.
1590 # pragma warning (default:4035)
1598 llmsg (message ("Source files are .c, .h and %s files. If there is no suffix,",
1600 llmsg (message (" LCLint will look for <file>.c and <file>%s.", LCL_EXTENSION));
1602 llmsglit ("Use lclint -help <topic or flag name> for more information");
1604 llmsglit ("Topics:");
1606 llmsglit (" annotations (describes source-code annotations)");
1607 llmsglit (" comments (describes control comments)");
1608 llmsglit (" flags (describes flag categories)");
1609 llmsglit (" flags <category> (describes flags in category)");
1610 llmsglit (" flags all (short description of all flags)");
1611 llmsglit (" flags alpha (list all flags alphabetically)");
1612 llmsglit (" flags full (full description of all flags)");
1613 llmsglit (" mail (information on mailing lists)");
1614 llmsglit (" modes (show mode settings)");
1615 llmsglit (" parseerrors (help on handling parser errors)");
1616 llmsglit (" prefixcodes (character codes in namespace prefixes)");
1617 llmsglit (" references (sources for more information)");
1618 llmsglit (" vars (environment variables)");
1619 llmsglit (" version (information on compilation, maintainer)");
1624 specialFlagsHelp (char *next)
1626 if ((next != NULL) && (*next != '-') && (*next != '+'))
1628 if (mstring_equal (next, "alpha"))
1633 else if (mstring_equal (next, "all"))
1635 printAllFlags (TRUE, FALSE);
1638 else if (mstring_equal (next, "categories")
1639 || mstring_equal (next, "cats"))
1641 listAllCategories ();
1644 else if (mstring_equal (next, "full"))
1646 printAllFlags (FALSE, TRUE);
1661 printParseErrors (void)
1663 llmsglit ("Parse Errors");
1664 llmsglit ("------------");
1666 llmsglit ("LCLint will sometimes encounter a parse error for code that "
1667 "can be parsed with a local compiler. There are a few likely "
1668 "causes for this and a number of techniques that can be used "
1669 "to work around the problem.");
1671 llmsglit ("Compiler extensions --- compilers sometimes extend the C "
1672 "language with compiler-specific keywords and syntax. While "
1673 "it is not advisible to use these, oftentimes one has no choice "
1674 "when the system header files use compiler extensions. ");
1676 llmsglit ("LCLint supports some of the GNU (gcc) compiler extensions, "
1677 "if the +gnuextensions flag is set. You may be able to workaround "
1678 "other compiler extensions by using a pre-processor define. "
1679 "Alternately, you can surround the unparseable code with");
1681 llmsglit (" # ifndef __LCLINT__");
1683 llmsglit (" # endif");
1685 /* evans 2000-12-21 fixed typo reported by Jeroen Ruigrok/Asmodai */
1686 llmsglit ("Missing type definitions --- an undefined type name will usually "
1687 "lead to a parse error. This often occurs when a standard header "
1688 "file defines some type that is not part of the standard library. ");
1689 llmsglit ("By default, LCLint does not process the local files corresponding "
1690 "to standard library headers, but uses a library specification "
1691 "instead so dependencies on local system headers can be detected. "
1692 "If another system header file that does not correspond to a "
1693 "standard library header uses one of these superfluous types, "
1694 "a parse error will result.");
1696 llmsglit ("If the parse error is inside a posix standard header file, the "
1697 "first thing to try is +posixlib. This make LCLint use "
1698 "the posix library specification instead of reading the posix "
1701 llmsglit ("Otherwise, you may need to either manually define the problematic "
1702 "type (e.g., add -Dmlink_t=int to your .lclintrc file) or force "
1703 "lclint to process the header file that defines it. This is done "
1704 "by setting -skipansiheaders or -skipposixheaders before "
1705 "the file that defines the type is #include'd.");
1706 llmsglit ("(See lclint -help "
1707 "skipansiheaders and lclint -help skipposixheaders for a list of "
1708 "standard headers.) For example, if <sys/local.h> uses a type "
1709 "defined by posix header <sys/types.h> but not defined by the "
1710 "posix library, we might do: ");
1712 llmsglit (" /*@-skipposixheaders@*/");
1713 llmsglit (" # include <sys/types.h>");
1714 llmsglit (" /*@=skipposixheaders@*/");
1715 llmsglit (" # include <sys/local.h>");
1717 llmsglit ("to force LCLint to process <sys/types.h>.");
1719 llmsglit ("At last resort, +trytorecover can be used to make LCLint attempt "
1720 "to continue after a parse error. This is usually not successful "
1721 "and the author does not consider assertion failures when +trytorecover "
1722 "is used to be bugs.");
1726 printAnnotations (void)
1728 llmsglit ("Annotations");
1729 llmsglit ("-----------");
1731 llmsglit ("Annotations are semantic comments that document certain "
1732 "assumptions about functions, variables, parameters, and types. ");
1734 llmsglit ("They may be used to indicate where the representation of a "
1735 "user-defined type is hidden, to limit where a global variable may "
1736 "be used or modified, to constrain what a function implementation "
1737 "may do to its parameters, and to express checked assumptions about "
1738 "variables, types, structure fields, function parameters, and "
1739 "function results.");
1741 llmsglit ("Annotations are introduced by \"/*@\". The role of the @ may be "
1742 "played by any printable character, selected using -commentchar <char>.");
1744 llmsglit ("Consult the User's Guide for descriptions of checking associated with each annotation.");
1746 llmsglit ("Globals: (in function declarations)");
1747 llmsglit (" /*@globals <globitem>,+ @*/");
1748 llmsglit (" globitem is an identifier, internalState or fileSystem");
1750 llmsglit ("Modifies: (in function declarations)");
1751 llmsglit (" /*@modifies <moditem>,+ @*/");
1752 llmsglit (" moditem is an lvalue");
1753 llmsglit (" /*@modifies nothing @*/");
1754 llmsglit (" /*@*/ (Abbreviation for no globals and modifies nothing.)");
1756 llmsglit ("Iterators:");
1757 llmsglit (" /*@iter <identifier> (<parameter-type-list>) @*/ - declare an iterator");
1759 llmsglit ("Constants:");
1760 llmsglit (" /*@constant <declaration> @*/ - declares a constant");
1762 llmsglit ("Alternate Types:");
1763 llmsglit (" /*@alt <basic-type>,+ @*/");
1764 llmsglit (" (e.g., int /*@alt char@*/ is a type matching either int or char)");
1766 llmsglit ("Declarator Annotations");
1768 llmsglit ("Type Definitions:");
1769 llmsglit (" /*@abstract@*/ - representation is hidden from clients");
1770 llmsglit (" /*@concrete@*/ - representation is visible to clients");
1771 llmsglit (" /*@immutable@*/ - instances of the type cannot change value");
1772 llmsglit (" /*@mutable@*/ - instances of the type can change value");
1773 llmsglit (" /*@refcounted@*/ - reference counted type");
1775 llmsglit ("Global Variables:");
1776 llmsglit (" /*@unchecked@*/ - weakest checking for global use");
1777 llmsglit (" /*@checkmod@*/ - check modification by not use of global");
1778 llmsglit (" /*@checked@*/ - check use and modification of global");
1779 llmsglit (" /*@checkedstrict@*/ - check use of global strictly");
1781 llmsglit ("Memory Management:");
1782 llmsglit (" /*@dependent@*/ - a reference to externally-owned storage");
1783 llmsglit (" /*@keep@*/ - a parameter that is kept by the called function");
1784 llmsglit (" /*@killref@*/ - a refcounted parameter, killed by the call");
1785 llmsglit (" /*@only@*/ - an unshared reference");
1786 llmsglit (" /*@owned@*/ - owner of storage that may be shared by /*@dependent@*/ references");
1787 llmsglit (" /*@shared@*/ - shared reference that is never deallocated");
1788 llmsglit (" /*@temp@*/ - temporary parameter");
1790 llmsglit ("Aliasing:");
1791 llmsglit (" /*@unique@*/ - may not be aliased by any other visible reference");
1792 llmsglit (" /*@returned@*/ - may be aliased by the return value");
1794 llmsglit ("Exposure:");
1795 llmsglit (" /*@observer@*/ - reference that cannot be modified");
1796 llmsglit (" /*@exposed@*/ - exposed reference to storage in another object");
1798 llmsglit ("Definition State:");
1799 llmsglit (" /*@out@*/ - storage reachable from reference need not be defined");
1800 llmsglit (" /*@in@*/ - all storage reachable from reference must be defined");
1801 llmsglit (" /*@partial@*/ - partially defined, may have undefined fields");
1802 llmsglit (" /*@reldef@*/ - relax definition checking");
1804 llmsglit ("Global State: (for globals lists, no /*@, since list is already in /*@\'s)");
1805 llmsglit (" undef - variable is undefined before the call");
1806 llmsglit (" killed - variable is undefined after the call");
1808 llmsglit ("Null State:");
1809 llmsglit (" /*@null@*/ - possibly null pointer");
1810 llmsglit (" /*@notnull@*/ - non-null pointer");
1811 llmsglit (" /*@relnull@*/ - relax null checking");
1813 llmsglit ("Null Predicates:");
1814 llmsglit (" /*@truenull@*/ - if result is TRUE, first parameter is NULL");
1815 llmsglit (" /*@falsenull@*/ - if result is TRUE, first parameter is not NULL");
1817 llmsglit ("Execution:");
1818 llmsglit (" /*@exits@*/ - function never returns");
1819 llmsglit (" /*@mayexit@*/ - function may or may not return");
1820 llmsglit (" /*@trueexit@*/ - function does not return if first parameter is TRUE");
1821 llmsglit (" /*@falseexit@*/ - function does not return if first parameter if FALSE");
1822 llmsglit (" /*@neverexit@*/ - function always returns");
1824 llmsglit ("Side-Effects:");
1825 llmsglit (" /*@sef@*/ - corresponding actual parameter has no side effects");
1827 llmsglit ("Declaration:");
1828 llmsglit (" /*@unused@*/ - need not be used (no unused errors reported)");
1829 llmsglit (" /*@external@*/ - defined externally (no undefined error reported)");
1832 llmsglit (" /*@fallthrough@*/ - fall-through case");
1834 llmsglit ("Break:");
1835 llmsglit (" /*@innerbreak@*/ - break is breaking an inner loop or switch");
1836 llmsglit (" /*@loopbreak@*/ - break is breaking a loop");
1837 llmsglit (" /*@switchbreak@*/ - break is breaking a switch");
1838 llmsglit (" /*@innercontinue@*/ - continue is continuing an inner loop");
1840 llmsglit ("Unreachable Code:");
1841 llmsglit (" /*@notreached@*/ - statement may be unreachable.");
1843 llmsglit ("Special Functions:");
1844 llmsglit (" /*@printflike@*/ - check variable arguments like printf");
1845 llmsglit (" /*@scanflike@*/ - check variable arguments like scanf");
1849 printComments (void)
1851 llmsglit ("Control Comments");
1852 llmsglit ("----------------");
1854 llmsglit ("Setting Flags");
1856 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.");
1858 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,");
1859 llmsglit (" /*@+boolint -modifies =showfunc@*/");
1860 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).");
1862 llmsglit ("Error Suppression");
1864 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.");
1866 llmsglit ("/*@ignore@*/ ... /*@end@*/");
1868 (cstring_makeLiteral
1869 ("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."));
1870 llmsglit ("/*@i@*/");
1872 (cstring_makeLiteral
1873 ("No errors will be reported from an /*@i@*/ comment to the end of the line."));
1874 llmsglit ("/*@i<n>@*/");
1876 (cstring_makeLiteral
1877 ("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."));
1878 llmsglit ("/*@t@*/, /*@t<n>@*/");
1880 (cstring_makeLiteral
1881 ("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."));
1883 llmsglit ("Type Access");
1885 llmsglit ("/*@access <type>@*/");
1886 llmsglit (" Allows the following code to access the representation of <type>");
1887 llmsglit ("/*@noaccess <type>@*/");
1888 llmsglit (" Hides the representation of <type>");
1890 llmsglit ("Macro Expansion");
1892 llmsglit ("/*@notfunction@*/");
1894 (cstring_makeLiteral
1895 ("Indicates that the next macro definition is not intended to be a "
1896 "function, and should be expanded in line instead of checked as a "
1897 "macro function definition."));
1904 llmsglit ("Flag Categories");
1905 llmsglit ("---------------");
1906 listAllCategories ();
1907 llmsglit ("\nTo see the flags in a flag category, do\n lclint -help flags <category>");
1908 llmsglit ("To see a list of all flags in alphabetical order, do\n lclint -help flags alpha");
1909 llmsglit ("To see a full description of all flags, do\n lclint -help flags full");
1913 printMaintainer (void)
1915 llmsg (message ("Maintainer: %s", cstring_makeLiteralTemp (LCLINT_MAINTAINER)));
1916 llmsglit (LCL_COMPILE);
1922 llmsglit ("Mailing Lists");
1923 llmsglit ("-------------");
1925 llmsglit ("There are two mailing lists associated with LCLint: ");
1927 llmsglit (" lclint-announce@virginia.edu");
1929 llmsglit (" Reserved for announcements of new releases and bug fixes.");
1930 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
1931 llmsglit (" subscribe lclint-announce");
1933 llmsglit (" lclint-interest@virginia.edu");
1935 llmsglit (" Informal discussions on the use and development of lclint.");
1936 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
1937 llmsglit (" subscribe lclint-interest");
1941 printReferences (void)
1943 llmsglit ("References");
1944 llmsglit ("----------");
1946 llmsglit ("The LCLint web site is http://lclint.cs.virginia.edu");
1948 llmsglit ("Technical papers relating to LCLint include:");
1950 llmsglit (" David Evans. \"Static Detection of Dynamic Memory Errors\".");
1951 llmsglit (" SIGPLAN Conference on Programming Language Design and ");
1952 llmsglit (" Implementation (PLDI '96), Philadelphia, PA, May 1996.");
1954 llmsglit (" David Evans, John Guttag, Jim Horning and Yang Meng Tan. ");
1955 llmsglit (" \"LCLint: A Tool for Using Specifications to Check Code\".");
1956 llmsglit (" SIGSOFT Symposium on the Foundations of Software Engineering,");
1957 llmsglit (" December 1994.");
1959 llmsglit ("A general book on Larch is:");
1961 llmsglit (" Guttag, John V., Horning, James J., (with Garland, S. J., Jones, ");
1962 llmsglit (" K. D., Modet, A., and Wing, J. M.), \"Larch: Languages and Tools ");
1963 llmsglit (" for Formal Specification\", Springer-Verlag, 1993.");
1967 describePrefixCodes (void)
1969 llmsglit ("Prefix Codes");
1970 llmsglit ("------------");
1972 llmsglit ("These characters have special meaning in name prefixes:");
1974 llmsg (message (" %h Any uppercase letter [A-Z]", PFX_UPPERCASE));
1975 llmsg (message (" %h Any lowercase letter [a-z]", PFX_LOWERCASE));
1976 llmsg (message (" %h Any character (valid in a C identifier)", PFX_ANY));
1977 llmsg (message (" %h Any digit [0-9]", PFX_DIGIT));
1978 llmsg (message (" %h Any non-uppercase letter [a-z0-9_]", PFX_NOTUPPER));
1979 llmsg (message (" %h Any non-lowercase letter [A-Z0-9_]", PFX_NOTLOWER));
1980 llmsg (message (" %h Any letter [A-Za-z]", PFX_ANYLETTER));
1981 llmsg (message (" %h Any letter or digit [A-Za-z0-9]", PFX_ANYLETTERDIGIT));
1982 llmsglit (" * Zero or more repetitions of the previous character class until the end of the name");
1991 eval = context_getLarchPath ();
1992 def = osd_getEnvironmentVariable (LARCH_PATH);
1994 if (cstring_isDefined (def) ||
1995 !cstring_equal (eval, cstring_fromChars (DEFAULT_LARCHPATH)))
1997 llmsg (message ("LARCH_PATH = %s", eval));
2001 llmsg (message ("LARCH_PATH = <not set> (default = %s)",
2002 cstring_fromChars (DEFAULT_LARCHPATH)));
2005 llmsglit (" --- path used to find larch initialization files and LSL traits");
2007 eval = context_getLCLImportDir ();
2008 def = osd_getEnvironmentVariable (cstring_makeLiteralTemp (LCLIMPORTDIR));
2010 if (cstring_isDefined (def) ||
2011 !cstring_equal (eval, cstring_fromChars (DEFAULT_LCLIMPORTDIR)))
2013 llmsg (message ("%q = %s", cstring_makeLiteral (LCLIMPORTDIR), eval));
2017 llmsg (message ("%s = <not set, default: %s>", cstring_makeLiteralTemp (LCLIMPORTDIR),
2018 cstring_makeLiteralTemp (DEFAULT_LCLIMPORTDIR)));
2021 llmsglit (" --- directory containing lcl standard library files "
2022 "(import with < ... >)");;
2025 ("include path = %q (set by environment variable %s and -I flags)",
2026 cppReader_getIncludePath (), INCLUDEPATH_VAR));
2028 llmsglit (" --- path used to find #include'd files");
2031 ("systemdirs = %s (set by -systemdirs or envirnoment variable %s)", /*@i413223@*/
2032 context_getString (FLG_SYSTEMDIRS),
2035 llmsglit (" --- if file is found on this path, it is treated as a system file for error reporting");
2044 fprintf (stderr, "*** Interrupt\n");
2045 llexit (LLINTERRUPT);
2050 /* Cheat when there are parse errors */
2053 fprintf (stderr, "*** Segmentation Violation\n");
2055 /* Don't catch it if fileloc_unparse causes a signal */
2056 (void) signal (SIGSEGV, NULL);
2058 loc = fileloc_unparse (g_currentloc);
2060 fprintf (stderr, "*** Location (not trusted): %s\n",
2061 cstring_toCharsSafe (loc));
2064 fprintf (stderr, "*** Please report bug to %s\n", LCLINT_MAINTAINER);
2068 fprintf (stderr, "*** Signal: %d\n", i);
2070 fprintf (stderr, "*** Location (not trusted): %s\n",
2071 cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
2074 fprintf (stderr, "*** Please report bug to %s ***\n", LCLINT_MAINTAINER);
2082 static bool doneCleanup = FALSE;
2084 /* make sure this is only called once! */
2086 if (doneCleanup) return;
2090 if (context_getFlag (FLG_KEEP))
2092 check (fputs ("Temporary files kept:\n", stderr) != EOF);
2093 fileTable_printTemps (context_fileTable ());
2098 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
2102 llbug (message ("Files unclosed: %d", nfiles));
2105 fileTable_cleanup (context_fileTable ());
2112 ** cleans up temp files (if necessary)
2119 DPRINTF (("llexit: %d", status));
2122 if (status == LLFAILURE)
2130 if (status != LLFAILURE)
2132 context_destroyMod ();
2133 exprNode_destroyMod ();
2136 uentry_destroyMod ();
2137 typeIdSet_destroyMod ();
2140 dmalloc_shutdown ();
2144 exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
2148 loadrc (/*@open@*/ FILE *rcfile, cstringSList *passThroughArgs)
2149 /*@ensures closed rcfile@*/
2151 char *s = mstring_create (MAX_LINE_LENGTH);
2154 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2158 while (reader_readLine (rcfile, s, MAX_LINE_LENGTH) != NULL)
2165 DPRINTF (("Line: %s", s));
2166 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2168 while (*s == ' ' || *s == '\t')
2176 bool escaped = FALSE;
2177 bool quoted = FALSE;
2180 DPRINTF (("Process: %s", s));
2181 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2182 /* comment characters */
2183 if (c == '#' || c == ';' || c == '\n')
2189 if (c == '-' || c == '+')
2196 voptgenerror (FLG_BADFLAG,
2197 message ("Bad flag syntax (+ or - expected, "
2198 "+ is assumed): %s",
2199 cstring_fromChars (s)),
2210 while ((c = *s) != '\0')
2211 { /* remember to handle spaces and quotes in -D and -U ... */
2237 if (c == ' ' || c == '\t' || c == '\n')
2239 /*@innerbreak@*/ break;
2247 DPRINTF (("Nulling: %c", *s));
2250 if (mstring_isEmpty (thisflag))
2252 llfatalerror (message ("Missing flag: %s",
2253 cstring_fromChars (os)));
2256 DPRINTF (("Flag: %s", thisflag));
2258 opt = identifyFlag (cstring_fromChars (thisflag));
2260 if (flagcode_isSkip (opt))
2264 else if (flagcode_isInvalid (opt))
2266 DPRINTF (("Invalid: %s", thisflag));
2268 if (isMode (cstring_fromChars (thisflag)))
2270 context_setMode (cstring_fromChars (thisflag));
2274 voptgenerror (FLG_BADFLAG,
2275 message ("Unrecognized option: %s",
2276 cstring_fromChars (thisflag)),
2282 context_userSetFlag (opt, set);
2284 if (flagcode_hasArgument (opt))
2286 if (opt == FLG_HELP)
2289 voptgenerror (FLG_BADFLAG,
2290 message ("Cannot use help in rc files"),
2293 else if (flagcode_isPassThrough (opt)) /* -D or -U */
2295 cstring arg = cstring_fromCharsNew (thisflag);
2296 cstring_markOwned (arg);
2297 *passThroughArgs = cstringSList_add (*passThroughArgs, arg);
2298 DPRINTF (("Pass through: %s",
2299 cstringSList_unparse (*passThroughArgs)));
2301 else if (opt == FLG_INCLUDEPATH
2302 || opt == FLG_SPECPATH)
2304 cstring dir = cstring_suffix (cstring_fromChars (thisflag), 1); /* skip over I/S */
2308 case FLG_INCLUDEPATH:
2309 cppAddIncludeDir (dir);
2310 /*@switchbreak@*/ break;
2313 g_localSpecPath = cstring_toCharsSafe
2314 (message ("%s:%s", cstring_fromChars (g_localSpecPath), dir));
2316 /*@switchbreak@*/ break;
2320 else if (flagcode_hasString (opt)
2321 || flagcode_hasValue (opt)
2322 || opt == FLG_INIT || opt == FLG_OPTF)
2324 cstring extra = cstring_undefined;
2329 rest = mstring_copy (s);
2330 DPRINTF (("Here: rest = %s", rest));
2334 while ((rchar = *rest) != '\0'
2335 && (isspace ((int) rchar)))
2341 DPRINTF (("Yo: %s", rest));
2343 while ((rchar = *rest) != '\0'
2344 && !isspace ((int) rchar))
2346 extra = cstring_appendChar (extra, rchar);
2351 DPRINTF (("Yo: %s", extra));
2354 if (cstring_isUndefined (extra))
2360 ("Flag %s must be followed by an argument",
2361 flagcode_unparse (opt)),
2368 DPRINTF (("Here we are: %s", extra));
2370 if (flagcode_hasValue (opt))
2372 DPRINTF (("Set value flag: %s", extra));
2373 setValueFlag (opt, extra);
2374 cstring_free (extra);
2376 else if (opt == FLG_OPTF)
2378 FILE *innerf = fopen (cstring_toCharsSafe (extra), "r");
2379 cstring_markOwned (extra);
2383 fileloc fc = g_currentloc;
2384 g_currentloc = fileloc_createRc (extra);
2385 loadrc (innerf, passThroughArgs);
2386 fileloc_reallyFree (g_currentloc);
2394 message ("Options file not found: %s",
2399 else if (opt == FLG_INIT)
2402 llassert (inputStream_isUndefined (initFile));
2404 initFile = inputStream_create
2406 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
2409 cstring_free (extra);
2412 else if (flagcode_hasString (opt))
2414 if (cstring_firstChar (extra) == '"')
2416 if (cstring_lastChar (extra) == '"')
2418 char *extras = cstring_toCharsSafe (extra);
2420 llassert (extras[strlen(extras) - 1] == '"');
2421 extras[strlen(extras) - 1] = '\0';
2422 extra = cstring_fromChars (extras + 1);
2423 DPRINTF (("Remove quites: %s", extra));
2429 message ("Unmatched \" in option string: %s",
2435 setStringFlag (opt, extra);
2439 cstring_free (extra);
2452 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2453 while ((c == ' ') || (c == '\t'))
2459 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2463 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2465 check (fclose (rcfile) == 0);
2468 static fileIdList preprocessFiles (fileIdList fl, bool xhfiles)
2469 /*@modifies fileSystem@*/
2471 bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
2472 int skip = (fileIdList_size (fl) / 5);
2473 int filesprocessed = 0;
2474 fileIdList dfiles = fileIdList_create ();
2476 fileloc_free (g_currentloc);
2477 g_currentloc = fileloc_createBuiltin ();
2479 fileIdList_elements (fl, fid)
2481 cstring ppfname = fileName (fid);
2487 if (osd_findOnLarchPath (ppfname, &fpath) == OSD_FILEFOUND)
2489 if (cstring_equal (ppfname, fpath))
2495 DPRINTF (("xh file: %s", fpath));
2497 fileTable_setFilePath (context_fileTable (), fid, fpath);
2502 lldiagmsg (message ("Cannot find .xh file on LARCH_PATH: %s", ppfname));
2503 lldiagmsg (cstring_makeLiteral (" Check LARCH_PATH environment variable."));
2504 ppfname = cstring_undefined;
2509 if (!(osd_fileIsReadable (ppfname)))
2511 lldiagmsg (message ("Cannot open file: %s", ppfname));
2512 ppfname = cstring_undefined;
2516 if (cstring_isDefined (ppfname))
2518 fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
2520 llassert (cstring_isNonEmpty (ppfname));
2524 if ((filesprocessed % skip) == 0)
2526 if (filesprocessed == 0) {
2527 fprintf (stderr, " ");
2530 fprintf (stderr, ".");
2533 (void) fflush (stderr);
2538 if (cppProcess (ppfname, fileName (dfile)) != 0)
2540 llfatalerror (message ("Preprocessing error for file: %s",
2541 rootFileName (fid)));
2544 fileIdList_add (dfiles, dfile);
2546 } end_fileIdList_elements;
2551 /* This should be in an lclUtils.c file... */
2553 char *specFullName (char *specfile, /*@out@*/ char **inpath)
2555 /* extract the path and the specname associated with the given file */
2556 char *specname = (char *) dmalloc (sizeof (*specname)
2557 * (strlen (specfile) + 9));
2558 char *ospecname = specname;
2559 char *path = (char *) dmalloc (sizeof (*path) * (strlen (specfile)));
2563 /* initialized path to empty string or may have accidental garbage */
2566 /*@-mayaliasunique@*/
2567 strcpy (specname, specfile);
2568 /*@=mayaliasunique@*/
2570 /* trim off pathnames in specfile */
2571 size = strlen (specname);
2573 for (i = size_toInt (size) - 1; i >= 0; i--)
2575 if (specname[i] == CONNECTCHAR)
2577 /* strcpy (specname, (char *)specname+i+1); */
2578 for (j = 0; j <= i; j++) /* include '/' */
2580 path[j] = specname[j];
2590 ** also remove .lcl file extension, assume it's the last extension
2594 size = strlen (specname);
2596 for (i = size_toInt (size) - 1; i >= 0; i--)
2598 if (specname[i] == '.')
2608 ** If specname no longer points to the original char,
2609 ** we need to allocate a new pointer and copy the string.
2612 if (specname != ospecname) {
2613 char *rspecname = (char *) dmalloc (sizeof (*rspecname) * (strlen (specname) + 1));
2614 strcpy (rspecname, specname); /* evs 2000-05-16: Bug: was ospecname! */