]> andersk Git - splint.git/blame - src/llmain.c
Fixed state clauses. Added obvious loop exec checking.
[splint.git] / src / llmain.c
CommitLineData
616915dd 1/*
11db3170 2** Splint - annotation-assisted static program checker
77d37419 3** Copyright (C) 1994-2002 University of Virginia,
616915dd 4** Massachusetts Institute of Technology
5**
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.
10**
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.
15**
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.
19**
20** For information on lclint: lclint-request@cs.virginia.edu
21** To report a bug: lclint-bug@cs.virginia.edu
11db3170 22** For more information: http://www.splint.org
616915dd 23*/
24/*
25** llmain.c
26**
11db3170 27** Main module for Splint annotation-assisted program checker
616915dd 28*/
29
30# include <signal.h>
12f2ffe9 31# include <time.h>
616915dd 32/*
33** Ensure that WIN32 and _WIN32 are both defined or both undefined.
34*/
35
36# ifdef WIN32
37# ifndef _WIN32
38# error "Inconsistent definitions."
39# endif
40# else
41# ifdef _WIN32
42# error "Inconsistent definitions."
43# endif
44# endif
45
46# ifdef WIN32
47# include <windows.h>
48# include <process.h>
49# endif
50
51# include "lclintMacros.nf"
52# include "llbasic.h"
53# include "osd.h"
54
55# ifndef NOLCL
56# include "gram.h"
57# include "lclscan.h"
58# include "scanline.h"
59# include "lclscanline.h"
60# include "lclsyntable.h"
61# include "lcltokentable.h"
62# include "lslparse.h"
63# include "scan.h"
64# include "syntable.h"
65# include "tokentable.h"
66# include "lslinit.h"
67# include "lclinit.h"
68# include "lh.h"
69# include "imports.h"
70# endif
71
72# include "version.h"
616915dd 73# include "fileIdList.h"
74# include "lcllib.h"
75# include "cgrammar.h"
76# include "llmain.h"
77# include "portab.h"
12f2ffe9 78
616915dd 79
80extern /*@external@*/ int yydebug;
81
82static void printMail (void);
83static void printMaintainer (void);
84static void printReferences (void);
85static void printFlags (void);
86static void printAnnotations (void);
87static void printParseErrors (void);
88static void printComments (void);
89static void describePrefixCodes (void);
90static void cleanupFiles (void);
91static void showHelp (void);
92static void interrupt (int p_i);
990ec868 93
f2b6724f 94static bool readOptionsFile (cstring p_fname,
95 cstringSList *p_passThroughArgs,
96 bool p_report)
97 /*@modifies fileSystem, internalState, *p_passThroughArgs@*/ ;
98
15b3d2b2 99static void loadrc (FILE *p_rcfile, cstringSList *p_passThroughArgs)
146e25eb 100 /*@modifies *p_passThroughArgs, p_rcfile@*/
f2b6724f 101 /*@ensures closed p_rcfile@*/ ;
990ec868 102
616915dd 103static void describeVars (void);
104static bool specialFlagsHelp (char *p_next);
105static bool hasShownHerald = FALSE;
28bf4b0b 106static char *specFullName (char *p_specfile, /*@out@*/ char **p_inpath)
107 /*@modifies *p_inpath@*/ ;
616915dd 108
109static bool anylcl = FALSE;
110static clock_t inittime;
111
28bf4b0b 112static /*@only@*/ /*@null@*/ inputStream initFile = inputStream_undefined;
616915dd 113
28bf4b0b 114static fileIdList preprocessFiles (fileIdList, bool)
616915dd 115 /*@modifies fileSystem@*/ ;
116
117# ifndef NOLCL
118
119static
120void lslCleanup (void)
121 /*@globals killed g_symtab@*/
122 /*@modifies internalState, g_symtab@*/
123{
124 /*
125 ** Cleanup all the LCL/LSL.
126 */
127
128 static bool didCleanup = FALSE;
129
130 llassert (!didCleanup);
131 llassert (anylcl);
132
133 didCleanup = TRUE;
134
135 lsymbol_destroyMod ();
136 LCLSynTableCleanup ();
137 LCLTokenTableCleanup ();
138 LCLScanLineCleanup ();
139 LCLScanCleanup ();
140
141 /* clean up LSL parsing */
142
143 lsynTableCleanup ();
144 ltokenTableCleanup ();
145 lscanLineCleanup ();
146 LSLScanCleanup ();
147
148 symtable_free (g_symtab);
149 sort_destroyMod ();
150}
151
152static
153 void lslInit (void)
154 /*@globals undef g_symtab; @*/
155 /*@modifies g_symtab, internalState, fileSystem; @*/
156{
157 /*
158 ** Open init file provided by user, or use the default LCL init file
159 */
160
161 cstring larchpath = context_getLarchPath ();
28bf4b0b 162 inputStream LSLinitFile = inputStream_undefined;
616915dd 163
164 setCodePoint ();
165
28bf4b0b 166 if (inputStream_isUndefined (initFile))
616915dd 167 {
28bf4b0b 168 initFile = inputStream_create (cstring_makeLiteral (INITFILENAME),
169 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
170 FALSE);
616915dd 171
28bf4b0b 172 if (!inputStream_getPath (larchpath, initFile))
616915dd 173 {
174 lldiagmsg (message ("Continuing without LCL init file: %s",
28bf4b0b 175 inputStream_fileName (initFile)));
616915dd 176 }
177 else
178 {
28bf4b0b 179 if (!inputStream_open (initFile))
616915dd 180 {
181 lldiagmsg (message ("Continuing without LCL init file: %s",
28bf4b0b 182 inputStream_fileName (initFile)));
616915dd 183 }
184 }
185 }
186 else
187 {
28bf4b0b 188 if (!inputStream_open (initFile))
616915dd 189 {
190 lldiagmsg (message ("Continuing without LCL init file: %s",
28bf4b0b 191 inputStream_fileName (initFile)));
616915dd 192 }
193 }
194
195 /* Initialize checker */
196
197 lsymbol_initMod ();
198 LCLSynTableInit ();
199
200 setCodePoint ();
201
202 LCLSynTableReset ();
203 LCLTokenTableInit ();
204
205 setCodePoint ();
206
207 LCLScanLineInit ();
208 setCodePoint ();
209 LCLScanLineReset ();
210 setCodePoint ();
211 LCLScanInit ();
212
213 setCodePoint ();
214
215 /* need this to initialize LCL checker */
28bf4b0b 216
217 llassert (inputStream_isDefined (initFile));
218 if (inputStream_isOpen (initFile))
616915dd 219 {
220 setCodePoint ();
221
222 LCLScanReset (initFile);
223 LCLProcessInitFileInit ();
224 LCLProcessInitFileReset ();
225
226 setCodePoint ();
227 LCLProcessInitFile ();
228 LCLProcessInitFileCleanup ();
229
230 setCodePoint ();
28bf4b0b 231 check (inputStream_close (initFile));
616915dd 232 }
233
234 /* Initialize LSL init files, for parsing LSL signatures from LSL */
235
28bf4b0b 236 LSLinitFile = inputStream_create (cstring_makeLiteral ("lslinit.lsi"),
237 cstring_makeLiteralTemp (".lsi"),
238 FALSE);
616915dd 239
28bf4b0b 240 if (!inputStream_getPath (larchpath, LSLinitFile))
616915dd 241 {
242 lldiagmsg (message ("Continuing without LSL init file: %s",
28bf4b0b 243 inputStream_fileName (LSLinitFile)));
616915dd 244 }
245 else
246 {
28bf4b0b 247 if (!inputStream_open (LSLinitFile))
616915dd 248 {
249 lldiagmsg (message ("Continuing without LSL init file: %s",
28bf4b0b 250 inputStream_fileName (LSLinitFile)));
616915dd 251 }
252 }
253
254 setCodePoint ();
255 lsynTableInit ();
256 lsynTableReset ();
257
258 setCodePoint ();
259 ltokenTableInit ();
260
261 setCodePoint ();
262 lscanLineInit ();
263 lscanLineReset ();
264 LSLScanInit ();
265
28bf4b0b 266 if (inputStream_isOpen (LSLinitFile))
616915dd 267 {
268 setCodePoint ();
269 LSLScanReset (LSLinitFile);
270 LSLProcessInitFileInit ();
271 setCodePoint ();
272 LSLProcessInitFile ();
273 setCodePoint ();
28bf4b0b 274 check (inputStream_close (LSLinitFile));
616915dd 275 }
276
28bf4b0b 277 inputStream_free (LSLinitFile);
616915dd 278
279 if (lclHadError ())
280 {
281 lclplainerror
282 (cstring_makeLiteral ("LSL init file error. Attempting to continue."));
283 }
284
285 setCodePoint ();
286 g_symtab = symtable_new ();
287
288 /*
289 ** sort_init must come after symtab has been initialized
290 */
291 sort_init ();
292 abstract_init ();
293 setCodePoint ();
294
295 inittime = clock ();
296
297 /*
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".
301 **
302 ** Reads in CTrait.syms (derived from CTrait.lsl) on LARCH_PATH.
303 */
304
305 LCLBuiltins ();
306 LCLReportEolTokens (FALSE);
307}
308
309static void
310lslProcess (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; @*/
314{
315 char *path = NULL;
316 bool parser_status = FALSE;
317 bool overallStatus = FALSE;
318
319 lslInit ();
320
321 context_resetSpecLines ();
322
323 fileIdList_elements (lclfiles, fid)
324 {
28bf4b0b 325 cstring actualName = cstring_undefined;
326 cstring fname = fileName (fid);
616915dd 327
28bf4b0b 328 if (osd_getPath (cstring_fromChars (g_localSpecPath),
329 fname, &actualName) == OSD_FILENOTFOUND)
616915dd 330 {
331 if (mstring_equal (g_localSpecPath, "."))
332 {
53a89507 333 lldiagmsg (message ("Spec file not found: %q", osd_outputPath (fname)));
616915dd 334 }
335 else
336 {
53a89507 337 lldiagmsg (message ("Spec file not found: %q (on %s)",
338 osd_outputPath (fname),
616915dd 339 cstring_fromChars (g_localSpecPath)));
340 }
341 }
342 else
343 {
28bf4b0b 344 inputStream specFile;
345 /*@access cstring@*/
346 char *namePtr = actualName;
347
348 while (*namePtr == '.' && *(namePtr + 1) == CONNECTCHAR)
616915dd 349 {
28bf4b0b 350 namePtr += 2;
616915dd 351 }
28bf4b0b 352 /*@noaccess cstring@*/
353
354 g_currentSpec = cstring_fromCharsNew (namePtr);
355
356 specFile = inputStream_create (cstring_copy (g_currentSpec),
357 LCL_EXTENSION, TRUE);
616915dd 358
28bf4b0b 359 llassert (inputStream_isDefined (specFile));
616915dd 360
616915dd 361 g_currentSpecName = specFullName
362 (cstring_toCharsSafe (g_currentSpec),
363 &path);
364
365 setSpecFileId (fid);
366
367 if (context_getFlag (FLG_SHOWSCAN))
368 {
369 lldiagmsg (message ("< reading spec %s >", g_currentSpec));
370 }
371
372 /* Open source file */
373
28bf4b0b 374 if (!inputStream_open (specFile))
616915dd 375 {
53a89507 376 lldiagmsg (message ("Cannot open file: %q",
377 osd_outputPath (inputStream_fileName (specFile))));
28bf4b0b 378 inputStream_free (specFile);
616915dd 379 }
380 else
381 {
382 scopeInfo dummy_scope = (scopeInfo) dmalloc (sizeof (*dummy_scope));
383 dummy_scope->kind = SPE_INVALID;
384
385 lhInit (specFile);
386 LCLScanReset (specFile);
387
388 /*
389 ** Minor hacks to allow more than one LCL file to
390 ** be scanned, while keeping initializations
391 */
392
393 symtable_enterScope (g_symtab, dummy_scope);
394 resetImports (cstring_fromChars (g_currentSpecName));
395 context_enterLCLfile ();
396 (void) lclHadNewError ();
397
398 parser_status = (ylparse () != 0);
399 context_exitLCLfile ();
400 lhCleanup ();
401 overallStatus = parser_status || lclHadNewError ();
402
403 if (context_getFlag (FLG_DOLCS))
404 {
405 if (overallStatus)
406 {
28bf4b0b 407 outputLCSFile (path, "%FAILED Output from ",
616915dd 408 g_currentSpecName);
409 }
410 else
411 {
28bf4b0b 412 outputLCSFile (path, "%PASSED Output from ",
616915dd 413 g_currentSpecName);
414 }
415 }
416
28bf4b0b 417 (void) inputStream_close (specFile);
418 inputStream_free (specFile);
616915dd 419
420 symtable_exitScope (g_symtab);
28bf4b0b 421 }
616915dd 422 }
28bf4b0b 423 cstring_free (actualName);
616915dd 424 } end_fileIdList_elements;
28bf4b0b 425
616915dd 426 /* Can cleanup lsl stuff right away */
28bf4b0b 427
428 lslCleanup ();
429
430 g_currentSpec = cstring_undefined;
431 g_currentSpecName = NULL;
616915dd 432}
433# endif
434
435static void handlePassThroughFlag (char *arg)
436{
437 char *curarg = arg;
438 char *quotechar = strchr (curarg, '\"');
439 int offset = 0;
440 bool open = FALSE;
b37cf05e 441 char *freearg = NULL;
616915dd 442
443 while (quotechar != NULL)
444 {
445 if (*(quotechar - 1) == '\\')
446 {
447 char *tp = quotechar - 2;
448 bool escape = TRUE;
449
450 while (*tp == '\\')
451 {
452 escape = !escape;
453 tp--;
454 }
455
456 if (escape)
457 {
458 curarg = quotechar + 1;
459 quotechar = strchr (curarg, '\"');
460 continue;
461 }
462 }
463
b37cf05e 464 llassert (quotechar != NULL);
616915dd 465 *quotechar = '\0';
466 offset = (quotechar - arg) + 2;
467
468 if (open)
469 {
470 arg = cstring_toCharsSafe
471 (message ("%s\"\'%s",
472 cstring_fromChars (arg),
473 cstring_fromChars (quotechar + 1)));
b37cf05e 474 freearg = arg;
616915dd 475 open = FALSE;
476 }
477 else
478 {
479 arg = cstring_toCharsSafe
480 (message ("%s\'\"%s",
481 cstring_fromChars (arg),
482 cstring_fromChars (quotechar + 1)));
b37cf05e 483 freearg = arg;
616915dd 484 open = TRUE;
485 }
486
487 curarg = arg + offset;
488 quotechar = strchr (curarg, '\"');
489 }
490
491 if (open)
492 {
493 showHerald ();
ccf0a4a8 494 voptgenerror (FLG_BADFLAG,
495 message ("Unclosed quote in flag: %s",
496 cstring_fromChars (arg)),
497 g_currentloc);
616915dd 498 }
499 else
500 {
501 if (arg[0] == 'D') {
502 cstring def;
503
504 /*
505 ** If the value is surrounded by single quotes ('), remove
506 ** them. This is an artifact of UNIX command line?
507 */
508
28bf4b0b 509 def = osd_fixDefine (cstring_fromChars (arg + 1));
616915dd 510 DPRINTF (("Do define: %s", def));
511 cppDoDefine (def);
512 DPRINTF (("After define"));
513 cstring_free (def);
514 } else if (arg[0] == 'U') {
515 cppDoUndefine (cstring_fromChars (arg + 1));
516 } else {
517 BADBRANCH;
518 }
519 }
b37cf05e 520
521 sfree (freearg);
616915dd 522}
523
524void showHerald (void)
525{
526 if (hasShownHerald || context_getFlag (FLG_QUIET)) return;
527
528 else
529 {
60868d40 530 fprintf (g_msgstream, "%s\n\n", SPLINT_VERSION);
616915dd 531 hasShownHerald = TRUE;
532 llflush ();
533 }
534}
535
53a89507 536static cstring findLarchPathFile (/*@temp@*/ cstring s)
616915dd 537{
53a89507 538 cstring pathName;
539 filestatus status;
540
541 status = osd_getPath (context_getLarchPath (), s, &pathName);
542
543 if (status == OSD_FILEFOUND)
544 {
545 return pathName;
546 }
547 else if (status == OSD_FILENOTFOUND)
616915dd 548 {
549 showHerald ();
53a89507 550 lldiagmsg (message ("Cannot find file on LARCHPATH: %s", s));
551 }
552 else if (status == OSD_PATHTOOLONG)
553 {
554 /* Directory and filename are too long. Report error. */
555 llbuglit ("soure_getPath: Filename plus directory from search path too long");
616915dd 556 }
557 else
558 {
53a89507 559 BADBRANCH;
616915dd 560 }
53a89507 561
562 return cstring_undefined;
616915dd 563}
564
53a89507 565static void addLarchPathFile (fileIdList files, /*@temp@*/ cstring s)
566{
567 cstring pathName = findLarchPathFile (s);
568
569 if (cstring_isDefined (pathName))
570 {
571 if (fileTable_exists (context_fileTable (), pathName))
572 {
573 showHerald ();
574 lldiagmsg (message ("File listed multiple times: %s", pathName));
575 cstring_free (pathName);
576 }
577 else
578 {
579 fileIdList_add (files, fileTable_addFileOnly (context_fileTable (), pathName));
580 }
581 }
582}
583
584static void addFile (fileIdList files, /*@only@*/ cstring s)
28bf4b0b 585{
586 if (fileTable_exists (context_fileTable (), s))
587 {
588 showHerald ();
589 lldiagmsg (message ("File listed multiple times: %s", s));
590 cstring_free (s);
591 }
592 else
593 {
53a89507 594 fileIdList_add (files, fileTable_addFileOnly (context_fileTable (), s));
28bf4b0b 595 }
596}
597
53a89507 598static void addXHFile (fileIdList files, /*@temp@*/ cstring s)
599{
600 cstring pathName = findLarchPathFile (s);
601
602 if (cstring_isDefined (pathName))
603 {
604 if (fileTable_exists (context_fileTable (), pathName))
605 {
606 showHerald ();
607 lldiagmsg (message ("File listed multiple times: %s", s));
608 }
609 else
610 {
611 fileIdList_add (files, fileTable_addXHFile (context_fileTable (), pathName));
612 }
613 }
614
615 cstring_free (pathName);
616}
617
616915dd 618/*
619** Disable MSVC++ warning about return value. Methinks humbly lclint control
620** comments are a mite more legible.
621*/
622
623# ifdef WIN32
624# pragma warning (disable:4035)
625# endif
626
627int main (int argc, char *argv[])
628# ifdef NOLCL
629 /*@globals killed undef g_currentloc,
630 killed undef yyin,
631 undef g_msgstream;
632 @*/
633 /*@modifies g_currentloc, fileSystem,
634 yyin;
635 @*/
636# else
637 /*@globals killed undef g_currentloc,
638 killed undef initFile,
639 killed g_localSpecPath,
640 killed undef g_currentSpec,
641 killed undef g_currentSpecName,
642 killed undef yyin,
643 undef g_msgstream;
644 @*/
645 /*@modifies g_currentloc, initFile,
646 g_localSpecPath, g_currentSpec, g_currentSpecName, fileSystem,
647 yyin;
648 @*/
649# endif
650{
651 bool first_time = TRUE;
652 bool showhelp = FALSE;
653 bool allhelp = TRUE;
654 bool expsuccess;
28bf4b0b 655 inputStream sourceFile = inputStream_undefined;
616915dd 656
657 fileIdList dercfiles;
658 cstringSList fl = cstringSList_undefined;
659 cstringSList passThroughArgs = cstringSList_undefined;
28bf4b0b 660 fileIdList cfiles, xfiles, lclfiles, mtfiles;
616915dd 661 clock_t before, lcltime, libtime, pptime, cptime, rstime;
662 int i = 0;
663
22367f91 664# ifdef __EMX__
665 _wildcard (&argc, &argv);
666# endif
667
616915dd 668 g_msgstream = stdout;
669
670 (void) signal (SIGINT, interrupt);
671 (void) signal (SIGSEGV, interrupt);
672
673 cfiles = fileIdList_create ();
28bf4b0b 674 xfiles = fileIdList_create ();
616915dd 675 lclfiles = fileIdList_create ();
28bf4b0b 676 mtfiles = fileIdList_create ();
616915dd 677
678 flags_initMod ();
28bf4b0b 679 clabstract_initMod ();
616915dd 680 typeIdSet_initMod ();
681 cppReader_initMod ();
53a89507 682 osd_initMod ();
683
616915dd 684 setCodePoint ();
28bf4b0b 685
616915dd 686 g_currentloc = fileloc_createBuiltin ();
28bf4b0b 687
616915dd 688 before = clock ();
689 context_initMod ();
28bf4b0b 690
616915dd 691 context_setInCommandLine ();
692
693 if (argc <= 1)
694 {
695 showHelp ();
696 llexit (LLGIVEUP);
697 }
698
699 setCodePoint ();
700 yydebug = 0;
701
702 /*
703 ** Add include directories from environment.
704 */
705
706 {
7272a1c1 707 cstring incval = cstring_copy (osd_getEnvironmentVariable (INCLUDEPATH_VAR));
b37cf05e 708 cstring oincval = incval;
616915dd 709
28bf4b0b 710 if (cstring_isDefined (incval))
616915dd 711 {
712 /*
713 ** Each directory on the include path is a system include directory.
714 */
715
716 DPRINTF (("include: %s", incval));
28bf4b0b 717 context_setString (FLG_SYSTEMDIRS, cstring_copy (incval));
616915dd 718
28bf4b0b 719 while (cstring_isDefined (incval))
616915dd 720 {
28bf4b0b 721 /*@access cstring@*/
7272a1c1 722 char *nextsep = strchr (incval, PATH_SEPARATOR);
616915dd 723
724 if (nextsep != NULL)
725 {
726 cstring dir;
727 *nextsep = '\0';
28bf4b0b 728 dir = cstring_copy (incval);
616915dd 729
730 if (cstring_length (dir) == 0
731 || !isalpha ((int) cstring_firstChar (dir)))
732 {
733 /*
734 ** win32 environment values can have special values,
735 ** ignore them
736 */
737 }
738 else
739 {
616915dd 740 cppAddIncludeDir (dir);
741 }
742
7272a1c1 743 *nextsep = PATH_SEPARATOR;
28bf4b0b 744 incval = cstring_fromChars (nextsep + 1);
616915dd 745 cstring_free (dir);
746 }
747 else
748 {
749 break;
750 }
28bf4b0b 751
752 /*@noaccess cstring@*/
616915dd 753 }
754 }
68de3f33 755 else /* 2001-09-09: herbert */
756 {
757 /* Put C_INCLUDE_PATH directories in sysdirs */
758 cstring cincval = osd_getEnvironmentVariable (cstring_makeLiteralTemp ("C_INCLUDE_PATH"));
759 if (cstring_isDefined (cincval))
760 {
761 context_setString (FLG_SYSTEMDIRS, cstring_copy (cincval));
762 }
763 }
764 /* /herbert */
28bf4b0b 765
b37cf05e 766 cstring_free (oincval);
616915dd 767 }
768
769 /*
770 ** check RCFILE for default flags
771 */
772
773 {
28bf4b0b 774 cstring home = osd_getHomeDir ();
60868d40 775 cstring fname = cstring_undefined;
616915dd 776 bool defaultf = TRUE;
777 bool nof = FALSE;
778
779 for (i = 1; i < argc; i++)
780 {
781 char *thisarg;
782 thisarg = argv[i];
783
784 if (*thisarg == '-' || *thisarg == '+')
785 {
f2b6724f 786 bool set = (*thisarg == '+');
787 flagcode opt;
788
616915dd 789 thisarg++;
f2b6724f 790 opt = identifyFlag (cstring_fromChars (thisarg));
616915dd 791
f2b6724f 792 if (opt == FLG_NOF)
616915dd 793 {
794 nof = TRUE;
795 }
f2b6724f 796 else if (opt == FLG_SHOWSCAN || opt == FLG_WARNRC)
797 {
798 /*
799 ** Need to set it immediately, so rc file scan is displayed
800 */
801
802 context_userSetFlag (opt, set);
803 }
804 else if (opt == FLG_OPTF)
616915dd 805 {
806 if (++i < argc)
807 {
808 defaultf = FALSE;
60868d40 809 fname = cstring_fromChars (argv[i]);
146e25eb 810 (void) readOptionsFile (fname, &passThroughArgs, TRUE);
616915dd 811 }
812 else
813 llfatalerror
814 (cstring_makeLiteral ("Flag f to select options file "
815 "requires an argument"));
816 }
817 else
818 {
819 ; /* wait to process later */
820 }
821 }
822 }
f2b6724f 823
616915dd 824 setCodePoint ();
825
826 if (!nof && defaultf)
827 {
60868d40 828 /*
f2b6724f 829 ** No explicit rc file, first try reading ~/.splintrc
60868d40 830 */
616915dd 831
f2b6724f 832 if (cstring_isUndefined (fname))
60868d40 833 {
f2b6724f 834 if (!cstring_isEmpty (home))
60868d40 835 {
f2b6724f 836 bool readhomerc, readaltrc;
837 cstring homename, altname;
838
839 homename = message ("%s%h%s", home, CONNECTCHAR,
840 cstring_fromChars (RCFILE));
841 readhomerc = readOptionsFile (homename, &passThroughArgs, FALSE);
60868d40 842
f2b6724f 843 /*
844 ** Try ~/.lclintrc also for historical accuracy
845 */
846
847 altname = message ("%s%h%s", home, CONNECTCHAR,
848 cstring_fromChars (ALTRCFILE));
849 readaltrc = readOptionsFile (altname, &passThroughArgs, FALSE);
850
851 if (readhomerc && readaltrc)
852 {
853
854 voptgenerror
855 (FLG_WARNRC,
856 message ("Found both %s and %s files. Using both files, "
857 "but recommend using only %s to avoid confusion.",
858 homename, altname, homename),
859 g_currentloc);
860 }
146e25eb 861
862 cstring_free (homename);
863 cstring_free (altname);
60868d40 864 }
865 }
866
f2b6724f 867 /*
868 ** Next, read .splintrc in the current working directory
869 */
870
871 {
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;
875
876 readrc = readOptionsFile (rcname, &passThroughArgs, FALSE);
877 readaltrc = readOptionsFile (altname, &passThroughArgs, FALSE);
878
879 if (readrc && readaltrc)
880 {
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),
885 g_currentloc);
886
887 }
616915dd 888
f2b6724f 889 cstring_free (rcname);
890 cstring_free (altname);
891 }
616915dd 892 }
893 }
894
895 setCodePoint ();
896
897 for (i = 1; i < argc; i++)
898 {
899 char *thisarg;
900 flagcode opt;
901
902 thisarg = argv[i];
903
904 if (showhelp)
905 {
906 if (allhelp)
907 {
908 showHerald ();
909 }
910
911 allhelp = FALSE;
912
913 if (*thisarg == '-' || *thisarg == '+')
914 {
915 thisarg++; /* skip '-' */
916 }
917 if (mstring_equal (thisarg, "modes"))
918 {
919 llmsg (describeModes ());
920 }
921 else if (mstring_equal (thisarg, "vars")
922 || mstring_equal (thisarg, "env"))
923 {
924 describeVars ();
925 }
926 else if (mstring_equal (thisarg, "annotations"))
927 {
928 printAnnotations ();
929 }
930 else if (mstring_equal (thisarg, "parseerrors"))
931 {
932 printParseErrors ();
933 }
934 else if (mstring_equal (thisarg, "comments"))
935 {
936 printComments ();
937 }
938 else if (mstring_equal (thisarg, "prefixcodes"))
939 {
940 describePrefixCodes ();
941 }
942 else if (mstring_equal (thisarg, "references")
943 || mstring_equal (thisarg, "refs"))
944 {
945 printReferences ();
946 }
947 else if (mstring_equal (thisarg, "mail"))
948 {
949 printMail ();
950 }
951 else if (mstring_equal (thisarg, "maintainer")
952 || mstring_equal (thisarg, "version"))
953 {
954 printMaintainer ();
955 }
956 else if (mstring_equal (thisarg, "flags"))
957 {
958 if (i + 1 < argc)
959 {
960 char *next = argv[i + 1];
961
962 if (specialFlagsHelp (next))
963 {
964 i++;
965 }
966 else
967 {
968 flagkind k = identifyCategory (cstring_fromChars (next));
969
970 if (k != FK_NONE)
971 {
972 printCategory (k);
973 i++;
974 }
975 }
976 }
977 else
978 {
979 printFlags ();
980 }
981 }
982 else
983 {
984 cstring s = describeFlag (cstring_fromChars (thisarg));
985
986 if (cstring_isDefined (s))
987 {
988 llmsg (s);
989 }
990 }
991 }
992 else
993 {
994 if (*thisarg == '-' || *thisarg == '+')
995 {
996 bool set = (*thisarg == '+');
997 cstring flagname;
998
999 thisarg++; /* skip '-' */
1000 flagname = cstring_fromChars (thisarg);
28bf4b0b 1001
1002 DPRINTF (("Flag: %s", flagname));
616915dd 1003 opt = identifyFlag (flagname);
28bf4b0b 1004 DPRINTF (("Flag: %s", flagcode_unparse (opt)));
1005
f2b6724f 1006 if (flagcode_isSkip (opt) || opt == FLG_SHOWSCAN || opt == FLG_WARNRC)
616915dd 1007 {
f2b6724f 1008 /* showscan already processed */
28bf4b0b 1009 DPRINTF (("Skipping!"));
616915dd 1010 }
1011 else if (flagcode_isInvalid (opt))
1012 {
28bf4b0b 1013 DPRINTF (("Invalid: %s", flagname));
1014
616915dd 1015 if (isMode (flagname))
1016 {
1017 context_setMode (flagname);
1018 }
1019 else
1020 {
28bf4b0b 1021 DPRINTF (("Error!"));
efd360a3 1022 voptgenerror (FLG_BADFLAG,
1023 message ("Unrecognized option: %s",
1024 cstring_fromChars (thisarg)),
1025 g_currentloc);
616915dd 1026 }
1027 }
1028 else
1029 {
1030 context_userSetFlag (opt, set);
1031
1032 if (flagcode_hasArgument (opt))
1033 {
1034 if (opt == FLG_HELP)
1035 {
1036 showhelp = TRUE;
1037 }
1038 else if (flagcode_isPassThrough (opt)) /* -D or -U */
1039 {
1040 passThroughArgs = cstringSList_add
1041 (passThroughArgs, cstring_fromChars (thisarg));
1042 }
1043 else if (flagcode_hasValue (opt))
1044 {
1045 if (++i < argc)
1046 {
1047 setValueFlag (opt, cstring_fromChars (argv[i]));
1048 }
1049 else
1050 {
1051 llfatalerror
1052 (message
1053 ("Flag %s must be followed by a number",
1054 flagcode_unparse (opt)));
1055 }
1056 }
1057 else if (opt == FLG_INCLUDEPATH || opt == FLG_SPECPATH)
1058 {
1059 cstring dir = cstring_suffix (cstring_fromChars (thisarg), 1); /* skip over I */
1060
1061 switch (opt)
1062 {
1063 case FLG_INCLUDEPATH:
1064 cppAddIncludeDir (dir);
1065 /*@switchbreak@*/ break;
1066 case FLG_SPECPATH:
1067 /*@-mustfree@*/
1068 g_localSpecPath = cstring_toCharsSafe
1069 (message ("%s%h%s",
1070 cstring_fromChars (g_localSpecPath),
7272a1c1 1071 PATH_SEPARATOR,
616915dd 1072 dir));
1073 /*@=mustfree@*/
1074 /*@switchbreak@*/ break;
1075 BADDEFAULT;
1076 }
1077 }
1078 else if (flagcode_hasString (opt)
1079 || opt == FLG_INIT || opt == FLG_OPTF)
1080 {
1081 if (++i < argc)
1082 {
1083 cstring arg = cstring_fromChars (argv[i]);
1084
1085 if (opt == FLG_OPTF)
1086 {
1087 ; /* -f already processed */
1088 }
1089 else if (opt == FLG_INIT)
1090 {
1091# ifndef NOLCL
28bf4b0b 1092 initFile = inputStream_create
1093 (arg,
1094 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
1095 FALSE);
616915dd 1096# endif
1097 break;
1098 }
1099 else
1100 {
28bf4b0b 1101 DPRINTF (("String flag: %s / %s",
1102 flagcode_unparse (opt), arg));
1103 if (opt == FLG_MTSFILE)
1104 {
1105 /*
1106 ** arg identifies mts files
1107 */
53a89507 1108 cstring tmp = message ("%s%s", arg, MTS_EXTENSION);
1109 addLarchPathFile (mtfiles, tmp);
1110 cstring_free (tmp);
1111 tmp = message ("%s%s", arg, XH_EXTENSION);
1112 addXHFile (xfiles, tmp);
1113 cstring_free (tmp);
28bf4b0b 1114 }
1115 else
1116 {
1117 setStringFlag (opt, arg);
1118 }
616915dd 1119 }
1120 }
1121 else
1122 {
1123 llfatalerror
1124 (message
1125 ("Flag %s must be followed by a string",
1126 flagcode_unparse (opt)));
1127 }
1128 }
1129 else
1130 {
1131 /* no argument */
1132 }
1133 }
1134 }
1135 }
1136 else /* its a filename */
1137 {
28bf4b0b 1138 DPRINTF (("Adding filename: %s", thisarg));
616915dd 1139 fl = cstringSList_add (fl, cstring_fromChars (thisarg));
1140 }
1141 }
1142 }
1143
1144 setCodePoint ();
f2b6724f 1145 showHerald ();
1146
616915dd 1147 /*
1148 ** create lists of C and LCL files
1149 */
1150
1151 cstringSList_elements (fl, current)
1152 {
28bf4b0b 1153 cstring ext = fileLib_getExtension (current);
1154
1155 if (cstring_isUndefined (ext))
616915dd 1156 {
1157 /* no extension --- both C and LCL with default extensions */
1158
28bf4b0b 1159 addFile (cfiles, message ("%s%s", current, C_EXTENSION));
1160 addFile (lclfiles, message ("%s%s", current, LCL_EXTENSION));
1161 }
1162 else if (cstring_equal (ext, XH_EXTENSION))
1163 {
53a89507 1164 addXHFile (xfiles, current);
28bf4b0b 1165 }
68de3f33 1166 else if (cstring_equal (ext, PP_EXTENSION))
1167 {
1168 if (!context_getFlag (FLG_NOPP))
1169 {
1170 voptgenerror
1171 (FLG_FILEEXTENSIONS,
1172 message ("File extension %s used without +nopp flag (will be processed as C source code): %s",
1173 ext, current),
1174 g_currentloc);
1175 }
1176
1177 addFile (cfiles, cstring_copy (current));
1178 }
28bf4b0b 1179 else if (cstring_equal (ext, LCL_EXTENSION))
1180 {
1181 addFile (lclfiles, cstring_copy (current));
616915dd 1182 }
28bf4b0b 1183 else if (fileLib_isCExtension (ext))
616915dd 1184 {
28bf4b0b 1185 addFile (cfiles, cstring_copy (current));
1186 }
1187 else if (cstring_equal (ext, MTS_EXTENSION))
1188 {
53a89507 1189 addLarchPathFile (mtfiles, current);
616915dd 1190 }
1191 else
1192 {
28bf4b0b 1193 voptgenerror
1194 (FLG_FILEEXTENSIONS,
1195 message ("Unrecognized file extension: %s (assuming %s is C source code)",
1196 current, ext),
1197 g_currentloc);
1198
1199 addFile (cfiles, cstring_copy (current));
616915dd 1200 }
1201 } end_cstringSList_elements;
1202
616915dd 1203 if (showhelp)
1204 {
1205 if (allhelp)
1206 {
1207 showHelp ();
1208 }
1209 fprintf (g_msgstream, "\n");
1210
1211 fileIdList_free (cfiles);
28bf4b0b 1212 fileIdList_free (xfiles);
616915dd 1213 fileIdList_free (lclfiles);
1214
1215 llexit (LLSUCCESS);
1216 }
1217
1218# ifdef DOANNOTS
1219 initAnnots ();
1220# endif
1221
1222 inittime = clock ();
1223
1224 context_resetErrors ();
1225 context_clearInCommandLine ();
1226
1227 anylcl = !fileIdList_isEmpty (lclfiles);
1228
1229 if (context_doMerge ())
1230 {
1231 cstring m = context_getMerge ();
1232
1233 if (context_getFlag (FLG_SHOWSCAN))
1234 {
1235 fprintf (g_msgstream, "< loading %s ", cstring_toCharsSafe (m));
1236 }
1237
1238 loadState (m);
1239
1240 if (context_getFlag (FLG_SHOWSCAN))
1241 {
1242 fprintf (g_msgstream, " >\n");
1243 }
1244
1245 if (!usymtab_existsType (context_getBoolName ()))
1246 {
1247 usymtab_initBool ();
1248 }
1249 }
1250 else
1251 {
1252 if (!context_getFlag (FLG_NOLIB) && loadStandardState ())
1253 {
1254 ;
1255 }
1256 else
1257 {
1258 ctype_initTable ();
1259 }
1260
1261 /* setup bool type and constants */
1262 usymtab_initBool ();
1263 }
1264
1265 fileloc_free (g_currentloc);
1266 g_currentloc = fileloc_createBuiltin ();
1267
28bf4b0b 1268 /*
1269 ** Read metastate files (must happen before loading libraries)
1270 */
1271
1272 fileIdList_elements (mtfiles, mtfile)
1273 {
1274 context_setFileId (mtfile);
1275
1276 if (context_getFlag (FLG_SHOWSCAN))
1277 {
1278 lldiagmsg (message ("< processing %s >", rootFileName (mtfile)));
1279 }
1280
1281 mtreader_readFile (cstring_copy (fileName (mtfile)));
1282 } end_fileIdList_elements;
1283
616915dd 1284 libtime = clock ();
28bf4b0b 1285
616915dd 1286 if (anylcl)
1287 {
1288# ifdef NOLCL
11db3170 1289 llfatalerror (cstring_makeLiteral ("This version of Splint does not handle LCL files."));
616915dd 1290# else
1291 lslProcess (lclfiles);
1292# endif
1293 }
1294
28bf4b0b 1295 usymtab_initGlobalMarker ();
1296
616915dd 1297 /*
1298 ** pre-processing
1299 **
1300 ** call the pre-preprocessor and /lib/cpp to generate appropriate
1301 ** files
1302 **
1303 */
1304
1305 context_setInCommandLine ();
1306
616915dd 1307 DPRINTF (("Pass through: %s", cstringSList_unparse (passThroughArgs)));
1308
1309 cstringSList_elements (passThroughArgs, thisarg) {
1310 handlePassThroughFlag (cstring_toCharsSafe (thisarg));
1311 } end_cstringSList_elements;
1312
1313 cstringSList_free (passThroughArgs);
1314
1315 cleanupMessages ();
1316
28bf4b0b 1317 DPRINTF (("Initializing cpp reader!"));
1318 cppReader_initialize ();
616915dd 1319 cppReader_saveDefinitions ();
1320
1321 context_clearInCommandLine ();
1322
1323 if (!context_getFlag (FLG_NOPP))
1324 {
28bf4b0b 1325 fileIdList tfiles;
1326
616915dd 1327 llflush ();
1328
1329 if (context_getFlag (FLG_SHOWSCAN))
1330 {
1331 fprintf (stderr, "< preprocessing");
1332 }
1333
1334 lcltime = clock ();
1335
1336 context_setPreprocessing ();
28bf4b0b 1337 dercfiles = preprocessFiles (xfiles, TRUE);
1338 tfiles = preprocessFiles (cfiles, FALSE);
1339 dercfiles = fileIdList_append (dercfiles, tfiles);
1340 fileIdList_free (tfiles);
1341
616915dd 1342 context_clearPreprocessing ();
1343
1344 fileIdList_free (cfiles);
1345
1346 if (context_getFlag (FLG_SHOWSCAN))
1347 {
1348 fprintf (stderr, " >\n");
1349 }
1350
1351 pptime = clock ();
1352 }
1353 else
1354 {
1355 lcltime = clock ();
28bf4b0b 1356 dercfiles = fileIdList_append (cfiles, xfiles);
616915dd 1357 pptime = clock ();
1358 }
28bf4b0b 1359
616915dd 1360 /*
1361 ** now, check all the corresponding C files
1362 **
1363 ** (for now these are just <file>.c, but after pre-processing
1364 ** will be <tmpprefix>.<file>.c)
1365 */
1366
1367 {
1368# ifdef WIN32
1369 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1370
1371 if (nfiles != 0)
1372 {
1373 llbug (message ("Files unclosed: %d", nfiles));
1374 }
1375# endif
1376 }
1377
28bf4b0b 1378 DPRINTF (("Initializing..."));
1379
616915dd 1380 exprNode_initMod ();
1381
28bf4b0b 1382 DPRINTF (("Okay..."));
1383
616915dd 1384 fileIdList_elements (dercfiles, fid)
1385 {
28bf4b0b 1386 sourceFile = inputStream_create (cstring_copy (fileName (fid)), C_EXTENSION, TRUE);
616915dd 1387 context_setFileId (fid);
1388
1389 /* Open source file */
1390
28bf4b0b 1391 if (inputStream_isUndefined (sourceFile) || (!inputStream_open (sourceFile)))
616915dd 1392 {
1393 /* previously, this was ignored ?! */
1394 llbug (message ("Could not open temp file: %s", fileName (fid)));
1395 }
1396 else
1397 {
28bf4b0b 1398 yyin = inputStream_getFile (sourceFile); /*< shared <- only */
616915dd 1399
1400 llassert (yyin != NULL);
1401
1402 if (context_getFlag (FLG_SHOWSCAN))
1403 {
53a89507 1404 lldiagmsg (message ("< checking %q >", osd_outputPath (rootFileName (fid))));
616915dd 1405 }
1406
1407 /*
1408 ** Every time, except the first time, through the loop,
1409 ** need to call yyrestart to clean up the parse buffer.
1410 */
1411
1412 if (!first_time)
1413 {
1414 (void) yyrestart (yyin);
1415 }
1416 else
1417 {
1418 first_time = FALSE;
1419 }
1420
28bf4b0b 1421 DPRINTF (("Entering..."));
616915dd 1422 context_enterFile ();
1423 (void) yyparse ();
28bf4b0b 1424 context_exitCFile ();
616915dd 1425
28bf4b0b 1426 (void) inputStream_close (sourceFile);
1427 }
616915dd 1428 } end_fileIdList_elements;
1429
1430 cptime = clock ();
1431
1432 /* process any leftover macros */
1433
1434 context_processAllMacros ();
1435
1436 /* check everything that was specified was defined */
1437
1438 /* don't check if no c files were processed ?
1439 ** is this correct behaviour?
1440 */
1441
1442 if (context_getFlag (FLG_SHOWSCAN))
1443 {
1444 lldiagmsg (cstring_makeLiteral ("< global checks >"));
1445 }
1446
1447 cleanupMessages ();
1448
1449 if (context_getLinesProcessed () > 0)
1450 {
1451 usymtab_allDefined ();
1452 }
1453
1454 if (context_maybeSet (FLG_TOPUNUSED))
1455 {
1456 uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main"));
1457
1458 if (uentry_isValid (ue))
1459 {
1460 uentry_setUsed (ue, fileloc_observeBuiltin ());
1461 }
1462
1463 usymtab_allUsed ();
1464 }
1465
1466 if (context_maybeSet (FLG_EXPORTLOCAL))
1467 {
1468 usymtab_exportLocal ();
1469 }
1470
1471
1472 if (context_maybeSet (FLG_EXPORTHEADER))
1473 {
1474 usymtab_exportHeader ();
1475 }
1476
1477 if (context_getFlag (FLG_SHOWUSES))
1478 {
1479 usymtab_displayAllUses ();
1480 }
1481
1482 context_checkSuppressCounts ();
1483
1484 if (context_doDump ())
1485 {
1486 cstring dump = context_getDump ();
1487
1488 dumpState (dump);
1489 }
1490
1491# ifdef DOANNOTS
1492 printAnnots ();
1493# endif
1494
1495 cleanupFiles ();
1496
1497 if (context_getFlag (FLG_SHOWSUMMARY))
1498 {
1499 summarizeErrors ();
1500 }
1501
1502
1503 {
1504 bool isQuiet = context_getFlag (FLG_QUIET);
1505 cstring specErrors = cstring_undefined;
1506# ifndef NOLCL
1507 int nspecErrors = lclNumberErrors ();
1508# endif
1509
1510 expsuccess = TRUE;
1511
1512 if (context_neednl ())
1513 fprintf (g_msgstream, "\n");
1514
1515# ifndef NOLCL
1516 if (nspecErrors > 0)
1517 {
1518 if (nspecErrors == context_getLCLExpect ())
1519 {
1520 specErrors =
11db3170 1521 message ("%d spec warning%&, as expected\n ",
616915dd 1522 nspecErrors);
1523 }
1524 else
1525 {
1526 if (context_getLCLExpect () > 0)
1527 {
1528 specErrors =
11db3170 1529 message ("%d spec warning%&, expected %d\n ",
616915dd 1530 nspecErrors,
1531 (int) context_getLCLExpect ());
1532 }
1533 else
1534 {
11db3170 1535 specErrors = message ("%d spec warning%& found\n ",
616915dd 1536 nspecErrors);
1537 expsuccess = FALSE;
1538 }
1539 }
1540 }
1541 else
1542 {
1543 if (context_getLCLExpect () > 0)
1544 {
11db3170 1545 specErrors = message ("No spec warnings, expected %d\n ",
616915dd 1546 (int) context_getLCLExpect ());
1547 expsuccess = FALSE;
1548 }
1549 }
1550# endif
1551
1552 if (context_anyErrors ())
1553 {
1554 if (context_numErrors () == context_getExpect ())
1555 {
1556 if (!isQuiet) {
11db3170 1557 llmsg (message ("Finished checking --- "
1558 "%s%d code warning%&, as expected",
616915dd 1559 specErrors, context_numErrors ()));
1560 }
1561 }
1562 else
1563 {
1564 if (context_getExpect () > 0)
1565 {
1566 if (!isQuiet) {
1567 llmsg (message
11db3170 1568 ("Finished checking --- "
1569 "%s%d code warning%&, expected %d",
616915dd 1570 specErrors, context_numErrors (),
1571 (int) context_getExpect ()));
1572 }
1573
1574 expsuccess = FALSE;
1575 }
1576 else
1577 {
1578
28bf4b0b 1579 if (!isQuiet)
1580 {
11db3170 1581 llmsg (message ("Finished checking --- "
1582 "%s%d code warning%& found",
28bf4b0b 1583 specErrors, context_numErrors ()));
1584 }
616915dd 1585
1586 expsuccess = FALSE;
1587 }
1588 }
1589 }
1590 else
1591 {
1592 if (context_getExpect () > 0)
1593 {
1594 if (!isQuiet) {
1595 llmsg (message
11db3170 1596 ("Finished checking --- "
1597 "%sno code warnings, expected %d",
616915dd 1598 specErrors,
1599 (int) context_getExpect ()));
1600 }
1601
1602 expsuccess = FALSE;
1603 }
1604 else
1605 {
1606 if (context_getLinesProcessed () > 0)
1607 {
11db3170 1608 if (cstring_isEmpty (specErrors))
1609 {
1610 if (!isQuiet)
1611 {
1612 llmsg (message ("Finished checking --- no warnings"));
1613 }
1614 }
1615 else
146e25eb 1616 {
11db3170 1617 if (!isQuiet)
1618 {
1619 llmsg (message ("Finished checking --- %sno code warnings",
1620 specErrors));
1621 }
146e25eb 1622 }
616915dd 1623 }
1624 else
1625 {
1626 if (!isQuiet) {
11db3170 1627 llmsg (message ("Finished checking --- %sno code processed",
616915dd 1628 specErrors));
1629 }
1630 }
1631 }
1632 }
1633
1634 cstring_free (specErrors);
1635 }
1636
1637 if (context_getFlag (FLG_STATS))
1638 {
1639 clock_t ttime = clock () - before;
1640 int specLines = context_getSpecLinesProcessed ();
1641
1642 rstime = clock ();
1643
1644 if (specLines > 0)
1645 {
1646 fprintf (g_msgstream, "%d spec, ", specLines);
1647 }
1648
1649# ifndef CLOCKS_PER_SEC
1650 fprintf (g_msgstream, "%d source lines in %ld time steps (steps/sec unknown)\n",
1651 context_getLinesProcessed (),
1652 (long) ttime);
1653# else
1654 fprintf (g_msgstream, "%d source lines in %.2f s.\n",
1655 context_getLinesProcessed (),
1656 (double) ttime / CLOCKS_PER_SEC);
1657# endif
1658 }
1659 else
1660 {
1661 rstime = clock ();
1662 }
1663
1664 if (context_getFlag (FLG_TIMEDIST))
1665 {
1666 clock_t ttime = clock () - before;
1667
1668 if (ttime > 0)
1669 {
1670 char *msg = (char *) dmalloc (256 * sizeof (*msg));
1671
1672 if (anylcl)
1673 {
1674 sprintf (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));
1682 }
1683 else
1684 {
1685 sprintf (msg,
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));
1692 }
1693
1694 llgenindentmsgnoloc (cstring_fromCharsO (msg));
1695 }
1696 }
1697
1698 llexit (expsuccess ? LLSUCCESS : LLFAILURE);
8250fa4a 1699 BADBRANCHRET (LLFAILURE);
616915dd 1700}
1701
28bf4b0b 1702# ifdef WIN32
616915dd 1703/*
1704** Reenable return value warnings.
1705*/
28bf4b0b 1706# pragma warning (default:4035)
1707# endif
616915dd 1708
1709void
1710showHelp (void)
1711{
1712 showHerald ();
1713
28bf4b0b 1714 llmsg (message ("Source files are .c, .h and %s files. If there is no suffix,",
1715 LCL_EXTENSION));
11db3170 1716 llmsg (message (" Splint will look for <file>.c and <file>%s.", LCL_EXTENSION));
616915dd 1717 llmsglit ("");
11db3170 1718 llmsglit ("Use splint -help <topic or flag name> for more information");
616915dd 1719 llmsglit ("");
1720 llmsglit ("Topics:");
1721 llmsglit ("");
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)");
1736 llmsglit ("");
1737}
1738
1739static bool
1740specialFlagsHelp (char *next)
1741{
1742 if ((next != NULL) && (*next != '-') && (*next != '+'))
1743 {
1744 if (mstring_equal (next, "alpha"))
1745 {
1746 printAlphaFlags ();
1747 return TRUE;
1748 }
1749 else if (mstring_equal (next, "all"))
1750 {
1751 printAllFlags (TRUE, FALSE);
1752 return TRUE;
1753 }
1754 else if (mstring_equal (next, "categories")
1755 || mstring_equal (next, "cats"))
1756 {
1757 listAllCategories ();
1758 return TRUE;
1759 }
1760 else if (mstring_equal (next, "full"))
1761 {
1762 printAllFlags (FALSE, TRUE);
1763 return TRUE;
1764 }
1765 else
1766 {
1767 return FALSE;
1768 }
1769 }
1770 else
1771 {
1772 return FALSE;
1773 }
1774}
1775
1776void
1777printParseErrors (void)
1778{
1779 llmsglit ("Parse Errors");
1780 llmsglit ("------------");
1781 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.");
1786 llmsglit ("");
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. ");
1791 llmsglit ("");
11db3170 1792 llmsglit ("Splint supports some of the GNU (gcc) compiler extensions, "
616915dd 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");
1796 llmsglit ("");
3e3ec469 1797 llmsglit (" # ifndef S_SPLINT_S");
616915dd 1798 llmsglit (" ...");
1799 llmsglit (" # endif");
1800 llmsglit ("");
28bf4b0b 1801 /* evans 2000-12-21 fixed typo reported by Jeroen Ruigrok/Asmodai */
616915dd 1802 llmsglit ("Missing type definitions --- an undefined type name will usually "
28bf4b0b 1803 "lead to a parse error. This often occurs when a standard header "
616915dd 1804 "file defines some type that is not part of the standard library. ");
11db3170 1805 llmsglit ("By default, Splint does not process the local files corresponding "
616915dd 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.");
1811 llmsglit ("");
1812 llmsglit ("If the parse error is inside a posix standard header file, the "
11db3170 1813 "first thing to try is +posixlib. This makes Splint use "
616915dd 1814 "the posix library specification instead of reading the posix "
1815 "header files.");
1816 llmsglit ("");
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: ");
1827 llmsglit ("");
1828 llmsglit (" /*@-skipposixheaders@*/");
1829 llmsglit (" # include <sys/types.h>");
1830 llmsglit (" /*@=skipposixheaders@*/");
1831 llmsglit (" # include <sys/local.h>");
1832 llmsglit ("");
11db3170 1833 llmsglit ("to force Splint to process <sys/types.h>.");
616915dd 1834 llmsglit ("");
11db3170 1835 llmsglit ("At last resort, +trytorecover can be used to make Splint attempt "
616915dd 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.");
1839}
1840
1841void
1842printAnnotations (void)
1843{
1844 llmsglit ("Annotations");
1845 llmsglit ("-----------");
1846 llmsglit ("");
28bf4b0b 1847 llmsglit ("Annotations are semantic comments that document certain "
616915dd 1848 "assumptions about functions, variables, parameters, and types. ");
1849 llmsglit ("");
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.");
1856 llmsglit ("");
1857 llmsglit ("Annotations are introduced by \"/*@\". The role of the @ may be "
1858 "played by any printable character, selected using -commentchar <char>.");
1859 llmsglit ("");
1860 llmsglit ("Consult the User's Guide for descriptions of checking associated with each annotation.");
1861 llmsglit ("");
1862 llmsglit ("Globals: (in function declarations)");
1863 llmsglit (" /*@globals <globitem>,+ @*/");
1864 llmsglit (" globitem is an identifier, internalState or fileSystem");
1865 llmsglit ("");
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.)");
1871 llmsglit ("");
1872 llmsglit ("Iterators:");
1873 llmsglit (" /*@iter <identifier> (<parameter-type-list>) @*/ - declare an iterator");
1874 llmsglit ("");
1875 llmsglit ("Constants:");
1876 llmsglit (" /*@constant <declaration> @*/ - declares a constant");
1877 llmsglit ("");
1878 llmsglit ("Alternate Types:");
1879 llmsglit (" /*@alt <basic-type>,+ @*/");
1880 llmsglit (" (e.g., int /*@alt char@*/ is a type matching either int or char)");
1881 llmsglit ("");
1882 llmsglit ("Declarator Annotations");
1883 llmsglit ("");
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");
1890 llmsglit ("");
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");
1896 llmsglit ("");
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");
1905 llmsglit ("");
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");
1909 llmsglit ("");
1910 llmsglit ("Exposure:");
1911 llmsglit (" /*@observer@*/ - reference that cannot be modified");
1912 llmsglit (" /*@exposed@*/ - exposed reference to storage in another object");
1913 llmsglit ("");
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");
1919 llmsglit ("");
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");
1923 llmsglit ("");
1924 llmsglit ("Null State:");
1925 llmsglit (" /*@null@*/ - possibly null pointer");
1926 llmsglit (" /*@notnull@*/ - non-null pointer");
1927 llmsglit (" /*@relnull@*/ - relax null checking");
1928 llmsglit ("");
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");
1932 llmsglit ("");
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");
1939 llmsglit ("");
1940 llmsglit ("Side-Effects:");
1941 llmsglit (" /*@sef@*/ - corresponding actual parameter has no side effects");
1942 llmsglit ("");
1943 llmsglit ("Declaration:");
1944 llmsglit (" /*@unused@*/ - need not be used (no unused errors reported)");
1945 llmsglit (" /*@external@*/ - defined externally (no undefined error reported)");
1946 llmsglit ("");
1947 llmsglit ("Case:");
1948 llmsglit (" /*@fallthrough@*/ - fall-through case");
1949 llmsglit ("");
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");
1955 llmsglit ("");
1956 llmsglit ("Unreachable Code:");
1957 llmsglit (" /*@notreached@*/ - statement may be unreachable.");
1958 llmsglit ("");
1959 llmsglit ("Special Functions:");
1960 llmsglit (" /*@printflike@*/ - check variable arguments like printf");
1961 llmsglit (" /*@scanflike@*/ - check variable arguments like scanf");
1962}
1963
1964void
1965printComments (void)
1966{
1967 llmsglit ("Control Comments");
1968 llmsglit ("----------------");
1969 llmsglit ("");
1970 llmsglit ("Setting Flags");
1971 llmsglit ("");
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.");
1973 llmsglit ("");
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).");
1977 llmsglit ("");
1978 llmsglit ("Error Suppression");
1979 llmsglit ("");
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.");
1981 llmsglit ("");
1982 llmsglit ("/*@ignore@*/ ... /*@end@*/");
1983 llgenindentmsgnoloc
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@*/");
1987 llgenindentmsgnoloc
1988 (cstring_makeLiteral
1989 ("No errors will be reported from an /*@i@*/ comment to the end of the line."));
1990 llmsglit ("/*@i<n>@*/");
1991 llgenindentmsgnoloc
1992 (cstring_makeLiteral
11db3170 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."));
616915dd 1994 llmsglit ("/*@t@*/, /*@t<n>@*/");
1995 llgenindentmsgnoloc
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."));
1998 llmsglit ("");
1999 llmsglit ("Type Access");
2000 llmsglit ("");
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>");
2005 llmsglit ("");
2006 llmsglit ("Macro Expansion");
2007 llmsglit ("");
2008 llmsglit ("/*@notfunction@*/");
2009 llgenindentmsgnoloc
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."));
2014}
2015
2016
2017void
2018printFlags (void)
2019{
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");
2026}
2027
2028void
2029printMaintainer (void)
2030{
2031 llmsg (message ("Maintainer: %s", cstring_makeLiteralTemp (LCLINT_MAINTAINER)));
2032 llmsglit (LCL_COMPILE);
2033}
2034
2035void
2036printMail (void)
2037{
2038 llmsglit ("Mailing Lists");
2039 llmsglit ("-------------");
2040 llmsglit ("");
11db3170 2041 llmsglit ("There are two mailing lists associated with Splint: ");
616915dd 2042 llmsglit ("");
2043 llmsglit (" lclint-announce@virginia.edu");
2044 llmsglit ("");
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");
2048 llmsglit ("");
2049 llmsglit (" lclint-interest@virginia.edu");
2050 llmsglit ("");
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");
2054}
2055
2056void
2057printReferences (void)
2058{
2059 llmsglit ("References");
2060 llmsglit ("----------");
2061 llmsglit ("");
11db3170 2062 llmsglit ("For more information, see the Splint web site: http://www.splint.org");
616915dd 2063}
2064
2065void
2066describePrefixCodes (void)
2067{
2068 llmsglit ("Prefix Codes");
2069 llmsglit ("------------");
2070 llmsglit ("");
2071 llmsglit ("These characters have special meaning in name prefixes:");
2072 llmsglit ("");
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");
2082}
2083
2084void
2085describeVars (void)
2086{
2087 cstring eval;
28bf4b0b 2088 cstring def;
616915dd 2089
2090 eval = context_getLarchPath ();
2091 def = osd_getEnvironmentVariable (LARCH_PATH);
2092
28bf4b0b 2093 if (cstring_isDefined (def) ||
616915dd 2094 !cstring_equal (eval, cstring_fromChars (DEFAULT_LARCHPATH)))
2095 {
2096 llmsg (message ("LARCH_PATH = %s", eval));
2097 }
2098 else
2099 {
2100 llmsg (message ("LARCH_PATH = <not set> (default = %s)",
2101 cstring_fromChars (DEFAULT_LARCHPATH)));
2102 }
2103
2104 llmsglit (" --- path used to find larch initialization files and LSL traits");
2105
2106 eval = context_getLCLImportDir ();
28bf4b0b 2107 def = osd_getEnvironmentVariable (cstring_makeLiteralTemp (LCLIMPORTDIR));
616915dd 2108
28bf4b0b 2109 if (cstring_isDefined (def) ||
616915dd 2110 !cstring_equal (eval, cstring_fromChars (DEFAULT_LCLIMPORTDIR)))
2111 {
2112 llmsg (message ("%q = %s", cstring_makeLiteral (LCLIMPORTDIR), eval));
2113 }
2114 else
2115 {
2116 llmsg (message ("%s = <not set, default: %s>", cstring_makeLiteralTemp (LCLIMPORTDIR),
2117 cstring_makeLiteralTemp (DEFAULT_LCLIMPORTDIR)));
2118 }
2119
2120 llmsglit (" --- directory containing lcl standard library files "
2121 "(import with < ... >)");;
2122
7272a1c1 2123 llmsg (message
2124 ("include path = %q (set by environment variable %s and -I flags)",
2125 cppReader_getIncludePath (), INCLUDEPATH_VAR));
616915dd 2126
7272a1c1 2127 llmsglit (" --- path used to find #include'd files");
2128
2129 llmsg (message
68de3f33 2130 ("systemdirs = %s (set by -systemdirs or environment variable %s)", /*@i413223@*/
7272a1c1 2131 context_getString (FLG_SYSTEMDIRS),
2132 INCLUDEPATH_VAR));
2133
2134 llmsglit (" --- if file is found on this path, it is treated as a system file for error reporting");
616915dd 2135}
2136
2137void
2138interrupt (int i)
2139{
2140 switch (i)
2141 {
2142 case SIGINT:
2143 fprintf (stderr, "*** Interrupt\n");
2144 llexit (LLINTERRUPT);
2145 case SIGSEGV:
2146 {
2147 cstring loc;
2148
2149 /* Cheat when there are parse errors */
2150 checkParseError ();
2151
2152 fprintf (stderr, "*** Segmentation Violation\n");
2153
2154 /* Don't catch it if fileloc_unparse causes a signal */
2155 (void) signal (SIGSEGV, NULL);
2156
2157 loc = fileloc_unparse (g_currentloc);
2158
2159 fprintf (stderr, "*** Location (not trusted): %s\n",
2160 cstring_toCharsSafe (loc));
2161 cstring_free (loc);
2162 printCodePoint ();
2163 fprintf (stderr, "*** Please report bug to %s\n", LCLINT_MAINTAINER);
2164 exit (LLGIVEUP);
2165 }
2166 default:
2167 fprintf (stderr, "*** Signal: %d\n", i);
2168 /*@-mustfree@*/
2169 fprintf (stderr, "*** Location (not trusted): %s\n",
2170 cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
2171 /*@=mustfree@*/
2172 printCodePoint ();
2173 fprintf (stderr, "*** Please report bug to %s ***\n", LCLINT_MAINTAINER);
2174 exit (LLGIVEUP);
2175 }
2176}
2177
2178void
2179cleanupFiles (void)
2180{
2181 static bool doneCleanup = FALSE;
2182
2183 /* make sure this is only called once! */
2184
2185 if (doneCleanup) return;
2186
2187 setCodePoint ();
2188
dfd82dce 2189 /*
2190 ** Close all open files
2191 ** (There should only be open files, if we exited after a fatal error.)
2192 */
2193
2194 fileTable_closeAll (context_fileTable ());
2195
616915dd 2196 if (context_getFlag (FLG_KEEP))
2197 {
2198 check (fputs ("Temporary files kept:\n", stderr) != EOF);
2199 fileTable_printTemps (context_fileTable ());
2200 }
2201 else
2202 {
2203# ifdef WIN32
2204 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
2205
2206 if (nfiles != 0)
2207 {
2208 llbug (message ("Files unclosed: %d", nfiles));
2209 }
2210# endif
2211 fileTable_cleanup (context_fileTable ());
2212 }
2213
2214 doneCleanup = TRUE;
2215}
2216
2217/*
11db3170 2218** cleans up temp files (if necessary) and exits
616915dd 2219*/
2220
2221/*@exits@*/ void
2222llexit (int status)
2223{
2224 DPRINTF (("llexit: %d", status));
2225
2226# ifdef WIN32
2227 if (status == LLFAILURE)
2228 {
2229 _fcloseall ();
2230 }
2231# endif
2232
2233 cleanupFiles ();
2234
2235 if (status != LLFAILURE)
2236 {
2237 context_destroyMod ();
2238 exprNode_destroyMod ();
2239
2240 sRef_destroyMod ();
2241 uentry_destroyMod ();
2242 typeIdSet_destroyMod ();
2243
2244# ifdef USEDMALLOC
2245 dmalloc_shutdown ();
2246# endif
2247 }
2248
2249 exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
2250}
2251
f2b6724f 2252bool readOptionsFile (cstring fname, cstringSList *passThroughArgs, bool report)
2253{
2254 bool res = FALSE;
2255
2256 if (fileTable_exists (context_fileTable (), fname))
2257 {
2258 if (report)
2259 {
2260 voptgenerror
2261 (FLG_WARNRC,
2262 message ("Multiple attempts to read options file: %s", fname),
2263 g_currentloc);
2264 }
2265 }
2266 else
2267 {
2268 FILE *innerf = fileTable_openFile (context_fileTable (), fname, "r");
2269
2270 if (innerf != NULL)
2271 {
2272 fileloc fc = g_currentloc;
2273 g_currentloc = fileloc_createRc (fname);
2274
2275 if (context_getFlag (FLG_SHOWSCAN))
2276 {
146e25eb 2277 lldiagmsg (message ("< reading options from %q >",
f2b6724f 2278 fileloc_outputFilename (g_currentloc)));
2279 }
2280
2281 loadrc (innerf, passThroughArgs);
2282 fileloc_reallyFree (g_currentloc);
2283 g_currentloc = fc;
2284 res = TRUE;
2285 }
2286 else
2287 {
2288 if (report)
2289 {
2290 voptgenerror
2291 (FLG_WARNRC,
2292 message ("Cannot open options file: %s", fname),
2293 g_currentloc);
2294 }
2295 }
2296 }
2297
2298 return res;
2299}
2300
ee229125 2301/*
2302** This shouldn't be necessary, but Apple Darwin can't handle '"''s.
2303*/
2304
616915dd 2305void
15b3d2b2 2306loadrc (/*:open:*/ FILE *rcfile, cstringSList *passThroughArgs)
146e25eb 2307 /*@modifies rcfile@*/
b9904f57 2308 /*@ensures closed rcfile@*/
616915dd 2309{
2310 char *s = mstring_create (MAX_LINE_LENGTH);
2311 char *os = s;
f2b6724f 2312
616915dd 2313 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2314
2315 s = os;
2316
28bf4b0b 2317 while (reader_readLine (rcfile, s, MAX_LINE_LENGTH) != NULL)
616915dd 2318 {
2319 char c;
2320 bool set = FALSE;
2321 char *thisflag;
2322 flagcode opt;
2323
2324 DPRINTF (("Line: %s", s));
2325 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
616915dd 2326
28bf4b0b 2327 while (*s == ' ' || *s == '\t')
616915dd 2328 {
2329 s++;
2330 incColumn ();
2331 }
2332
2333 while (*s != '\0')
2334 {
2335 bool escaped = FALSE;
2336 bool quoted = FALSE;
2337 c = *s;
2338
2339 DPRINTF (("Process: %s", s));
2340 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2341 /* comment characters */
2342 if (c == '#' || c == ';' || c == '\n')
2343 {
2344 /*@innerbreak@*/
2345 break;
2346 }
2347
2348 if (c == '-' || c == '+')
2349 {
2350 set = (c == '+');
2351 }
2352 else
2353 {
2354 showHerald ();
ccf0a4a8 2355 voptgenerror (FLG_BADFLAG,
2356 message ("Bad flag syntax (+ or - expected, "
2357 "+ is assumed): %s",
2358 cstring_fromChars (s)),
2359 g_currentloc);
616915dd 2360 s--;
2361 set = TRUE;
2362 }
2363
2364 s++;
2365 incColumn ();
2366
2367 thisflag = s;
2368
2369 while ((c = *s) != '\0')
2370 { /* remember to handle spaces and quotes in -D and -U ... */
2371 if (escaped)
2372 {
2373 escaped = FALSE;
2374 }
2375 else if (quoted)
2376 {
2377 if (c == '\\')
2378 {
2379 escaped = TRUE;
2380 }
2381 else if (c == '\"')
2382 {
2383 quoted = FALSE;
2384 }
2385 else
2386 {
2387 ;
2388 }
2389 }
2390 else if (c == '\"')
2391 {
2392 quoted = TRUE;
2393 }
2394 else
2395 {
2396 if (c == ' ' || c == '\t' || c == '\n')
2397 {
2398 /*@innerbreak@*/ break;
2399 }
2400 }
2401
2402 s++;
2403 incColumn ();
2404 }
2405
2406 DPRINTF (("Nulling: %c", *s));
2407 *s = '\0';
2408
2409 if (mstring_isEmpty (thisflag))
2410 {
2411 llfatalerror (message ("Missing flag: %s",
2412 cstring_fromChars (os)));
2413 }
2414
2415 DPRINTF (("Flag: %s", thisflag));
2416
2417 opt = identifyFlag (cstring_fromChars (thisflag));
2418
2419 if (flagcode_isSkip (opt))
2420 {
2421 ;
2422 }
2423 else if (flagcode_isInvalid (opt))
2424 {
28bf4b0b 2425 DPRINTF (("Invalid: %s", thisflag));
2426
616915dd 2427 if (isMode (cstring_fromChars (thisflag)))
2428 {
2429 context_setMode (cstring_fromChars (thisflag));
2430 }
2431 else
2432 {
ccf0a4a8 2433 voptgenerror (FLG_BADFLAG,
2434 message ("Unrecognized option: %s",
2435 cstring_fromChars (thisflag)),
2436 g_currentloc);
616915dd 2437 }
2438 }
2439 else
2440 {
2441 context_userSetFlag (opt, set);
2442
2443 if (flagcode_hasArgument (opt))
2444 {
2445 if (opt == FLG_HELP)
2446 {
2447 showHerald ();
ccf0a4a8 2448 voptgenerror (FLG_BADFLAG,
2449 message ("Cannot use help in rc files"),
2450 g_currentloc);
616915dd 2451 }
2452 else if (flagcode_isPassThrough (opt)) /* -D or -U */
2453 {
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)));
2459 }
2460 else if (opt == FLG_INCLUDEPATH
2461 || opt == FLG_SPECPATH)
2462 {
2463 cstring dir = cstring_suffix (cstring_fromChars (thisflag), 1); /* skip over I/S */
2464
2465 switch (opt)
2466 {
2467 case FLG_INCLUDEPATH:
2468 cppAddIncludeDir (dir);
2469 /*@switchbreak@*/ break;
2470 case FLG_SPECPATH:
2471 /*@-mustfree@*/
2472 g_localSpecPath = cstring_toCharsSafe
2473 (message ("%s:%s", cstring_fromChars (g_localSpecPath), dir));
2474 /*@=mustfree@*/
2475 /*@switchbreak@*/ break;
2476 BADDEFAULT;
2477 }
2478 }
2479 else if (flagcode_hasString (opt)
2480 || flagcode_hasValue (opt)
2481 || opt == FLG_INIT || opt == FLG_OPTF)
2482 {
2483 cstring extra = cstring_undefined;
2484 char *rest, *orest;
2485 char rchar;
2486
2487 *s = c;
2488 rest = mstring_copy (s);
2489 DPRINTF (("Here: rest = %s", rest));
2490 orest = rest;
2491 *s = '\0';
2492
2493 while ((rchar = *rest) != '\0'
2494 && (isspace ((int) rchar)))
2495 {
2496 rest++;
2497 s++;
2498 }
2499
2500 DPRINTF (("Yo: %s", rest));
2501
2502 while ((rchar = *rest) != '\0'
2503 && !isspace ((int) rchar))
2504 {
2505 extra = cstring_appendChar (extra, rchar);
2506 rest++;
2507 s++;
2508 }
2509
2510 DPRINTF (("Yo: %s", extra));
2511 sfree (orest);
2512
2513 if (cstring_isUndefined (extra))
2514 {
2515 showHerald ();
ccf0a4a8 2516 voptgenerror
616915dd 2517 (FLG_BADFLAG,
2518 message
2519 ("Flag %s must be followed by an argument",
ccf0a4a8 2520 flagcode_unparse (opt)),
2521 g_currentloc);
616915dd 2522 }
2523 else
2524 {
2525 s--;
2526
2527 DPRINTF (("Here we are: %s", extra));
2528
2529 if (flagcode_hasValue (opt))
2530 {
2531 DPRINTF (("Set value flag: %s", extra));
2532 setValueFlag (opt, extra);
616915dd 2533 }
2534 else if (opt == FLG_OPTF)
2535 {
f2b6724f 2536 (void) readOptionsFile (extra, passThroughArgs, TRUE);
616915dd 2537 }
2538 else if (opt == FLG_INIT)
2539 {
2540# ifndef NOLCL
28bf4b0b 2541 llassert (inputStream_isUndefined (initFile));
616915dd 2542
28bf4b0b 2543 initFile = inputStream_create
146e25eb 2544 (cstring_copy (extra),
28bf4b0b 2545 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
2546 FALSE);
616915dd 2547# endif
2548 }
2549 else if (flagcode_hasString (opt))
2550 {
146e25eb 2551 DPRINTF (("Here: %s", extra));
2552
2553 /*
2554 ** If it has "'s, we need to remove them.
2555 */
2556
ee229125 2557 if (cstring_firstChar (extra) == '\"')
616915dd 2558 {
ee229125 2559 if (cstring_lastChar (extra) == '\"')
616915dd 2560 {
146e25eb 2561 cstring unquoted = cstring_copyLength
2562 (cstring_toCharsSafe (cstring_suffix (extra, 1)),
2563 cstring_length (extra) - 2);
2564
2565 DPRINTF (("string flag: %s -> %s", extra, unquoted));
2566 setStringFlag (opt, unquoted);
2567 cstring_free (extra);
616915dd 2568 }
2569 else
2570 {
ccf0a4a8 2571 voptgenerror
2572 (FLG_BADFLAG,
616915dd 2573 message ("Unmatched \" in option string: %s",
ccf0a4a8 2574 extra),
2575 g_currentloc);
146e25eb 2576 setStringFlag (opt, extra);
616915dd 2577 }
2578 }
146e25eb 2579 else
2580 {
2581 DPRINTF (("No quotes: %s", extra));
2582 setStringFlag (opt, extra);
2583 }
2584
2585 extra = cstring_undefined;
616915dd 2586 }
2587 else
2588 {
616915dd 2589 BADEXIT;
2590 }
2591 }
146e25eb 2592
2593 cstring_free (extra);
616915dd 2594 }
2595 else
2596 {
2597 BADEXIT;
2598 }
2599 }
2600 }
2601
2602 *s = c;
2603 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2604 while ((c == ' ') || (c == '\t'))
2605 {
2606 c = *(++s);
2607 incColumn ();
2608 }
2609 }
2610 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2611 s = os;
2612 }
2613
2614 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2615 sfree (os);
dfd82dce 2616 check (fileTable_closeFile (context_fileTable (), rcfile));
616915dd 2617}
2618
28bf4b0b 2619static fileIdList preprocessFiles (fileIdList fl, bool xhfiles)
616915dd 2620 /*@modifies fileSystem@*/
2621{
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 ();
2626
2627 fileloc_free (g_currentloc);
2628 g_currentloc = fileloc_createBuiltin ();
2629
2630 fileIdList_elements (fl, fid)
2631 {
28bf4b0b 2632 cstring ppfname = fileName (fid);
616915dd 2633
53a89507 2634 if (!(osd_fileIsReadable (ppfname)))
616915dd 2635 {
146e25eb 2636 lldiagmsg (message ("Cannot open file: %q", osd_outputPath (ppfname)));
53a89507 2637 ppfname = cstring_undefined;
28bf4b0b 2638 }
2639
2640 if (cstring_isDefined (ppfname))
2641 {
2642 fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
53a89507 2643
2644 if (xhfiles)
2645 {
2646 llassert (fileTable_isXHFile (context_fileTable (), dfile));
2647 }
2648
28bf4b0b 2649 llassert (cstring_isNonEmpty (ppfname));
616915dd 2650
2651 if (msg)
2652 {
2653 if ((filesprocessed % skip) == 0)
2654 {
2655 if (filesprocessed == 0) {
2656 fprintf (stderr, " ");
2657 }
2658 else {
2659 fprintf (stderr, ".");
2660 }
2661
2662 (void) fflush (stderr);
2663 }
2664 filesprocessed++;
2665 }
2666
28bf4b0b 2667 if (cppProcess (ppfname, fileName (dfile)) != 0)
616915dd 2668 {
2669 llfatalerror (message ("Preprocessing error for file: %s",
2670 rootFileName (fid)));
2671 }
2672
2673 fileIdList_add (dfiles, dfile);
2674 }
2675 } end_fileIdList_elements;
2676
2677 return dfiles;
2678}
28bf4b0b 2679
2680/* This should be in an lclUtils.c file... */
2681# ifndef NOLCL
2682char *specFullName (char *specfile, /*@out@*/ char **inpath)
2683{
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)));
2689 size_t size;
2690 long int i, j;
2691
2692 /* initialized path to empty string or may have accidental garbage */
2693 *path = '\0';
2694
2695 /*@-mayaliasunique@*/
2696 strcpy (specname, specfile);
2697 /*@=mayaliasunique@*/
2698
2699 /* trim off pathnames in specfile */
2700 size = strlen (specname);
2701
2702 for (i = size_toInt (size) - 1; i >= 0; i--)
2703 {
2704 if (specname[i] == CONNECTCHAR)
2705 {
2706 /* strcpy (specname, (char *)specname+i+1); */
2707 for (j = 0; j <= i; j++) /* include '/' */
2708 {
2709 path[j] = specname[j];
2710 }
2711
2712 path[i + 1] = '\0';
2713 specname += i + 1;
2714 break;
2715 }
2716 }
2717
2718 /*
2719 ** also remove .lcl file extension, assume it's the last extension
2720 ** of the file name
2721 */
2722
2723 size = strlen (specname);
2724
2725 for (i = size_toInt (size) - 1; i >= 0; i--)
2726 {
2727 if (specname[i] == '.')
2728 {
2729 specname[i] = '\0';
2730 break;
2731 }
2732 }
2733
2734 *inpath = path;
2735
2736 /*
2737 ** If specname no longer points to the original char,
2738 ** we need to allocate a new pointer and copy the string.
2739 */
2740
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! */
2744 sfree (ospecname);
2745 return rspecname;
2746 }
2747
2748 return specname;
2749}
2750# endif
This page took 0.591622 seconds and 5 git commands to generate.