2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2002 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://www.splint.org
27 ** Main module for Splint annotation-assisted program 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"
73 # include "fileIdList.h"
75 # include "cgrammar.h"
80 extern /*@external@*/ int yydebug;
82 static void printMail (void);
83 static void printMaintainer (void);
84 static void printReferences (void);
85 static void printFlags (void);
86 static void printAnnotations (void);
87 static void printParseErrors (void);
88 static void printComments (void);
89 static void describePrefixCodes (void);
90 static void cleanupFiles (void);
91 static void showHelp (void);
92 static void interrupt (int p_i);
94 static bool readOptionsFile (cstring p_fname,
95 cstringSList *p_passThroughArgs,
97 /*@modifies fileSystem, internalState, *p_passThroughArgs@*/ ;
99 static void loadrc (FILE *p_rcfile, cstringSList *p_passThroughArgs)
100 /*@modifies *p_passThroughArgs, p_rcfile@*/
101 /*@ensures closed p_rcfile@*/ ;
103 static void describeVars (void);
104 static bool specialFlagsHelp (char *p_next);
105 static bool hasShownHerald = FALSE;
106 static char *specFullName (char *p_specfile, /*@out@*/ char **p_inpath)
107 /*@modifies *p_inpath@*/ ;
109 static bool anylcl = FALSE;
110 static clock_t inittime;
112 static /*@only@*/ /*@null@*/ inputStream initFile = inputStream_undefined;
114 static fileIdList preprocessFiles (fileIdList, bool)
115 /*@modifies fileSystem@*/ ;
120 void lslCleanup (void)
121 /*@globals killed g_symtab@*/
122 /*@modifies internalState, g_symtab@*/
125 ** Cleanup all the LCL/LSL.
128 static bool didCleanup = FALSE;
130 llassert (!didCleanup);
135 lsymbol_destroyMod ();
136 LCLSynTableCleanup ();
137 LCLTokenTableCleanup ();
138 LCLScanLineCleanup ();
141 /* clean up LSL parsing */
144 ltokenTableCleanup ();
148 symtable_free (g_symtab);
154 /*@globals undef g_symtab; @*/
155 /*@modifies g_symtab, internalState, fileSystem; @*/
158 ** Open init file provided by user, or use the default LCL init file
161 cstring larchpath = context_getLarchPath ();
162 inputStream LSLinitFile = inputStream_undefined;
166 if (inputStream_isUndefined (initFile))
168 initFile = inputStream_create (cstring_makeLiteral (INITFILENAME),
169 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
172 if (!inputStream_getPath (larchpath, initFile))
174 lldiagmsg (message ("Continuing without LCL init file: %s",
175 inputStream_fileName (initFile)));
179 if (!inputStream_open (initFile))
181 lldiagmsg (message ("Continuing without LCL init file: %s",
182 inputStream_fileName (initFile)));
188 if (!inputStream_open (initFile))
190 lldiagmsg (message ("Continuing without LCL init file: %s",
191 inputStream_fileName (initFile)));
195 /* Initialize checker */
203 LCLTokenTableInit ();
215 /* need this to initialize LCL checker */
217 llassert (inputStream_isDefined (initFile));
218 if (inputStream_isOpen (initFile))
222 LCLScanReset (initFile);
223 LCLProcessInitFileInit ();
224 LCLProcessInitFileReset ();
227 LCLProcessInitFile ();
228 LCLProcessInitFileCleanup ();
231 check (inputStream_close (initFile));
234 /* Initialize LSL init files, for parsing LSL signatures from LSL */
236 LSLinitFile = inputStream_create (cstring_makeLiteral ("lslinit.lsi"),
237 cstring_makeLiteralTemp (".lsi"),
240 if (!inputStream_getPath (larchpath, LSLinitFile))
242 lldiagmsg (message ("Continuing without LSL init file: %s",
243 inputStream_fileName (LSLinitFile)));
247 if (!inputStream_open (LSLinitFile))
249 lldiagmsg (message ("Continuing without LSL init file: %s",
250 inputStream_fileName (LSLinitFile)));
266 if (inputStream_isOpen (LSLinitFile))
269 LSLScanReset (LSLinitFile);
270 LSLProcessInitFileInit ();
272 LSLProcessInitFile ();
274 check (inputStream_close (LSLinitFile));
277 inputStream_free (LSLinitFile);
282 (cstring_makeLiteral ("LSL init file error. Attempting to continue."));
286 g_symtab = symtable_new ();
289 ** sort_init must come after symtab has been initialized
298 ** Equivalent to importing old spec_csupport.lcl
299 ** define immutable LCL type "bool" and bool constants TRUE and FALSE
300 ** and initialized them to be equal to LSL's "true" and "false".
302 ** Reads in CTrait.syms (derived from CTrait.lsl) on LARCH_PATH.
306 LCLReportEolTokens (FALSE);
310 lslProcess (fileIdList lclfiles)
311 /*@globals undef g_currentSpec, undef g_currentSpecName, g_currentloc,
312 undef killed g_symtab; @*/
313 /*@modifies g_currentSpec, g_currentSpecName, g_currentloc, internalState, fileSystem; @*/
316 bool parser_status = FALSE;
317 bool overallStatus = FALSE;
321 context_resetSpecLines ();
323 fileIdList_elements (lclfiles, fid)
325 cstring actualName = cstring_undefined;
326 cstring fname = fileName (fid);
328 if (osd_getPath (cstring_fromChars (g_localSpecPath),
329 fname, &actualName) == OSD_FILENOTFOUND)
331 if (mstring_equal (g_localSpecPath, "."))
333 lldiagmsg (message ("Spec file not found: %q", osd_outputPath (fname)));
337 lldiagmsg (message ("Spec file not found: %q (on %s)",
338 osd_outputPath (fname),
339 cstring_fromChars (g_localSpecPath)));
344 inputStream specFile;
346 char *namePtr = actualName;
348 while (*namePtr == '.' && *(namePtr + 1) == CONNECTCHAR)
352 /*@noaccess cstring@*/
354 g_currentSpec = cstring_fromCharsNew (namePtr);
356 specFile = inputStream_create (cstring_copy (g_currentSpec),
357 LCL_EXTENSION, TRUE);
359 llassert (inputStream_isDefined (specFile));
361 g_currentSpecName = specFullName
362 (cstring_toCharsSafe (g_currentSpec),
367 if (context_getFlag (FLG_SHOWSCAN))
369 lldiagmsg (message ("< reading spec %s >", g_currentSpec));
372 /* Open source file */
374 if (!inputStream_open (specFile))
376 lldiagmsg (message ("Cannot open file: %q",
377 osd_outputPath (inputStream_fileName (specFile))));
378 inputStream_free (specFile);
382 scopeInfo dummy_scope = (scopeInfo) dmalloc (sizeof (*dummy_scope));
383 dummy_scope->kind = SPE_INVALID;
386 LCLScanReset (specFile);
389 ** Minor hacks to allow more than one LCL file to
390 ** be scanned, while keeping initializations
393 symtable_enterScope (g_symtab, dummy_scope);
394 resetImports (cstring_fromChars (g_currentSpecName));
395 context_enterLCLfile ();
396 (void) lclHadNewError ();
398 parser_status = (ylparse () != 0);
399 context_exitLCLfile ();
401 overallStatus = parser_status || lclHadNewError ();
403 if (context_getFlag (FLG_DOLCS))
407 outputLCSFile (path, "%FAILED Output from ",
412 outputLCSFile (path, "%PASSED Output from ",
417 (void) inputStream_close (specFile);
418 inputStream_free (specFile);
420 symtable_exitScope (g_symtab);
423 cstring_free (actualName);
424 } end_fileIdList_elements;
426 /* Can cleanup lsl stuff right away */
430 g_currentSpec = cstring_undefined;
431 g_currentSpecName = NULL;
435 static void handlePassThroughFlag (char *arg)
438 char *quotechar = strchr (curarg, '\"');
441 char *freearg = NULL;
443 while (quotechar != NULL)
445 if (*(quotechar - 1) == '\\')
447 char *tp = quotechar - 2;
458 curarg = quotechar + 1;
459 quotechar = strchr (curarg, '\"');
464 llassert (quotechar != NULL);
466 offset = (quotechar - arg) + 2;
470 arg = cstring_toCharsSafe
471 (message ("%s\"\'%s",
472 cstring_fromChars (arg),
473 cstring_fromChars (quotechar + 1)));
479 arg = cstring_toCharsSafe
480 (message ("%s\'\"%s",
481 cstring_fromChars (arg),
482 cstring_fromChars (quotechar + 1)));
487 curarg = arg + offset;
488 quotechar = strchr (curarg, '\"');
494 voptgenerror (FLG_BADFLAG,
495 message ("Unclosed quote in flag: %s",
496 cstring_fromChars (arg)),
505 ** If the value is surrounded by single quotes ('), remove
506 ** them. This is an artifact of UNIX command line?
509 def = osd_fixDefine (cstring_fromChars (arg + 1));
510 DPRINTF (("Do define: %s", def));
512 DPRINTF (("After define"));
514 } else if (arg[0] == 'U') {
515 cppDoUndefine (cstring_fromChars (arg + 1));
524 void showHerald (void)
526 if (hasShownHerald || context_getFlag (FLG_QUIET)) return;
530 fprintf (g_msgstream, "%s\n\n", SPLINT_VERSION);
531 hasShownHerald = TRUE;
536 static cstring findLarchPathFile (/*@temp@*/ cstring s)
541 status = osd_getPath (context_getLarchPath (), s, &pathName);
543 if (status == OSD_FILEFOUND)
547 else if (status == OSD_FILENOTFOUND)
550 lldiagmsg (message ("Cannot find file on LARCHPATH: %s", s));
552 else if (status == OSD_PATHTOOLONG)
554 /* Directory and filename are too long. Report error. */
555 llbuglit ("soure_getPath: Filename plus directory from search path too long");
562 return cstring_undefined;
565 static void addLarchPathFile (fileIdList files, /*@temp@*/ cstring s)
567 cstring pathName = findLarchPathFile (s);
569 if (cstring_isDefined (pathName))
571 if (fileTable_exists (context_fileTable (), pathName))
574 lldiagmsg (message ("File listed multiple times: %s", pathName));
575 cstring_free (pathName);
579 fileIdList_add (files, fileTable_addFileOnly (context_fileTable (), pathName));
584 static void addFile (fileIdList files, /*@only@*/ cstring s)
586 if (fileTable_exists (context_fileTable (), s))
589 lldiagmsg (message ("File listed multiple times: %s", s));
594 fileIdList_add (files, fileTable_addFileOnly (context_fileTable (), s));
598 static void addXHFile (fileIdList files, /*@temp@*/ cstring s)
600 cstring pathName = findLarchPathFile (s);
602 if (cstring_isDefined (pathName))
604 if (fileTable_exists (context_fileTable (), pathName))
607 lldiagmsg (message ("File listed multiple times: %s", s));
611 fileIdList_add (files, fileTable_addXHFile (context_fileTable (), pathName));
615 cstring_free (pathName);
619 ** Disable MSVC++ warning about return value. Methinks humbly lclint control
620 ** comments are a mite more legible.
624 # pragma warning (disable:4035)
627 int main (int argc, char *argv[])
629 /*@globals killed undef g_currentloc,
633 /*@modifies g_currentloc, fileSystem,
637 /*@globals killed undef g_currentloc,
638 killed undef initFile,
639 killed g_localSpecPath,
640 killed undef g_currentSpec,
641 killed undef g_currentSpecName,
645 /*@modifies g_currentloc, initFile,
646 g_localSpecPath, g_currentSpec, g_currentSpecName, fileSystem,
651 bool first_time = TRUE;
652 bool showhelp = FALSE;
655 inputStream sourceFile = inputStream_undefined;
657 fileIdList dercfiles;
658 cstringSList fl = cstringSList_undefined;
659 cstringSList passThroughArgs = cstringSList_undefined;
660 fileIdList cfiles, xfiles, lclfiles, mtfiles;
661 clock_t before, lcltime, libtime, pptime, cptime, rstime;
665 _wildcard (&argc, &argv);
668 g_msgstream = stdout;
670 (void) signal (SIGINT, interrupt);
671 (void) signal (SIGSEGV, interrupt);
673 cfiles = fileIdList_create ();
674 xfiles = fileIdList_create ();
675 lclfiles = fileIdList_create ();
676 mtfiles = fileIdList_create ();
679 clabstract_initMod ();
680 typeIdSet_initMod ();
681 cppReader_initMod ();
686 g_currentloc = fileloc_createBuiltin ();
691 context_setInCommandLine ();
703 ** Add include directories from environment.
707 cstring incval = cstring_copy (osd_getEnvironmentVariable (INCLUDEPATH_VAR));
708 cstring oincval = incval;
710 if (cstring_isDefined (incval))
713 ** Each directory on the include path is a system include directory.
716 DPRINTF (("include: %s", incval));
717 context_setString (FLG_SYSTEMDIRS, cstring_copy (incval));
719 while (cstring_isDefined (incval))
722 char *nextsep = strchr (incval, PATH_SEPARATOR);
728 dir = cstring_copy (incval);
730 if (cstring_length (dir) == 0
731 || !isalpha ((int) cstring_firstChar (dir)))
734 ** win32 environment values can have special values,
740 cppAddIncludeDir (dir);
743 *nextsep = PATH_SEPARATOR;
744 incval = cstring_fromChars (nextsep + 1);
752 /*@noaccess cstring@*/
755 else /* 2001-09-09: herbert */
757 /* Put C_INCLUDE_PATH directories in sysdirs */
758 cstring cincval = osd_getEnvironmentVariable (cstring_makeLiteralTemp ("C_INCLUDE_PATH"));
759 if (cstring_isDefined (cincval))
761 context_setString (FLG_SYSTEMDIRS, cstring_copy (cincval));
766 cstring_free (oincval);
770 ** check RCFILE for default flags
774 cstring home = osd_getHomeDir ();
775 cstring fname = cstring_undefined;
776 bool defaultf = TRUE;
779 for (i = 1; i < argc; i++)
784 if (*thisarg == '-' || *thisarg == '+')
786 bool set = (*thisarg == '+');
790 opt = identifyFlag (cstring_fromChars (thisarg));
796 else if (opt == FLG_SHOWSCAN || opt == FLG_WARNRC)
799 ** Need to set it immediately, so rc file scan is displayed
802 context_userSetFlag (opt, set);
804 else if (opt == FLG_OPTF)
809 fname = cstring_fromChars (argv[i]);
810 (void) readOptionsFile (fname, &passThroughArgs, TRUE);
814 (cstring_makeLiteral ("Flag f to select options file "
815 "requires an argument"));
819 ; /* wait to process later */
826 if (!nof && defaultf)
829 ** No explicit rc file, first try reading ~/.splintrc
832 if (cstring_isUndefined (fname))
834 if (!cstring_isEmpty (home))
836 bool readhomerc, readaltrc;
837 cstring homename, altname;
839 homename = message ("%s%h%s", home, CONNECTCHAR,
840 cstring_fromChars (RCFILE));
841 readhomerc = readOptionsFile (homename, &passThroughArgs, FALSE);
844 ** Try ~/.lclintrc also for historical accuracy
847 altname = message ("%s%h%s", home, CONNECTCHAR,
848 cstring_fromChars (ALTRCFILE));
849 readaltrc = readOptionsFile (altname, &passThroughArgs, FALSE);
851 if (readhomerc && readaltrc)
856 message ("Found both %s and %s files. Using both files, "
857 "but recommend using only %s to avoid confusion.",
858 homename, altname, homename),
862 cstring_free (homename);
863 cstring_free (altname);
868 ** Next, read .splintrc in the current working directory
872 cstring rcname = message ("%s%s",osd_getCurrentDirectory (), cstring_fromChars (RCFILE));
873 cstring altname = message ("%s%s",osd_getCurrentDirectory (), cstring_fromChars (ALTRCFILE));
874 bool readrc, readaltrc;
876 readrc = readOptionsFile (rcname, &passThroughArgs, FALSE);
877 readaltrc = readOptionsFile (altname, &passThroughArgs, FALSE);
879 if (readrc && readaltrc)
881 voptgenerror (FLG_WARNRC,
882 message ("Found both %s and %s files. Using both files, "
883 "but recommend using only %s to avoid confusion.",
884 rcname, altname, rcname),
889 cstring_free (rcname);
890 cstring_free (altname);
897 for (i = 1; i < argc; i++)
913 if (*thisarg == '-' || *thisarg == '+')
915 thisarg++; /* skip '-' */
917 if (mstring_equal (thisarg, "modes"))
919 llmsg (describeModes ());
921 else if (mstring_equal (thisarg, "vars")
922 || mstring_equal (thisarg, "env"))
926 else if (mstring_equal (thisarg, "annotations"))
930 else if (mstring_equal (thisarg, "parseerrors"))
934 else if (mstring_equal (thisarg, "comments"))
938 else if (mstring_equal (thisarg, "prefixcodes"))
940 describePrefixCodes ();
942 else if (mstring_equal (thisarg, "references")
943 || mstring_equal (thisarg, "refs"))
947 else if (mstring_equal (thisarg, "mail"))
951 else if (mstring_equal (thisarg, "maintainer")
952 || mstring_equal (thisarg, "version"))
956 else if (mstring_equal (thisarg, "flags"))
960 char *next = argv[i + 1];
962 if (specialFlagsHelp (next))
968 flagkind k = identifyCategory (cstring_fromChars (next));
984 cstring s = describeFlag (cstring_fromChars (thisarg));
986 if (cstring_isDefined (s))
994 if (*thisarg == '-' || *thisarg == '+')
996 bool set = (*thisarg == '+');
999 thisarg++; /* skip '-' */
1000 flagname = cstring_fromChars (thisarg);
1002 DPRINTF (("Flag: %s", flagname));
1003 opt = identifyFlag (flagname);
1004 DPRINTF (("Flag: %s", flagcode_unparse (opt)));
1006 if (flagcode_isSkip (opt) || opt == FLG_SHOWSCAN || opt == FLG_WARNRC)
1008 /* showscan already processed */
1009 DPRINTF (("Skipping!"));
1011 else if (flagcode_isInvalid (opt))
1013 DPRINTF (("Invalid: %s", flagname));
1015 if (isMode (flagname))
1017 context_setMode (flagname);
1021 DPRINTF (("Error!"));
1022 voptgenerror (FLG_BADFLAG,
1023 message ("Unrecognized option: %s",
1024 cstring_fromChars (thisarg)),
1030 context_userSetFlag (opt, set);
1032 if (flagcode_hasArgument (opt))
1034 if (opt == FLG_HELP)
1038 else if (flagcode_isPassThrough (opt)) /* -D or -U */
1040 passThroughArgs = cstringSList_add
1041 (passThroughArgs, cstring_fromChars (thisarg));
1043 else if (flagcode_hasValue (opt))
1047 setValueFlag (opt, cstring_fromChars (argv[i]));
1053 ("Flag %s must be followed by a number",
1054 flagcode_unparse (opt)));
1057 else if (opt == FLG_INCLUDEPATH || opt == FLG_SPECPATH)
1059 cstring dir = cstring_suffix (cstring_fromChars (thisarg), 1); /* skip over I */
1063 case FLG_INCLUDEPATH:
1064 cppAddIncludeDir (dir);
1065 /*@switchbreak@*/ break;
1068 g_localSpecPath = cstring_toCharsSafe
1070 cstring_fromChars (g_localSpecPath),
1074 /*@switchbreak@*/ break;
1078 else if (flagcode_hasString (opt)
1079 || opt == FLG_INIT || opt == FLG_OPTF)
1083 cstring arg = cstring_fromChars (argv[i]);
1085 if (opt == FLG_OPTF)
1087 ; /* -f already processed */
1089 else if (opt == FLG_INIT)
1092 initFile = inputStream_create
1094 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
1101 DPRINTF (("String flag: %s / %s",
1102 flagcode_unparse (opt), arg));
1103 if (opt == FLG_MTSFILE)
1106 ** arg identifies mts files
1108 cstring tmp = message ("%s%s", arg, MTS_EXTENSION);
1109 addLarchPathFile (mtfiles, tmp);
1111 tmp = message ("%s%s", arg, XH_EXTENSION);
1112 addXHFile (xfiles, tmp);
1117 setStringFlag (opt, arg);
1125 ("Flag %s must be followed by a string",
1126 flagcode_unparse (opt)));
1136 else /* its a filename */
1138 DPRINTF (("Adding filename: %s", thisarg));
1139 fl = cstringSList_add (fl, cstring_fromChars (thisarg));
1148 ** create lists of C and LCL files
1151 cstringSList_elements (fl, current)
1153 cstring ext = fileLib_getExtension (current);
1155 if (cstring_isUndefined (ext))
1157 /* no extension --- both C and LCL with default extensions */
1159 addFile (cfiles, message ("%s%s", current, C_EXTENSION));
1160 addFile (lclfiles, message ("%s%s", current, LCL_EXTENSION));
1162 else if (cstring_equal (ext, XH_EXTENSION))
1164 addXHFile (xfiles, current);
1166 else if (cstring_equal (ext, PP_EXTENSION))
1168 if (!context_getFlag (FLG_NOPP))
1171 (FLG_FILEEXTENSIONS,
1172 message ("File extension %s used without +nopp flag (will be processed as C source code): %s",
1177 addFile (cfiles, cstring_copy (current));
1179 else if (cstring_equal (ext, LCL_EXTENSION))
1181 addFile (lclfiles, cstring_copy (current));
1183 else if (fileLib_isCExtension (ext))
1185 addFile (cfiles, cstring_copy (current));
1187 else if (cstring_equal (ext, MTS_EXTENSION))
1189 addLarchPathFile (mtfiles, current);
1194 (FLG_FILEEXTENSIONS,
1195 message ("Unrecognized file extension: %s (assuming %s is C source code)",
1199 addFile (cfiles, cstring_copy (current));
1201 } end_cstringSList_elements;
1209 fprintf (g_msgstream, "\n");
1211 fileIdList_free (cfiles);
1212 fileIdList_free (xfiles);
1213 fileIdList_free (lclfiles);
1222 inittime = clock ();
1224 context_resetErrors ();
1225 context_clearInCommandLine ();
1227 anylcl = !fileIdList_isEmpty (lclfiles);
1229 if (context_doMerge ())
1231 cstring m = context_getMerge ();
1233 if (context_getFlag (FLG_SHOWSCAN))
1235 fprintf (g_msgstream, "< loading %s ", cstring_toCharsSafe (m));
1240 if (context_getFlag (FLG_SHOWSCAN))
1242 fprintf (g_msgstream, " >\n");
1245 if (!usymtab_existsType (context_getBoolName ()))
1247 usymtab_initBool ();
1252 if (!context_getFlag (FLG_NOLIB) && loadStandardState ())
1261 /* setup bool type and constants */
1262 usymtab_initBool ();
1265 fileloc_free (g_currentloc);
1266 g_currentloc = fileloc_createBuiltin ();
1269 ** Read metastate files (must happen before loading libraries)
1272 fileIdList_elements (mtfiles, mtfile)
1274 context_setFileId (mtfile);
1276 if (context_getFlag (FLG_SHOWSCAN))
1278 lldiagmsg (message ("< processing %s >", rootFileName (mtfile)));
1281 mtreader_readFile (cstring_copy (fileName (mtfile)));
1282 } end_fileIdList_elements;
1289 llfatalerror (cstring_makeLiteral ("This version of Splint does not handle LCL files."));
1291 lslProcess (lclfiles);
1295 usymtab_initGlobalMarker ();
1300 ** call the pre-preprocessor and /lib/cpp to generate appropriate
1305 context_setInCommandLine ();
1307 DPRINTF (("Pass through: %s", cstringSList_unparse (passThroughArgs)));
1309 cstringSList_elements (passThroughArgs, thisarg) {
1310 handlePassThroughFlag (cstring_toCharsSafe (thisarg));
1311 } end_cstringSList_elements;
1313 cstringSList_free (passThroughArgs);
1317 DPRINTF (("Initializing cpp reader!"));
1318 cppReader_initialize ();
1319 cppReader_saveDefinitions ();
1321 context_clearInCommandLine ();
1323 if (!context_getFlag (FLG_NOPP))
1329 if (context_getFlag (FLG_SHOWSCAN))
1331 fprintf (stderr, "< preprocessing");
1336 context_setPreprocessing ();
1337 dercfiles = preprocessFiles (xfiles, TRUE);
1338 tfiles = preprocessFiles (cfiles, FALSE);
1339 dercfiles = fileIdList_append (dercfiles, tfiles);
1340 fileIdList_free (tfiles);
1342 context_clearPreprocessing ();
1344 fileIdList_free (cfiles);
1346 if (context_getFlag (FLG_SHOWSCAN))
1348 fprintf (stderr, " >\n");
1356 dercfiles = fileIdList_append (cfiles, xfiles);
1361 ** now, check all the corresponding C files
1363 ** (for now these are just <file>.c, but after pre-processing
1364 ** will be <tmpprefix>.<file>.c)
1369 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1373 llbug (message ("Files unclosed: %d", nfiles));
1378 DPRINTF (("Initializing..."));
1380 exprNode_initMod ();
1382 DPRINTF (("Okay..."));
1384 fileIdList_elements (dercfiles, fid)
1386 sourceFile = inputStream_create (cstring_copy (fileName (fid)), C_EXTENSION, TRUE);
1387 context_setFileId (fid);
1389 /* Open source file */
1391 if (inputStream_isUndefined (sourceFile) || (!inputStream_open (sourceFile)))
1393 /* previously, this was ignored ?! */
1394 llbug (message ("Could not open temp file: %s", fileName (fid)));
1398 yyin = inputStream_getFile (sourceFile); /*< shared <- only */
1400 llassert (yyin != NULL);
1402 if (context_getFlag (FLG_SHOWSCAN))
1404 lldiagmsg (message ("< checking %q >", osd_outputPath (rootFileName (fid))));
1408 ** Every time, except the first time, through the loop,
1409 ** need to call yyrestart to clean up the parse buffer.
1414 (void) yyrestart (yyin);
1421 DPRINTF (("Entering..."));
1422 context_enterFile ();
1424 context_exitCFile ();
1426 (void) inputStream_close (sourceFile);
1428 } end_fileIdList_elements;
1432 /* process any leftover macros */
1434 context_processAllMacros ();
1436 /* check everything that was specified was defined */
1438 /* don't check if no c files were processed ?
1439 ** is this correct behaviour?
1442 if (context_getFlag (FLG_SHOWSCAN))
1444 lldiagmsg (cstring_makeLiteral ("< global checks >"));
1449 if (context_getLinesProcessed () > 0)
1451 usymtab_allDefined ();
1454 if (context_maybeSet (FLG_TOPUNUSED))
1456 uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main"));
1458 if (uentry_isValid (ue))
1460 uentry_setUsed (ue, fileloc_observeBuiltin ());
1466 if (context_maybeSet (FLG_EXPORTLOCAL))
1468 usymtab_exportLocal ();
1472 if (context_maybeSet (FLG_EXPORTHEADER))
1474 usymtab_exportHeader ();
1477 if (context_getFlag (FLG_SHOWUSES))
1479 usymtab_displayAllUses ();
1482 context_checkSuppressCounts ();
1484 if (context_doDump ())
1486 cstring dump = context_getDump ();
1497 if (context_getFlag (FLG_SHOWSUMMARY))
1504 bool isQuiet = context_getFlag (FLG_QUIET);
1505 cstring specErrors = cstring_undefined;
1507 int nspecErrors = lclNumberErrors ();
1512 if (context_neednl ())
1513 fprintf (g_msgstream, "\n");
1516 if (nspecErrors > 0)
1518 if (nspecErrors == context_getLCLExpect ())
1521 message ("%d spec warning%&, as expected\n ",
1526 if (context_getLCLExpect () > 0)
1529 message ("%d spec warning%&, expected %d\n ",
1531 (int) context_getLCLExpect ());
1535 specErrors = message ("%d spec warning%& found\n ",
1543 if (context_getLCLExpect () > 0)
1545 specErrors = message ("No spec warnings, expected %d\n ",
1546 (int) context_getLCLExpect ());
1552 if (context_anyErrors ())
1554 if (context_numErrors () == context_getExpect ())
1557 llmsg (message ("Finished checking --- "
1558 "%s%d code warning%&, as expected",
1559 specErrors, context_numErrors ()));
1564 if (context_getExpect () > 0)
1568 ("Finished checking --- "
1569 "%s%d code warning%&, expected %d",
1570 specErrors, context_numErrors (),
1571 (int) context_getExpect ()));
1581 llmsg (message ("Finished checking --- "
1582 "%s%d code warning%& found",
1583 specErrors, context_numErrors ()));
1592 if (context_getExpect () > 0)
1596 ("Finished checking --- "
1597 "%sno code warnings, expected %d",
1599 (int) context_getExpect ()));
1606 if (context_getLinesProcessed () > 0)
1608 if (cstring_isEmpty (specErrors))
1612 llmsg (message ("Finished checking --- no warnings"));
1619 llmsg (message ("Finished checking --- %sno code warnings",
1627 llmsg (message ("Finished checking --- %sno code processed",
1634 cstring_free (specErrors);
1637 if (context_getFlag (FLG_STATS))
1639 clock_t ttime = clock () - before;
1640 int specLines = context_getSpecLinesProcessed ();
1646 fprintf (g_msgstream, "%d spec, ", specLines);
1649 # ifndef CLOCKS_PER_SEC
1650 fprintf (g_msgstream, "%d source lines in %ld time steps (steps/sec unknown)\n",
1651 context_getLinesProcessed (),
1654 fprintf (g_msgstream, "%d source lines in %.2f s.\n",
1655 context_getLinesProcessed (),
1656 (double) ttime / CLOCKS_PER_SEC);
1664 if (context_getFlag (FLG_TIMEDIST))
1666 clock_t ttime = clock () - before;
1670 char *msg = (char *) dmalloc (256 * sizeof (*msg));
1675 "Time distribution (percent): initialize %.2f / lcl %.2f / "
1676 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1677 (100.0 * (double) (libtime - before) / ttime),
1678 (100.0 * (double) (lcltime - libtime) / ttime),
1679 (100.0 * (double) (pptime - lcltime) / ttime),
1680 (100.0 * (double) (cptime - pptime) / ttime),
1681 (100.0 * (double) (rstime - cptime) / ttime));
1686 "Time distribution (percent): initialize %.2f / "
1687 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1688 (100.0 * (double) (libtime - before) / ttime),
1689 (100.0 * (double) (pptime - libtime) / ttime),
1690 (100.0 * (double) (cptime - pptime) / ttime),
1691 (100.0 * (double) (rstime - cptime) / ttime));
1694 llgenindentmsgnoloc (cstring_fromCharsO (msg));
1698 llexit (expsuccess ? LLSUCCESS : LLFAILURE);
1699 BADBRANCHRET (LLFAILURE);
1704 ** Reenable return value warnings.
1706 # pragma warning (default:4035)
1714 llmsg (message ("Source files are .c, .h and %s files. If there is no suffix,",
1716 llmsg (message (" Splint will look for <file>.c and <file>%s.", LCL_EXTENSION));
1718 llmsglit ("Use splint -help <topic or flag name> for more information");
1720 llmsglit ("Topics:");
1722 llmsglit (" annotations (describes source-code annotations)");
1723 llmsglit (" comments (describes control comments)");
1724 llmsglit (" flags (describes flag categories)");
1725 llmsglit (" flags <category> (describes flags in category)");
1726 llmsglit (" flags all (short description of all flags)");
1727 llmsglit (" flags alpha (list all flags alphabetically)");
1728 llmsglit (" flags full (full description of all flags)");
1729 llmsglit (" mail (information on mailing lists)");
1730 llmsglit (" modes (show mode settings)");
1731 llmsglit (" parseerrors (help on handling parser errors)");
1732 llmsglit (" prefixcodes (character codes in namespace prefixes)");
1733 llmsglit (" references (sources for more information)");
1734 llmsglit (" vars (environment variables)");
1735 llmsglit (" version (information on compilation, maintainer)");
1740 specialFlagsHelp (char *next)
1742 if ((next != NULL) && (*next != '-') && (*next != '+'))
1744 if (mstring_equal (next, "alpha"))
1749 else if (mstring_equal (next, "all"))
1751 printAllFlags (TRUE, FALSE);
1754 else if (mstring_equal (next, "categories")
1755 || mstring_equal (next, "cats"))
1757 listAllCategories ();
1760 else if (mstring_equal (next, "full"))
1762 printAllFlags (FALSE, TRUE);
1777 printParseErrors (void)
1779 llmsglit ("Parse Errors");
1780 llmsglit ("------------");
1782 llmsglit ("LCLint will sometimes encounter a parse error for code that "
1783 "can be parsed with a local compiler. There are a few likely "
1784 "causes for this and a number of techniques that can be used "
1785 "to work around the problem.");
1787 llmsglit ("Compiler extensions --- compilers sometimes extend the C "
1788 "language with compiler-specific keywords and syntax. While "
1789 "it is not advisible to use these, oftentimes one has no choice "
1790 "when the system header files use compiler extensions. ");
1792 llmsglit ("Splint supports some of the GNU (gcc) compiler extensions, "
1793 "if the +gnuextensions flag is set. You may be able to workaround "
1794 "other compiler extensions by using a pre-processor define. "
1795 "Alternately, you can surround the unparseable code with");
1797 llmsglit (" # ifndef S_SPLINT_S");
1799 llmsglit (" # endif");
1801 /* evans 2000-12-21 fixed typo reported by Jeroen Ruigrok/Asmodai */
1802 llmsglit ("Missing type definitions --- an undefined type name will usually "
1803 "lead to a parse error. This often occurs when a standard header "
1804 "file defines some type that is not part of the standard library. ");
1805 llmsglit ("By default, Splint does not process the local files corresponding "
1806 "to standard library headers, but uses a library specification "
1807 "instead so dependencies on local system headers can be detected. "
1808 "If another system header file that does not correspond to a "
1809 "standard library header uses one of these superfluous types, "
1810 "a parse error will result.");
1812 llmsglit ("If the parse error is inside a posix standard header file, the "
1813 "first thing to try is +posixlib. This makes Splint use "
1814 "the posix library specification instead of reading the posix "
1817 llmsglit ("Otherwise, you may need to either manually define the problematic "
1818 "type (e.g., add -Dmlink_t=int to your .lclintrc file) or force "
1819 "lclint to process the header file that defines it. This is done "
1820 "by setting -skipansiheaders or -skipposixheaders before "
1821 "the file that defines the type is #include'd.");
1822 llmsglit ("(See lclint -help "
1823 "skipansiheaders and lclint -help skipposixheaders for a list of "
1824 "standard headers.) For example, if <sys/local.h> uses a type "
1825 "defined by posix header <sys/types.h> but not defined by the "
1826 "posix library, we might do: ");
1828 llmsglit (" /*@-skipposixheaders@*/");
1829 llmsglit (" # include <sys/types.h>");
1830 llmsglit (" /*@=skipposixheaders@*/");
1831 llmsglit (" # include <sys/local.h>");
1833 llmsglit ("to force Splint to process <sys/types.h>.");
1835 llmsglit ("At last resort, +trytorecover can be used to make Splint attempt "
1836 "to continue after a parse error. This is usually not successful "
1837 "and the author does not consider assertion failures when +trytorecover "
1838 "is used to be bugs.");
1842 printAnnotations (void)
1844 llmsglit ("Annotations");
1845 llmsglit ("-----------");
1847 llmsglit ("Annotations are semantic comments that document certain "
1848 "assumptions about functions, variables, parameters, and types. ");
1850 llmsglit ("They may be used to indicate where the representation of a "
1851 "user-defined type is hidden, to limit where a global variable may "
1852 "be used or modified, to constrain what a function implementation "
1853 "may do to its parameters, and to express checked assumptions about "
1854 "variables, types, structure fields, function parameters, and "
1855 "function results.");
1857 llmsglit ("Annotations are introduced by \"/*@\". The role of the @ may be "
1858 "played by any printable character, selected using -commentchar <char>.");
1860 llmsglit ("Consult the User's Guide for descriptions of checking associated with each annotation.");
1862 llmsglit ("Globals: (in function declarations)");
1863 llmsglit (" /*@globals <globitem>,+ @*/");
1864 llmsglit (" globitem is an identifier, internalState or fileSystem");
1866 llmsglit ("Modifies: (in function declarations)");
1867 llmsglit (" /*@modifies <moditem>,+ @*/");
1868 llmsglit (" moditem is an lvalue");
1869 llmsglit (" /*@modifies nothing @*/");
1870 llmsglit (" /*@*/ (Abbreviation for no globals and modifies nothing.)");
1872 llmsglit ("Iterators:");
1873 llmsglit (" /*@iter <identifier> (<parameter-type-list>) @*/ - declare an iterator");
1875 llmsglit ("Constants:");
1876 llmsglit (" /*@constant <declaration> @*/ - declares a constant");
1878 llmsglit ("Alternate Types:");
1879 llmsglit (" /*@alt <basic-type>,+ @*/");
1880 llmsglit (" (e.g., int /*@alt char@*/ is a type matching either int or char)");
1882 llmsglit ("Declarator Annotations");
1884 llmsglit ("Type Definitions:");
1885 llmsglit (" /*@abstract@*/ - representation is hidden from clients");
1886 llmsglit (" /*@concrete@*/ - representation is visible to clients");
1887 llmsglit (" /*@immutable@*/ - instances of the type cannot change value");
1888 llmsglit (" /*@mutable@*/ - instances of the type can change value");
1889 llmsglit (" /*@refcounted@*/ - reference counted type");
1891 llmsglit ("Global Variables:");
1892 llmsglit (" /*@unchecked@*/ - weakest checking for global use");
1893 llmsglit (" /*@checkmod@*/ - check modification by not use of global");
1894 llmsglit (" /*@checked@*/ - check use and modification of global");
1895 llmsglit (" /*@checkedstrict@*/ - check use of global strictly");
1897 llmsglit ("Memory Management:");
1898 llmsglit (" /*@dependent@*/ - a reference to externally-owned storage");
1899 llmsglit (" /*@keep@*/ - a parameter that is kept by the called function");
1900 llmsglit (" /*@killref@*/ - a refcounted parameter, killed by the call");
1901 llmsglit (" /*@only@*/ - an unshared reference");
1902 llmsglit (" /*@owned@*/ - owner of storage that may be shared by /*@dependent@*/ references");
1903 llmsglit (" /*@shared@*/ - shared reference that is never deallocated");
1904 llmsglit (" /*@temp@*/ - temporary parameter");
1906 llmsglit ("Aliasing:");
1907 llmsglit (" /*@unique@*/ - may not be aliased by any other visible reference");
1908 llmsglit (" /*@returned@*/ - may be aliased by the return value");
1910 llmsglit ("Exposure:");
1911 llmsglit (" /*@observer@*/ - reference that cannot be modified");
1912 llmsglit (" /*@exposed@*/ - exposed reference to storage in another object");
1914 llmsglit ("Definition State:");
1915 llmsglit (" /*@out@*/ - storage reachable from reference need not be defined");
1916 llmsglit (" /*@in@*/ - all storage reachable from reference must be defined");
1917 llmsglit (" /*@partial@*/ - partially defined, may have undefined fields");
1918 llmsglit (" /*@reldef@*/ - relax definition checking");
1920 llmsglit ("Global State: (for globals lists, no /*@, since list is already in /*@\'s)");
1921 llmsglit (" undef - variable is undefined before the call");
1922 llmsglit (" killed - variable is undefined after the call");
1924 llmsglit ("Null State:");
1925 llmsglit (" /*@null@*/ - possibly null pointer");
1926 llmsglit (" /*@notnull@*/ - non-null pointer");
1927 llmsglit (" /*@relnull@*/ - relax null checking");
1929 llmsglit ("Null Predicates:");
1930 llmsglit (" /*@truenull@*/ - if result is TRUE, first parameter is NULL");
1931 llmsglit (" /*@falsenull@*/ - if result is TRUE, first parameter is not NULL");
1933 llmsglit ("Execution:");
1934 llmsglit (" /*@exits@*/ - function never returns");
1935 llmsglit (" /*@mayexit@*/ - function may or may not return");
1936 llmsglit (" /*@trueexit@*/ - function does not return if first parameter is TRUE");
1937 llmsglit (" /*@falseexit@*/ - function does not return if first parameter if FALSE");
1938 llmsglit (" /*@neverexit@*/ - function always returns");
1940 llmsglit ("Side-Effects:");
1941 llmsglit (" /*@sef@*/ - corresponding actual parameter has no side effects");
1943 llmsglit ("Declaration:");
1944 llmsglit (" /*@unused@*/ - need not be used (no unused errors reported)");
1945 llmsglit (" /*@external@*/ - defined externally (no undefined error reported)");
1948 llmsglit (" /*@fallthrough@*/ - fall-through case");
1950 llmsglit ("Break:");
1951 llmsglit (" /*@innerbreak@*/ - break is breaking an inner loop or switch");
1952 llmsglit (" /*@loopbreak@*/ - break is breaking a loop");
1953 llmsglit (" /*@switchbreak@*/ - break is breaking a switch");
1954 llmsglit (" /*@innercontinue@*/ - continue is continuing an inner loop");
1956 llmsglit ("Unreachable Code:");
1957 llmsglit (" /*@notreached@*/ - statement may be unreachable.");
1959 llmsglit ("Special Functions:");
1960 llmsglit (" /*@printflike@*/ - check variable arguments like printf");
1961 llmsglit (" /*@scanflike@*/ - check variable arguments like scanf");
1965 printComments (void)
1967 llmsglit ("Control Comments");
1968 llmsglit ("----------------");
1970 llmsglit ("Setting Flags");
1972 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.");
1974 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,");
1975 llmsglit (" /*@+boolint -modifies =showfunc@*/");
1976 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).");
1978 llmsglit ("Error Suppression");
1980 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.");
1982 llmsglit ("/*@ignore@*/ ... /*@end@*/");
1984 (cstring_makeLiteral
1985 ("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."));
1986 llmsglit ("/*@i@*/");
1988 (cstring_makeLiteral
1989 ("No errors will be reported from an /*@i@*/ comment to the end of the line."));
1990 llmsglit ("/*@i<n>@*/");
1992 (cstring_makeLiteral
1993 ("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, Splint will report an error."));
1994 llmsglit ("/*@t@*/, /*@t<n>@*/");
1996 (cstring_makeLiteral
1997 ("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."));
1999 llmsglit ("Type Access");
2001 llmsglit ("/*@access <type>@*/");
2002 llmsglit (" Allows the following code to access the representation of <type>");
2003 llmsglit ("/*@noaccess <type>@*/");
2004 llmsglit (" Hides the representation of <type>");
2006 llmsglit ("Macro Expansion");
2008 llmsglit ("/*@notfunction@*/");
2010 (cstring_makeLiteral
2011 ("Indicates that the next macro definition is not intended to be a "
2012 "function, and should be expanded in line instead of checked as a "
2013 "macro function definition."));
2020 llmsglit ("Flag Categories");
2021 llmsglit ("---------------");
2022 listAllCategories ();
2023 llmsglit ("\nTo see the flags in a flag category, do\n lclint -help flags <category>");
2024 llmsglit ("To see a list of all flags in alphabetical order, do\n lclint -help flags alpha");
2025 llmsglit ("To see a full description of all flags, do\n lclint -help flags full");
2029 printMaintainer (void)
2031 llmsg (message ("Maintainer: %s", cstring_makeLiteralTemp (LCLINT_MAINTAINER)));
2032 llmsglit (LCL_COMPILE);
2038 llmsglit ("Mailing Lists");
2039 llmsglit ("-------------");
2041 llmsglit ("There are two mailing lists associated with Splint: ");
2043 llmsglit (" lclint-announce@virginia.edu");
2045 llmsglit (" Reserved for announcements of new releases and bug fixes.");
2046 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
2047 llmsglit (" subscribe lclint-announce");
2049 llmsglit (" lclint-interest@virginia.edu");
2051 llmsglit (" Informal discussions on the use and development of lclint.");
2052 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
2053 llmsglit (" subscribe lclint-interest");
2057 printReferences (void)
2059 llmsglit ("References");
2060 llmsglit ("----------");
2062 llmsglit ("For more information, see the Splint web site: http://www.splint.org");
2066 describePrefixCodes (void)
2068 llmsglit ("Prefix Codes");
2069 llmsglit ("------------");
2071 llmsglit ("These characters have special meaning in name prefixes:");
2073 llmsg (message (" %h Any uppercase letter [A-Z]", PFX_UPPERCASE));
2074 llmsg (message (" %h Any lowercase letter [a-z]", PFX_LOWERCASE));
2075 llmsg (message (" %h Any character (valid in a C identifier)", PFX_ANY));
2076 llmsg (message (" %h Any digit [0-9]", PFX_DIGIT));
2077 llmsg (message (" %h Any non-uppercase letter [a-z0-9_]", PFX_NOTUPPER));
2078 llmsg (message (" %h Any non-lowercase letter [A-Z0-9_]", PFX_NOTLOWER));
2079 llmsg (message (" %h Any letter [A-Za-z]", PFX_ANYLETTER));
2080 llmsg (message (" %h Any letter or digit [A-Za-z0-9]", PFX_ANYLETTERDIGIT));
2081 llmsglit (" * Zero or more repetitions of the previous character class until the end of the name");
2090 eval = context_getLarchPath ();
2091 def = osd_getEnvironmentVariable (LARCH_PATH);
2093 if (cstring_isDefined (def) ||
2094 !cstring_equal (eval, cstring_fromChars (DEFAULT_LARCHPATH)))
2096 llmsg (message ("LARCH_PATH = %s", eval));
2100 llmsg (message ("LARCH_PATH = <not set> (default = %s)",
2101 cstring_fromChars (DEFAULT_LARCHPATH)));
2104 llmsglit (" --- path used to find larch initialization files and LSL traits");
2106 eval = context_getLCLImportDir ();
2107 def = osd_getEnvironmentVariable (cstring_makeLiteralTemp (LCLIMPORTDIR));
2109 if (cstring_isDefined (def) ||
2110 !cstring_equal (eval, cstring_fromChars (DEFAULT_LCLIMPORTDIR)))
2112 llmsg (message ("%q = %s", cstring_makeLiteral (LCLIMPORTDIR), eval));
2116 llmsg (message ("%s = <not set, default: %s>", cstring_makeLiteralTemp (LCLIMPORTDIR),
2117 cstring_makeLiteralTemp (DEFAULT_LCLIMPORTDIR)));
2120 llmsglit (" --- directory containing lcl standard library files "
2121 "(import with < ... >)");;
2124 ("include path = %q (set by environment variable %s and -I flags)",
2125 cppReader_getIncludePath (), INCLUDEPATH_VAR));
2127 llmsglit (" --- path used to find #include'd files");
2130 ("systemdirs = %s (set by -systemdirs or environment variable %s)", /*@i413223@*/
2131 context_getString (FLG_SYSTEMDIRS),
2134 llmsglit (" --- if file is found on this path, it is treated as a system file for error reporting");
2143 fprintf (stderr, "*** Interrupt\n");
2144 llexit (LLINTERRUPT);
2149 /* Cheat when there are parse errors */
2152 fprintf (stderr, "*** Segmentation Violation\n");
2154 /* Don't catch it if fileloc_unparse causes a signal */
2155 (void) signal (SIGSEGV, NULL);
2157 loc = fileloc_unparse (g_currentloc);
2159 fprintf (stderr, "*** Location (not trusted): %s\n",
2160 cstring_toCharsSafe (loc));
2163 fprintf (stderr, "*** Please report bug to %s\n", LCLINT_MAINTAINER);
2167 fprintf (stderr, "*** Signal: %d\n", i);
2169 fprintf (stderr, "*** Location (not trusted): %s\n",
2170 cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
2173 fprintf (stderr, "*** Please report bug to %s ***\n", LCLINT_MAINTAINER);
2181 static bool doneCleanup = FALSE;
2183 /* make sure this is only called once! */
2185 if (doneCleanup) return;
2190 ** Close all open files
2191 ** (There should only be open files, if we exited after a fatal error.)
2194 fileTable_closeAll (context_fileTable ());
2196 if (context_getFlag (FLG_KEEP))
2198 check (fputs ("Temporary files kept:\n", stderr) != EOF);
2199 fileTable_printTemps (context_fileTable ());
2204 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
2208 llbug (message ("Files unclosed: %d", nfiles));
2211 fileTable_cleanup (context_fileTable ());
2218 ** cleans up temp files (if necessary) and exits
2224 DPRINTF (("llexit: %d", status));
2227 if (status == LLFAILURE)
2235 if (status != LLFAILURE)
2237 context_destroyMod ();
2238 exprNode_destroyMod ();
2241 uentry_destroyMod ();
2242 typeIdSet_destroyMod ();
2245 dmalloc_shutdown ();
2249 exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
2252 bool readOptionsFile (cstring fname, cstringSList *passThroughArgs, bool report)
2256 if (fileTable_exists (context_fileTable (), fname))
2262 message ("Multiple attempts to read options file: %s", fname),
2268 FILE *innerf = fileTable_openFile (context_fileTable (), fname, "r");
2272 fileloc fc = g_currentloc;
2273 g_currentloc = fileloc_createRc (fname);
2275 if (context_getFlag (FLG_SHOWSCAN))
2277 lldiagmsg (message ("< reading options from %q >",
2278 fileloc_outputFilename (g_currentloc)));
2281 loadrc (innerf, passThroughArgs);
2282 fileloc_reallyFree (g_currentloc);
2292 message ("Cannot open options file: %s", fname),
2302 ** This shouldn't be necessary, but Apple Darwin can't handle '"''s.
2306 loadrc (/*:open:*/ FILE *rcfile, cstringSList *passThroughArgs)
2307 /*@modifies rcfile@*/
2308 /*@ensures closed rcfile@*/
2310 char *s = mstring_create (MAX_LINE_LENGTH);
2313 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2317 while (reader_readLine (rcfile, s, MAX_LINE_LENGTH) != NULL)
2324 DPRINTF (("Line: %s", s));
2325 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2327 while (*s == ' ' || *s == '\t')
2335 bool escaped = FALSE;
2336 bool quoted = FALSE;
2339 DPRINTF (("Process: %s", s));
2340 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2341 /* comment characters */
2342 if (c == '#' || c == ';' || c == '\n')
2348 if (c == '-' || c == '+')
2355 voptgenerror (FLG_BADFLAG,
2356 message ("Bad flag syntax (+ or - expected, "
2357 "+ is assumed): %s",
2358 cstring_fromChars (s)),
2369 while ((c = *s) != '\0')
2370 { /* remember to handle spaces and quotes in -D and -U ... */
2396 if (c == ' ' || c == '\t' || c == '\n')
2398 /*@innerbreak@*/ break;
2406 DPRINTF (("Nulling: %c", *s));
2409 if (mstring_isEmpty (thisflag))
2411 llfatalerror (message ("Missing flag: %s",
2412 cstring_fromChars (os)));
2415 DPRINTF (("Flag: %s", thisflag));
2417 opt = identifyFlag (cstring_fromChars (thisflag));
2419 if (flagcode_isSkip (opt))
2423 else if (flagcode_isInvalid (opt))
2425 DPRINTF (("Invalid: %s", thisflag));
2427 if (isMode (cstring_fromChars (thisflag)))
2429 context_setMode (cstring_fromChars (thisflag));
2433 voptgenerror (FLG_BADFLAG,
2434 message ("Unrecognized option: %s",
2435 cstring_fromChars (thisflag)),
2441 context_userSetFlag (opt, set);
2443 if (flagcode_hasArgument (opt))
2445 if (opt == FLG_HELP)
2448 voptgenerror (FLG_BADFLAG,
2449 message ("Cannot use help in rc files"),
2452 else if (flagcode_isPassThrough (opt)) /* -D or -U */
2454 cstring arg = cstring_fromCharsNew (thisflag);
2455 cstring_markOwned (arg);
2456 *passThroughArgs = cstringSList_add (*passThroughArgs, arg);
2457 DPRINTF (("Pass through: %s",
2458 cstringSList_unparse (*passThroughArgs)));
2460 else if (opt == FLG_INCLUDEPATH
2461 || opt == FLG_SPECPATH)
2463 cstring dir = cstring_suffix (cstring_fromChars (thisflag), 1); /* skip over I/S */
2467 case FLG_INCLUDEPATH:
2468 cppAddIncludeDir (dir);
2469 /*@switchbreak@*/ break;
2472 g_localSpecPath = cstring_toCharsSafe
2473 (message ("%s:%s", cstring_fromChars (g_localSpecPath), dir));
2475 /*@switchbreak@*/ break;
2479 else if (flagcode_hasString (opt)
2480 || flagcode_hasValue (opt)
2481 || opt == FLG_INIT || opt == FLG_OPTF)
2483 cstring extra = cstring_undefined;
2488 rest = mstring_copy (s);
2489 DPRINTF (("Here: rest = %s", rest));
2493 while ((rchar = *rest) != '\0'
2494 && (isspace ((int) rchar)))
2500 DPRINTF (("Yo: %s", rest));
2502 while ((rchar = *rest) != '\0'
2503 && !isspace ((int) rchar))
2505 extra = cstring_appendChar (extra, rchar);
2510 DPRINTF (("Yo: %s", extra));
2513 if (cstring_isUndefined (extra))
2519 ("Flag %s must be followed by an argument",
2520 flagcode_unparse (opt)),
2527 DPRINTF (("Here we are: %s", extra));
2529 if (flagcode_hasValue (opt))
2531 DPRINTF (("Set value flag: %s", extra));
2532 setValueFlag (opt, extra);
2534 else if (opt == FLG_OPTF)
2536 (void) readOptionsFile (extra, passThroughArgs, TRUE);
2538 else if (opt == FLG_INIT)
2541 llassert (inputStream_isUndefined (initFile));
2543 initFile = inputStream_create
2544 (cstring_copy (extra),
2545 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
2549 else if (flagcode_hasString (opt))
2551 DPRINTF (("Here: %s", extra));
2554 ** If it has "'s, we need to remove them.
2557 if (cstring_firstChar (extra) == '\"')
2559 if (cstring_lastChar (extra) == '\"')
2561 cstring unquoted = cstring_copyLength
2562 (cstring_toCharsSafe (cstring_suffix (extra, 1)),
2563 cstring_length (extra) - 2);
2565 DPRINTF (("string flag: %s -> %s", extra, unquoted));
2566 setStringFlag (opt, unquoted);
2567 cstring_free (extra);
2573 message ("Unmatched \" in option string: %s",
2576 setStringFlag (opt, extra);
2581 DPRINTF (("No quotes: %s", extra));
2582 setStringFlag (opt, extra);
2585 extra = cstring_undefined;
2593 cstring_free (extra);
2603 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2604 while ((c == ' ') || (c == '\t'))
2610 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2614 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2616 check (fileTable_closeFile (context_fileTable (), rcfile));
2619 static fileIdList preprocessFiles (fileIdList fl, bool xhfiles)
2620 /*@modifies fileSystem@*/
2622 bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
2623 int skip = (fileIdList_size (fl) / 5);
2624 int filesprocessed = 0;
2625 fileIdList dfiles = fileIdList_create ();
2627 fileloc_free (g_currentloc);
2628 g_currentloc = fileloc_createBuiltin ();
2630 fileIdList_elements (fl, fid)
2632 cstring ppfname = fileName (fid);
2634 if (!(osd_fileIsReadable (ppfname)))
2636 lldiagmsg (message ("Cannot open file: %q", osd_outputPath (ppfname)));
2637 ppfname = cstring_undefined;
2640 if (cstring_isDefined (ppfname))
2642 fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
2646 llassert (fileTable_isXHFile (context_fileTable (), dfile));
2649 llassert (cstring_isNonEmpty (ppfname));
2653 if ((filesprocessed % skip) == 0)
2655 if (filesprocessed == 0) {
2656 fprintf (stderr, " ");
2659 fprintf (stderr, ".");
2662 (void) fflush (stderr);
2667 if (cppProcess (ppfname, fileName (dfile)) != 0)
2669 llfatalerror (message ("Preprocessing error for file: %s",
2670 rootFileName (fid)));
2673 fileIdList_add (dfiles, dfile);
2675 } end_fileIdList_elements;
2680 /* This should be in an lclUtils.c file... */
2682 char *specFullName (char *specfile, /*@out@*/ char **inpath)
2684 /* extract the path and the specname associated with the given file */
2685 char *specname = (char *) dmalloc (sizeof (*specname)
2686 * (strlen (specfile) + 9));
2687 char *ospecname = specname;
2688 char *path = (char *) dmalloc (sizeof (*path) * (strlen (specfile)));
2692 /* initialized path to empty string or may have accidental garbage */
2695 /*@-mayaliasunique@*/
2696 strcpy (specname, specfile);
2697 /*@=mayaliasunique@*/
2699 /* trim off pathnames in specfile */
2700 size = strlen (specname);
2702 for (i = size_toInt (size) - 1; i >= 0; i--)
2704 if (specname[i] == CONNECTCHAR)
2706 /* strcpy (specname, (char *)specname+i+1); */
2707 for (j = 0; j <= i; j++) /* include '/' */
2709 path[j] = specname[j];
2719 ** also remove .lcl file extension, assume it's the last extension
2723 size = strlen (specname);
2725 for (i = size_toInt (size) - 1; i >= 0; i--)
2727 if (specname[i] == '.')
2737 ** If specname no longer points to the original char,
2738 ** we need to allocate a new pointer and copy the string.
2741 if (specname != ospecname) {
2742 char *rspecname = (char *) dmalloc (sizeof (*rspecname) * (strlen (specname) + 1));
2743 strcpy (rspecname, specname); /* evs 2000-05-16: Bug: was ospecname! */