]> andersk Git - splint.git/blame - src/llmain.c
Fixed loading of rc files, warnrc and showscan.
[splint.git] / src / llmain.c
CommitLineData
616915dd 1/*
11db3170 2** Splint - annotation-assisted static program checker
28bf4b0b 3** Copyright (C) 1994-2001 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)
f2b6724f 100 /*@modifies *p_passThroughArgs@*/
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 FILE *rcfile;
777 bool defaultf = TRUE;
778 bool nof = FALSE;
779
780 for (i = 1; i < argc; i++)
781 {
782 char *thisarg;
783 thisarg = argv[i];
784
785 if (*thisarg == '-' || *thisarg == '+')
786 {
f2b6724f 787 bool set = (*thisarg == '+');
788 flagcode opt;
789
616915dd 790 thisarg++;
f2b6724f 791 opt = identifyFlag (cstring_fromChars (thisarg));
616915dd 792
f2b6724f 793 if (opt == FLG_NOF)
616915dd 794 {
795 nof = TRUE;
796 }
f2b6724f 797 else if (opt == FLG_SHOWSCAN || opt == FLG_WARNRC)
798 {
799 /*
800 ** Need to set it immediately, so rc file scan is displayed
801 */
802
803 context_userSetFlag (opt, set);
804 }
805 else if (opt == FLG_OPTF)
616915dd 806 {
807 if (++i < argc)
808 {
809 defaultf = FALSE;
60868d40 810 fname = cstring_fromChars (argv[i]);
f2b6724f 811 readOptionsFile (fname, &passThroughArgs, TRUE);
616915dd 812 }
813 else
814 llfatalerror
815 (cstring_makeLiteral ("Flag f to select options file "
816 "requires an argument"));
817 }
818 else
819 {
820 ; /* wait to process later */
821 }
822 }
823 }
f2b6724f 824
616915dd 825 setCodePoint ();
826
827 if (!nof && defaultf)
828 {
60868d40 829 /*
f2b6724f 830 ** No explicit rc file, first try reading ~/.splintrc
60868d40 831 */
616915dd 832
f2b6724f 833 if (cstring_isUndefined (fname))
60868d40 834 {
f2b6724f 835 if (!cstring_isEmpty (home))
60868d40 836 {
f2b6724f 837 bool readhomerc, readaltrc;
838 cstring homename, altname;
839
840 homename = message ("%s%h%s", home, CONNECTCHAR,
841 cstring_fromChars (RCFILE));
842 readhomerc = readOptionsFile (homename, &passThroughArgs, FALSE);
60868d40 843
f2b6724f 844 /*
845 ** Try ~/.lclintrc also for historical accuracy
846 */
847
848 altname = message ("%s%h%s", home, CONNECTCHAR,
849 cstring_fromChars (ALTRCFILE));
850 readaltrc = readOptionsFile (altname, &passThroughArgs, FALSE);
851
852 if (readhomerc && readaltrc)
853 {
854
855 voptgenerror
856 (FLG_WARNRC,
857 message ("Found both %s and %s files. Using both files, "
858 "but recommend using only %s to avoid confusion.",
859 homename, altname, homename),
860 g_currentloc);
861 }
60868d40 862 }
863 }
864
f2b6724f 865 /*
866 ** Next, read .splintrc in the current working directory
867 */
868
869 {
870 cstring rcname = message ("%s%s",osd_getCurrentDirectory (), cstring_fromChars (RCFILE));
871 cstring altname = message ("%s%s",osd_getCurrentDirectory (), cstring_fromChars (ALTRCFILE));
872 bool readrc, readaltrc;
873
874 readrc = readOptionsFile (rcname, &passThroughArgs, FALSE);
875 readaltrc = readOptionsFile (altname, &passThroughArgs, FALSE);
876
877 if (readrc && readaltrc)
878 {
879 voptgenerror (FLG_WARNRC,
880 message ("Found both %s and %s files. Using both files, "
881 "but recommend using only %s to avoid confusion.",
882 rcname, altname, rcname),
883 g_currentloc);
884
885 }
616915dd 886
f2b6724f 887 cstring_free (rcname);
888 cstring_free (altname);
889 }
616915dd 890 }
891 }
892
893 setCodePoint ();
894
895 for (i = 1; i < argc; i++)
896 {
897 char *thisarg;
898 flagcode opt;
899
900 thisarg = argv[i];
901
902 if (showhelp)
903 {
904 if (allhelp)
905 {
906 showHerald ();
907 }
908
909 allhelp = FALSE;
910
911 if (*thisarg == '-' || *thisarg == '+')
912 {
913 thisarg++; /* skip '-' */
914 }
915 if (mstring_equal (thisarg, "modes"))
916 {
917 llmsg (describeModes ());
918 }
919 else if (mstring_equal (thisarg, "vars")
920 || mstring_equal (thisarg, "env"))
921 {
922 describeVars ();
923 }
924 else if (mstring_equal (thisarg, "annotations"))
925 {
926 printAnnotations ();
927 }
928 else if (mstring_equal (thisarg, "parseerrors"))
929 {
930 printParseErrors ();
931 }
932 else if (mstring_equal (thisarg, "comments"))
933 {
934 printComments ();
935 }
936 else if (mstring_equal (thisarg, "prefixcodes"))
937 {
938 describePrefixCodes ();
939 }
940 else if (mstring_equal (thisarg, "references")
941 || mstring_equal (thisarg, "refs"))
942 {
943 printReferences ();
944 }
945 else if (mstring_equal (thisarg, "mail"))
946 {
947 printMail ();
948 }
949 else if (mstring_equal (thisarg, "maintainer")
950 || mstring_equal (thisarg, "version"))
951 {
952 printMaintainer ();
953 }
954 else if (mstring_equal (thisarg, "flags"))
955 {
956 if (i + 1 < argc)
957 {
958 char *next = argv[i + 1];
959
960 if (specialFlagsHelp (next))
961 {
962 i++;
963 }
964 else
965 {
966 flagkind k = identifyCategory (cstring_fromChars (next));
967
968 if (k != FK_NONE)
969 {
970 printCategory (k);
971 i++;
972 }
973 }
974 }
975 else
976 {
977 printFlags ();
978 }
979 }
980 else
981 {
982 cstring s = describeFlag (cstring_fromChars (thisarg));
983
984 if (cstring_isDefined (s))
985 {
986 llmsg (s);
987 }
988 }
989 }
990 else
991 {
992 if (*thisarg == '-' || *thisarg == '+')
993 {
994 bool set = (*thisarg == '+');
995 cstring flagname;
996
997 thisarg++; /* skip '-' */
998 flagname = cstring_fromChars (thisarg);
28bf4b0b 999
1000 DPRINTF (("Flag: %s", flagname));
616915dd 1001 opt = identifyFlag (flagname);
28bf4b0b 1002 DPRINTF (("Flag: %s", flagcode_unparse (opt)));
1003
f2b6724f 1004 if (flagcode_isSkip (opt) || opt == FLG_SHOWSCAN || opt == FLG_WARNRC)
616915dd 1005 {
f2b6724f 1006 /* showscan already processed */
28bf4b0b 1007 DPRINTF (("Skipping!"));
616915dd 1008 }
1009 else if (flagcode_isInvalid (opt))
1010 {
28bf4b0b 1011 DPRINTF (("Invalid: %s", flagname));
1012
616915dd 1013 if (isMode (flagname))
1014 {
1015 context_setMode (flagname);
1016 }
1017 else
1018 {
28bf4b0b 1019 DPRINTF (("Error!"));
efd360a3 1020 voptgenerror (FLG_BADFLAG,
1021 message ("Unrecognized option: %s",
1022 cstring_fromChars (thisarg)),
1023 g_currentloc);
616915dd 1024 }
1025 }
1026 else
1027 {
1028 context_userSetFlag (opt, set);
1029
1030 if (flagcode_hasArgument (opt))
1031 {
1032 if (opt == FLG_HELP)
1033 {
1034 showhelp = TRUE;
1035 }
1036 else if (flagcode_isPassThrough (opt)) /* -D or -U */
1037 {
1038 passThroughArgs = cstringSList_add
1039 (passThroughArgs, cstring_fromChars (thisarg));
1040 }
1041 else if (flagcode_hasValue (opt))
1042 {
1043 if (++i < argc)
1044 {
1045 setValueFlag (opt, cstring_fromChars (argv[i]));
1046 }
1047 else
1048 {
1049 llfatalerror
1050 (message
1051 ("Flag %s must be followed by a number",
1052 flagcode_unparse (opt)));
1053 }
1054 }
1055 else if (opt == FLG_INCLUDEPATH || opt == FLG_SPECPATH)
1056 {
1057 cstring dir = cstring_suffix (cstring_fromChars (thisarg), 1); /* skip over I */
1058
1059 switch (opt)
1060 {
1061 case FLG_INCLUDEPATH:
1062 cppAddIncludeDir (dir);
1063 /*@switchbreak@*/ break;
1064 case FLG_SPECPATH:
1065 /*@-mustfree@*/
1066 g_localSpecPath = cstring_toCharsSafe
1067 (message ("%s%h%s",
1068 cstring_fromChars (g_localSpecPath),
7272a1c1 1069 PATH_SEPARATOR,
616915dd 1070 dir));
1071 /*@=mustfree@*/
1072 /*@switchbreak@*/ break;
1073 BADDEFAULT;
1074 }
1075 }
1076 else if (flagcode_hasString (opt)
1077 || opt == FLG_INIT || opt == FLG_OPTF)
1078 {
1079 if (++i < argc)
1080 {
1081 cstring arg = cstring_fromChars (argv[i]);
1082
1083 if (opt == FLG_OPTF)
1084 {
1085 ; /* -f already processed */
1086 }
1087 else if (opt == FLG_INIT)
1088 {
1089# ifndef NOLCL
28bf4b0b 1090 initFile = inputStream_create
1091 (arg,
1092 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
1093 FALSE);
616915dd 1094# endif
1095 break;
1096 }
1097 else
1098 {
28bf4b0b 1099 DPRINTF (("String flag: %s / %s",
1100 flagcode_unparse (opt), arg));
1101 if (opt == FLG_MTSFILE)
1102 {
1103 /*
1104 ** arg identifies mts files
1105 */
53a89507 1106 cstring tmp = message ("%s%s", arg, MTS_EXTENSION);
1107 addLarchPathFile (mtfiles, tmp);
1108 cstring_free (tmp);
1109 tmp = message ("%s%s", arg, XH_EXTENSION);
1110 addXHFile (xfiles, tmp);
1111 cstring_free (tmp);
28bf4b0b 1112 }
1113 else
1114 {
1115 setStringFlag (opt, arg);
1116 }
616915dd 1117 }
1118 }
1119 else
1120 {
1121 llfatalerror
1122 (message
1123 ("Flag %s must be followed by a string",
1124 flagcode_unparse (opt)));
1125 }
1126 }
1127 else
1128 {
1129 /* no argument */
1130 }
1131 }
1132 }
1133 }
1134 else /* its a filename */
1135 {
28bf4b0b 1136 DPRINTF (("Adding filename: %s", thisarg));
616915dd 1137 fl = cstringSList_add (fl, cstring_fromChars (thisarg));
1138 }
1139 }
1140 }
1141
1142 setCodePoint ();
f2b6724f 1143 showHerald ();
1144
616915dd 1145 /*
1146 ** create lists of C and LCL files
1147 */
1148
1149 cstringSList_elements (fl, current)
1150 {
28bf4b0b 1151 cstring ext = fileLib_getExtension (current);
1152
1153 if (cstring_isUndefined (ext))
616915dd 1154 {
1155 /* no extension --- both C and LCL with default extensions */
1156
28bf4b0b 1157 addFile (cfiles, message ("%s%s", current, C_EXTENSION));
1158 addFile (lclfiles, message ("%s%s", current, LCL_EXTENSION));
1159 }
1160 else if (cstring_equal (ext, XH_EXTENSION))
1161 {
53a89507 1162 addXHFile (xfiles, current);
28bf4b0b 1163 }
68de3f33 1164 else if (cstring_equal (ext, PP_EXTENSION))
1165 {
1166 if (!context_getFlag (FLG_NOPP))
1167 {
1168 voptgenerror
1169 (FLG_FILEEXTENSIONS,
1170 message ("File extension %s used without +nopp flag (will be processed as C source code): %s",
1171 ext, current),
1172 g_currentloc);
1173 }
1174
1175 addFile (cfiles, cstring_copy (current));
1176 }
28bf4b0b 1177 else if (cstring_equal (ext, LCL_EXTENSION))
1178 {
1179 addFile (lclfiles, cstring_copy (current));
616915dd 1180 }
28bf4b0b 1181 else if (fileLib_isCExtension (ext))
616915dd 1182 {
28bf4b0b 1183 addFile (cfiles, cstring_copy (current));
1184 }
1185 else if (cstring_equal (ext, MTS_EXTENSION))
1186 {
53a89507 1187 addLarchPathFile (mtfiles, current);
616915dd 1188 }
1189 else
1190 {
28bf4b0b 1191 voptgenerror
1192 (FLG_FILEEXTENSIONS,
1193 message ("Unrecognized file extension: %s (assuming %s is C source code)",
1194 current, ext),
1195 g_currentloc);
1196
1197 addFile (cfiles, cstring_copy (current));
616915dd 1198 }
1199 } end_cstringSList_elements;
1200
616915dd 1201 if (showhelp)
1202 {
1203 if (allhelp)
1204 {
1205 showHelp ();
1206 }
1207 fprintf (g_msgstream, "\n");
1208
1209 fileIdList_free (cfiles);
28bf4b0b 1210 fileIdList_free (xfiles);
616915dd 1211 fileIdList_free (lclfiles);
1212
1213 llexit (LLSUCCESS);
1214 }
1215
1216# ifdef DOANNOTS
1217 initAnnots ();
1218# endif
1219
1220 inittime = clock ();
1221
1222 context_resetErrors ();
1223 context_clearInCommandLine ();
1224
1225 anylcl = !fileIdList_isEmpty (lclfiles);
1226
1227 if (context_doMerge ())
1228 {
1229 cstring m = context_getMerge ();
1230
1231 if (context_getFlag (FLG_SHOWSCAN))
1232 {
1233 fprintf (g_msgstream, "< loading %s ", cstring_toCharsSafe (m));
1234 }
1235
1236 loadState (m);
1237
1238 if (context_getFlag (FLG_SHOWSCAN))
1239 {
1240 fprintf (g_msgstream, " >\n");
1241 }
1242
1243 if (!usymtab_existsType (context_getBoolName ()))
1244 {
1245 usymtab_initBool ();
1246 }
1247 }
1248 else
1249 {
1250 if (!context_getFlag (FLG_NOLIB) && loadStandardState ())
1251 {
1252 ;
1253 }
1254 else
1255 {
1256 ctype_initTable ();
1257 }
1258
1259 /* setup bool type and constants */
1260 usymtab_initBool ();
1261 }
1262
1263 fileloc_free (g_currentloc);
1264 g_currentloc = fileloc_createBuiltin ();
1265
28bf4b0b 1266 /*
1267 ** Read metastate files (must happen before loading libraries)
1268 */
1269
1270 fileIdList_elements (mtfiles, mtfile)
1271 {
1272 context_setFileId (mtfile);
1273
1274 if (context_getFlag (FLG_SHOWSCAN))
1275 {
1276 lldiagmsg (message ("< processing %s >", rootFileName (mtfile)));
1277 }
1278
1279 mtreader_readFile (cstring_copy (fileName (mtfile)));
1280 } end_fileIdList_elements;
1281
616915dd 1282 libtime = clock ();
28bf4b0b 1283
616915dd 1284 if (anylcl)
1285 {
1286# ifdef NOLCL
11db3170 1287 llfatalerror (cstring_makeLiteral ("This version of Splint does not handle LCL files."));
616915dd 1288# else
1289 lslProcess (lclfiles);
1290# endif
1291 }
1292
28bf4b0b 1293 usymtab_initGlobalMarker ();
1294
616915dd 1295 /*
1296 ** pre-processing
1297 **
1298 ** call the pre-preprocessor and /lib/cpp to generate appropriate
1299 ** files
1300 **
1301 */
1302
1303 context_setInCommandLine ();
1304
616915dd 1305 DPRINTF (("Pass through: %s", cstringSList_unparse (passThroughArgs)));
1306
1307 cstringSList_elements (passThroughArgs, thisarg) {
1308 handlePassThroughFlag (cstring_toCharsSafe (thisarg));
1309 } end_cstringSList_elements;
1310
1311 cstringSList_free (passThroughArgs);
1312
1313 cleanupMessages ();
1314
28bf4b0b 1315 DPRINTF (("Initializing cpp reader!"));
1316 cppReader_initialize ();
616915dd 1317 cppReader_saveDefinitions ();
1318
1319 context_clearInCommandLine ();
1320
1321 if (!context_getFlag (FLG_NOPP))
1322 {
28bf4b0b 1323 fileIdList tfiles;
1324
616915dd 1325 llflush ();
1326
1327 if (context_getFlag (FLG_SHOWSCAN))
1328 {
1329 fprintf (stderr, "< preprocessing");
1330 }
1331
1332 lcltime = clock ();
1333
1334 context_setPreprocessing ();
28bf4b0b 1335 dercfiles = preprocessFiles (xfiles, TRUE);
1336 tfiles = preprocessFiles (cfiles, FALSE);
1337 dercfiles = fileIdList_append (dercfiles, tfiles);
1338 fileIdList_free (tfiles);
1339
616915dd 1340 context_clearPreprocessing ();
1341
1342 fileIdList_free (cfiles);
1343
1344 if (context_getFlag (FLG_SHOWSCAN))
1345 {
1346 fprintf (stderr, " >\n");
1347 }
1348
1349 pptime = clock ();
1350 }
1351 else
1352 {
1353 lcltime = clock ();
28bf4b0b 1354 dercfiles = fileIdList_append (cfiles, xfiles);
616915dd 1355 pptime = clock ();
1356 }
28bf4b0b 1357
616915dd 1358 /*
1359 ** now, check all the corresponding C files
1360 **
1361 ** (for now these are just <file>.c, but after pre-processing
1362 ** will be <tmpprefix>.<file>.c)
1363 */
1364
1365 {
1366# ifdef WIN32
1367 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1368
1369 if (nfiles != 0)
1370 {
1371 llbug (message ("Files unclosed: %d", nfiles));
1372 }
1373# endif
1374 }
1375
28bf4b0b 1376 DPRINTF (("Initializing..."));
1377
616915dd 1378 exprNode_initMod ();
1379
28bf4b0b 1380 DPRINTF (("Okay..."));
1381
616915dd 1382 fileIdList_elements (dercfiles, fid)
1383 {
28bf4b0b 1384 sourceFile = inputStream_create (cstring_copy (fileName (fid)), C_EXTENSION, TRUE);
616915dd 1385 context_setFileId (fid);
1386
1387 /* Open source file */
1388
28bf4b0b 1389 if (inputStream_isUndefined (sourceFile) || (!inputStream_open (sourceFile)))
616915dd 1390 {
1391 /* previously, this was ignored ?! */
1392 llbug (message ("Could not open temp file: %s", fileName (fid)));
1393 }
1394 else
1395 {
28bf4b0b 1396 yyin = inputStream_getFile (sourceFile); /*< shared <- only */
616915dd 1397
1398 llassert (yyin != NULL);
1399
1400 if (context_getFlag (FLG_SHOWSCAN))
1401 {
53a89507 1402 lldiagmsg (message ("< checking %q >", osd_outputPath (rootFileName (fid))));
616915dd 1403 }
1404
1405 /*
1406 ** Every time, except the first time, through the loop,
1407 ** need to call yyrestart to clean up the parse buffer.
1408 */
1409
1410 if (!first_time)
1411 {
1412 (void) yyrestart (yyin);
1413 }
1414 else
1415 {
1416 first_time = FALSE;
1417 }
1418
28bf4b0b 1419 DPRINTF (("Entering..."));
616915dd 1420 context_enterFile ();
1421 (void) yyparse ();
28bf4b0b 1422 context_exitCFile ();
616915dd 1423
28bf4b0b 1424 (void) inputStream_close (sourceFile);
1425 }
616915dd 1426 } end_fileIdList_elements;
1427
1428 cptime = clock ();
1429
1430 /* process any leftover macros */
1431
1432 context_processAllMacros ();
1433
1434 /* check everything that was specified was defined */
1435
1436 /* don't check if no c files were processed ?
1437 ** is this correct behaviour?
1438 */
1439
1440 if (context_getFlag (FLG_SHOWSCAN))
1441 {
1442 lldiagmsg (cstring_makeLiteral ("< global checks >"));
1443 }
1444
1445 cleanupMessages ();
1446
1447 if (context_getLinesProcessed () > 0)
1448 {
1449 usymtab_allDefined ();
1450 }
1451
1452 if (context_maybeSet (FLG_TOPUNUSED))
1453 {
1454 uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main"));
1455
1456 if (uentry_isValid (ue))
1457 {
1458 uentry_setUsed (ue, fileloc_observeBuiltin ());
1459 }
1460
1461 usymtab_allUsed ();
1462 }
1463
1464 if (context_maybeSet (FLG_EXPORTLOCAL))
1465 {
1466 usymtab_exportLocal ();
1467 }
1468
1469
1470 if (context_maybeSet (FLG_EXPORTHEADER))
1471 {
1472 usymtab_exportHeader ();
1473 }
1474
1475 if (context_getFlag (FLG_SHOWUSES))
1476 {
1477 usymtab_displayAllUses ();
1478 }
1479
1480 context_checkSuppressCounts ();
1481
1482 if (context_doDump ())
1483 {
1484 cstring dump = context_getDump ();
1485
1486 dumpState (dump);
1487 }
1488
1489# ifdef DOANNOTS
1490 printAnnots ();
1491# endif
1492
1493 cleanupFiles ();
1494
1495 if (context_getFlag (FLG_SHOWSUMMARY))
1496 {
1497 summarizeErrors ();
1498 }
1499
1500
1501 {
1502 bool isQuiet = context_getFlag (FLG_QUIET);
1503 cstring specErrors = cstring_undefined;
1504# ifndef NOLCL
1505 int nspecErrors = lclNumberErrors ();
1506# endif
1507
1508 expsuccess = TRUE;
1509
1510 if (context_neednl ())
1511 fprintf (g_msgstream, "\n");
1512
1513# ifndef NOLCL
1514 if (nspecErrors > 0)
1515 {
1516 if (nspecErrors == context_getLCLExpect ())
1517 {
1518 specErrors =
11db3170 1519 message ("%d spec warning%&, as expected\n ",
616915dd 1520 nspecErrors);
1521 }
1522 else
1523 {
1524 if (context_getLCLExpect () > 0)
1525 {
1526 specErrors =
11db3170 1527 message ("%d spec warning%&, expected %d\n ",
616915dd 1528 nspecErrors,
1529 (int) context_getLCLExpect ());
1530 }
1531 else
1532 {
11db3170 1533 specErrors = message ("%d spec warning%& found\n ",
616915dd 1534 nspecErrors);
1535 expsuccess = FALSE;
1536 }
1537 }
1538 }
1539 else
1540 {
1541 if (context_getLCLExpect () > 0)
1542 {
11db3170 1543 specErrors = message ("No spec warnings, expected %d\n ",
616915dd 1544 (int) context_getLCLExpect ());
1545 expsuccess = FALSE;
1546 }
1547 }
1548# endif
1549
1550 if (context_anyErrors ())
1551 {
1552 if (context_numErrors () == context_getExpect ())
1553 {
1554 if (!isQuiet) {
11db3170 1555 llmsg (message ("Finished checking --- "
1556 "%s%d code warning%&, as expected",
616915dd 1557 specErrors, context_numErrors ()));
1558 }
1559 }
1560 else
1561 {
1562 if (context_getExpect () > 0)
1563 {
1564 if (!isQuiet) {
1565 llmsg (message
11db3170 1566 ("Finished checking --- "
1567 "%s%d code warning%&, expected %d",
616915dd 1568 specErrors, context_numErrors (),
1569 (int) context_getExpect ()));
1570 }
1571
1572 expsuccess = FALSE;
1573 }
1574 else
1575 {
1576
28bf4b0b 1577 if (!isQuiet)
1578 {
11db3170 1579 llmsg (message ("Finished checking --- "
1580 "%s%d code warning%& found",
28bf4b0b 1581 specErrors, context_numErrors ()));
1582 }
616915dd 1583
1584 expsuccess = FALSE;
1585 }
1586 }
1587 }
1588 else
1589 {
1590 if (context_getExpect () > 0)
1591 {
1592 if (!isQuiet) {
1593 llmsg (message
11db3170 1594 ("Finished checking --- "
1595 "%sno code warnings, expected %d",
616915dd 1596 specErrors,
1597 (int) context_getExpect ()));
1598 }
1599
1600 expsuccess = FALSE;
1601 }
1602 else
1603 {
1604 if (context_getLinesProcessed () > 0)
1605 {
11db3170 1606 if (cstring_isEmpty (specErrors))
1607 {
1608 if (!isQuiet)
1609 {
1610 llmsg (message ("Finished checking --- no warnings"));
1611 }
1612 }
1613 else
1614 if (!isQuiet)
1615 {
1616 llmsg (message ("Finished checking --- %sno code warnings",
1617 specErrors));
1618 }
616915dd 1619 }
1620 else
1621 {
1622 if (!isQuiet) {
11db3170 1623 llmsg (message ("Finished checking --- %sno code processed",
616915dd 1624 specErrors));
1625 }
1626 }
1627 }
1628 }
1629
1630 cstring_free (specErrors);
1631 }
1632
1633 if (context_getFlag (FLG_STATS))
1634 {
1635 clock_t ttime = clock () - before;
1636 int specLines = context_getSpecLinesProcessed ();
1637
1638 rstime = clock ();
1639
1640 if (specLines > 0)
1641 {
1642 fprintf (g_msgstream, "%d spec, ", specLines);
1643 }
1644
1645# ifndef CLOCKS_PER_SEC
1646 fprintf (g_msgstream, "%d source lines in %ld time steps (steps/sec unknown)\n",
1647 context_getLinesProcessed (),
1648 (long) ttime);
1649# else
1650 fprintf (g_msgstream, "%d source lines in %.2f s.\n",
1651 context_getLinesProcessed (),
1652 (double) ttime / CLOCKS_PER_SEC);
1653# endif
1654 }
1655 else
1656 {
1657 rstime = clock ();
1658 }
1659
1660 if (context_getFlag (FLG_TIMEDIST))
1661 {
1662 clock_t ttime = clock () - before;
1663
1664 if (ttime > 0)
1665 {
1666 char *msg = (char *) dmalloc (256 * sizeof (*msg));
1667
1668 if (anylcl)
1669 {
1670 sprintf (msg,
1671 "Time distribution (percent): initialize %.2f / lcl %.2f / "
1672 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1673 (100.0 * (double) (libtime - before) / ttime),
1674 (100.0 * (double) (lcltime - libtime) / ttime),
1675 (100.0 * (double) (pptime - lcltime) / ttime),
1676 (100.0 * (double) (cptime - pptime) / ttime),
1677 (100.0 * (double) (rstime - cptime) / ttime));
1678 }
1679 else
1680 {
1681 sprintf (msg,
1682 "Time distribution (percent): initialize %.2f / "
1683 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1684 (100.0 * (double) (libtime - before) / ttime),
1685 (100.0 * (double) (pptime - libtime) / ttime),
1686 (100.0 * (double) (cptime - pptime) / ttime),
1687 (100.0 * (double) (rstime - cptime) / ttime));
1688 }
1689
1690 llgenindentmsgnoloc (cstring_fromCharsO (msg));
1691 }
1692 }
1693
1694 llexit (expsuccess ? LLSUCCESS : LLFAILURE);
8250fa4a 1695 BADBRANCHRET (LLFAILURE);
616915dd 1696}
1697
28bf4b0b 1698# ifdef WIN32
616915dd 1699/*
1700** Reenable return value warnings.
1701*/
28bf4b0b 1702# pragma warning (default:4035)
1703# endif
616915dd 1704
1705void
1706showHelp (void)
1707{
1708 showHerald ();
1709
28bf4b0b 1710 llmsg (message ("Source files are .c, .h and %s files. If there is no suffix,",
1711 LCL_EXTENSION));
11db3170 1712 llmsg (message (" Splint will look for <file>.c and <file>%s.", LCL_EXTENSION));
616915dd 1713 llmsglit ("");
11db3170 1714 llmsglit ("Use splint -help <topic or flag name> for more information");
616915dd 1715 llmsglit ("");
1716 llmsglit ("Topics:");
1717 llmsglit ("");
1718 llmsglit (" annotations (describes source-code annotations)");
1719 llmsglit (" comments (describes control comments)");
1720 llmsglit (" flags (describes flag categories)");
1721 llmsglit (" flags <category> (describes flags in category)");
1722 llmsglit (" flags all (short description of all flags)");
1723 llmsglit (" flags alpha (list all flags alphabetically)");
1724 llmsglit (" flags full (full description of all flags)");
1725 llmsglit (" mail (information on mailing lists)");
1726 llmsglit (" modes (show mode settings)");
1727 llmsglit (" parseerrors (help on handling parser errors)");
1728 llmsglit (" prefixcodes (character codes in namespace prefixes)");
1729 llmsglit (" references (sources for more information)");
1730 llmsglit (" vars (environment variables)");
1731 llmsglit (" version (information on compilation, maintainer)");
1732 llmsglit ("");
1733}
1734
1735static bool
1736specialFlagsHelp (char *next)
1737{
1738 if ((next != NULL) && (*next != '-') && (*next != '+'))
1739 {
1740 if (mstring_equal (next, "alpha"))
1741 {
1742 printAlphaFlags ();
1743 return TRUE;
1744 }
1745 else if (mstring_equal (next, "all"))
1746 {
1747 printAllFlags (TRUE, FALSE);
1748 return TRUE;
1749 }
1750 else if (mstring_equal (next, "categories")
1751 || mstring_equal (next, "cats"))
1752 {
1753 listAllCategories ();
1754 return TRUE;
1755 }
1756 else if (mstring_equal (next, "full"))
1757 {
1758 printAllFlags (FALSE, TRUE);
1759 return TRUE;
1760 }
1761 else
1762 {
1763 return FALSE;
1764 }
1765 }
1766 else
1767 {
1768 return FALSE;
1769 }
1770}
1771
1772void
1773printParseErrors (void)
1774{
1775 llmsglit ("Parse Errors");
1776 llmsglit ("------------");
1777 llmsglit ("");
1778 llmsglit ("LCLint will sometimes encounter a parse error for code that "
1779 "can be parsed with a local compiler. There are a few likely "
1780 "causes for this and a number of techniques that can be used "
1781 "to work around the problem.");
1782 llmsglit ("");
1783 llmsglit ("Compiler extensions --- compilers sometimes extend the C "
1784 "language with compiler-specific keywords and syntax. While "
1785 "it is not advisible to use these, oftentimes one has no choice "
1786 "when the system header files use compiler extensions. ");
1787 llmsglit ("");
11db3170 1788 llmsglit ("Splint supports some of the GNU (gcc) compiler extensions, "
616915dd 1789 "if the +gnuextensions flag is set. You may be able to workaround "
1790 "other compiler extensions by using a pre-processor define. "
1791 "Alternately, you can surround the unparseable code with");
1792 llmsglit ("");
1793 llmsglit (" # ifndef __LCLINT__");
1794 llmsglit (" ...");
1795 llmsglit (" # endif");
1796 llmsglit ("");
28bf4b0b 1797 /* evans 2000-12-21 fixed typo reported by Jeroen Ruigrok/Asmodai */
616915dd 1798 llmsglit ("Missing type definitions --- an undefined type name will usually "
28bf4b0b 1799 "lead to a parse error. This often occurs when a standard header "
616915dd 1800 "file defines some type that is not part of the standard library. ");
11db3170 1801 llmsglit ("By default, Splint does not process the local files corresponding "
616915dd 1802 "to standard library headers, but uses a library specification "
1803 "instead so dependencies on local system headers can be detected. "
1804 "If another system header file that does not correspond to a "
1805 "standard library header uses one of these superfluous types, "
1806 "a parse error will result.");
1807 llmsglit ("");
1808 llmsglit ("If the parse error is inside a posix standard header file, the "
11db3170 1809 "first thing to try is +posixlib. This makes Splint use "
616915dd 1810 "the posix library specification instead of reading the posix "
1811 "header files.");
1812 llmsglit ("");
1813 llmsglit ("Otherwise, you may need to either manually define the problematic "
1814 "type (e.g., add -Dmlink_t=int to your .lclintrc file) or force "
1815 "lclint to process the header file that defines it. This is done "
1816 "by setting -skipansiheaders or -skipposixheaders before "
1817 "the file that defines the type is #include'd.");
1818 llmsglit ("(See lclint -help "
1819 "skipansiheaders and lclint -help skipposixheaders for a list of "
1820 "standard headers.) For example, if <sys/local.h> uses a type "
1821 "defined by posix header <sys/types.h> but not defined by the "
1822 "posix library, we might do: ");
1823 llmsglit ("");
1824 llmsglit (" /*@-skipposixheaders@*/");
1825 llmsglit (" # include <sys/types.h>");
1826 llmsglit (" /*@=skipposixheaders@*/");
1827 llmsglit (" # include <sys/local.h>");
1828 llmsglit ("");
11db3170 1829 llmsglit ("to force Splint to process <sys/types.h>.");
616915dd 1830 llmsglit ("");
11db3170 1831 llmsglit ("At last resort, +trytorecover can be used to make Splint attempt "
616915dd 1832 "to continue after a parse error. This is usually not successful "
1833 "and the author does not consider assertion failures when +trytorecover "
1834 "is used to be bugs.");
1835}
1836
1837void
1838printAnnotations (void)
1839{
1840 llmsglit ("Annotations");
1841 llmsglit ("-----------");
1842 llmsglit ("");
28bf4b0b 1843 llmsglit ("Annotations are semantic comments that document certain "
616915dd 1844 "assumptions about functions, variables, parameters, and types. ");
1845 llmsglit ("");
1846 llmsglit ("They may be used to indicate where the representation of a "
1847 "user-defined type is hidden, to limit where a global variable may "
1848 "be used or modified, to constrain what a function implementation "
1849 "may do to its parameters, and to express checked assumptions about "
1850 "variables, types, structure fields, function parameters, and "
1851 "function results.");
1852 llmsglit ("");
1853 llmsglit ("Annotations are introduced by \"/*@\". The role of the @ may be "
1854 "played by any printable character, selected using -commentchar <char>.");
1855 llmsglit ("");
1856 llmsglit ("Consult the User's Guide for descriptions of checking associated with each annotation.");
1857 llmsglit ("");
1858 llmsglit ("Globals: (in function declarations)");
1859 llmsglit (" /*@globals <globitem>,+ @*/");
1860 llmsglit (" globitem is an identifier, internalState or fileSystem");
1861 llmsglit ("");
1862 llmsglit ("Modifies: (in function declarations)");
1863 llmsglit (" /*@modifies <moditem>,+ @*/");
1864 llmsglit (" moditem is an lvalue");
1865 llmsglit (" /*@modifies nothing @*/");
1866 llmsglit (" /*@*/ (Abbreviation for no globals and modifies nothing.)");
1867 llmsglit ("");
1868 llmsglit ("Iterators:");
1869 llmsglit (" /*@iter <identifier> (<parameter-type-list>) @*/ - declare an iterator");
1870 llmsglit ("");
1871 llmsglit ("Constants:");
1872 llmsglit (" /*@constant <declaration> @*/ - declares a constant");
1873 llmsglit ("");
1874 llmsglit ("Alternate Types:");
1875 llmsglit (" /*@alt <basic-type>,+ @*/");
1876 llmsglit (" (e.g., int /*@alt char@*/ is a type matching either int or char)");
1877 llmsglit ("");
1878 llmsglit ("Declarator Annotations");
1879 llmsglit ("");
1880 llmsglit ("Type Definitions:");
1881 llmsglit (" /*@abstract@*/ - representation is hidden from clients");
1882 llmsglit (" /*@concrete@*/ - representation is visible to clients");
1883 llmsglit (" /*@immutable@*/ - instances of the type cannot change value");
1884 llmsglit (" /*@mutable@*/ - instances of the type can change value");
1885 llmsglit (" /*@refcounted@*/ - reference counted type");
1886 llmsglit ("");
1887 llmsglit ("Global Variables:");
1888 llmsglit (" /*@unchecked@*/ - weakest checking for global use");
1889 llmsglit (" /*@checkmod@*/ - check modification by not use of global");
1890 llmsglit (" /*@checked@*/ - check use and modification of global");
1891 llmsglit (" /*@checkedstrict@*/ - check use of global strictly");
1892 llmsglit ("");
1893 llmsglit ("Memory Management:");
1894 llmsglit (" /*@dependent@*/ - a reference to externally-owned storage");
1895 llmsglit (" /*@keep@*/ - a parameter that is kept by the called function");
1896 llmsglit (" /*@killref@*/ - a refcounted parameter, killed by the call");
1897 llmsglit (" /*@only@*/ - an unshared reference");
1898 llmsglit (" /*@owned@*/ - owner of storage that may be shared by /*@dependent@*/ references");
1899 llmsglit (" /*@shared@*/ - shared reference that is never deallocated");
1900 llmsglit (" /*@temp@*/ - temporary parameter");
1901 llmsglit ("");
1902 llmsglit ("Aliasing:");
1903 llmsglit (" /*@unique@*/ - may not be aliased by any other visible reference");
1904 llmsglit (" /*@returned@*/ - may be aliased by the return value");
1905 llmsglit ("");
1906 llmsglit ("Exposure:");
1907 llmsglit (" /*@observer@*/ - reference that cannot be modified");
1908 llmsglit (" /*@exposed@*/ - exposed reference to storage in another object");
1909 llmsglit ("");
1910 llmsglit ("Definition State:");
1911 llmsglit (" /*@out@*/ - storage reachable from reference need not be defined");
1912 llmsglit (" /*@in@*/ - all storage reachable from reference must be defined");
1913 llmsglit (" /*@partial@*/ - partially defined, may have undefined fields");
1914 llmsglit (" /*@reldef@*/ - relax definition checking");
1915 llmsglit ("");
1916 llmsglit ("Global State: (for globals lists, no /*@, since list is already in /*@\'s)");
1917 llmsglit (" undef - variable is undefined before the call");
1918 llmsglit (" killed - variable is undefined after the call");
1919 llmsglit ("");
1920 llmsglit ("Null State:");
1921 llmsglit (" /*@null@*/ - possibly null pointer");
1922 llmsglit (" /*@notnull@*/ - non-null pointer");
1923 llmsglit (" /*@relnull@*/ - relax null checking");
1924 llmsglit ("");
1925 llmsglit ("Null Predicates:");
1926 llmsglit (" /*@truenull@*/ - if result is TRUE, first parameter is NULL");
1927 llmsglit (" /*@falsenull@*/ - if result is TRUE, first parameter is not NULL");
1928 llmsglit ("");
1929 llmsglit ("Execution:");
1930 llmsglit (" /*@exits@*/ - function never returns");
1931 llmsglit (" /*@mayexit@*/ - function may or may not return");
1932 llmsglit (" /*@trueexit@*/ - function does not return if first parameter is TRUE");
1933 llmsglit (" /*@falseexit@*/ - function does not return if first parameter if FALSE");
1934 llmsglit (" /*@neverexit@*/ - function always returns");
1935 llmsglit ("");
1936 llmsglit ("Side-Effects:");
1937 llmsglit (" /*@sef@*/ - corresponding actual parameter has no side effects");
1938 llmsglit ("");
1939 llmsglit ("Declaration:");
1940 llmsglit (" /*@unused@*/ - need not be used (no unused errors reported)");
1941 llmsglit (" /*@external@*/ - defined externally (no undefined error reported)");
1942 llmsglit ("");
1943 llmsglit ("Case:");
1944 llmsglit (" /*@fallthrough@*/ - fall-through case");
1945 llmsglit ("");
1946 llmsglit ("Break:");
1947 llmsglit (" /*@innerbreak@*/ - break is breaking an inner loop or switch");
1948 llmsglit (" /*@loopbreak@*/ - break is breaking a loop");
1949 llmsglit (" /*@switchbreak@*/ - break is breaking a switch");
1950 llmsglit (" /*@innercontinue@*/ - continue is continuing an inner loop");
1951 llmsglit ("");
1952 llmsglit ("Unreachable Code:");
1953 llmsglit (" /*@notreached@*/ - statement may be unreachable.");
1954 llmsglit ("");
1955 llmsglit ("Special Functions:");
1956 llmsglit (" /*@printflike@*/ - check variable arguments like printf");
1957 llmsglit (" /*@scanflike@*/ - check variable arguments like scanf");
1958}
1959
1960void
1961printComments (void)
1962{
1963 llmsglit ("Control Comments");
1964 llmsglit ("----------------");
1965 llmsglit ("");
1966 llmsglit ("Setting Flags");
1967 llmsglit ("");
1968 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.");
1969 llmsglit ("");
1970 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,");
1971 llmsglit (" /*@+boolint -modifies =showfunc@*/");
1972 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).");
1973 llmsglit ("");
1974 llmsglit ("Error Suppression");
1975 llmsglit ("");
1976 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.");
1977 llmsglit ("");
1978 llmsglit ("/*@ignore@*/ ... /*@end@*/");
1979 llgenindentmsgnoloc
1980 (cstring_makeLiteral
1981 ("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."));
1982 llmsglit ("/*@i@*/");
1983 llgenindentmsgnoloc
1984 (cstring_makeLiteral
1985 ("No errors will be reported from an /*@i@*/ comment to the end of the line."));
1986 llmsglit ("/*@i<n>@*/");
1987 llgenindentmsgnoloc
1988 (cstring_makeLiteral
11db3170 1989 ("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 1990 llmsglit ("/*@t@*/, /*@t<n>@*/");
1991 llgenindentmsgnoloc
1992 (cstring_makeLiteral
1993 ("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."));
1994 llmsglit ("");
1995 llmsglit ("Type Access");
1996 llmsglit ("");
1997 llmsglit ("/*@access <type>@*/");
1998 llmsglit (" Allows the following code to access the representation of <type>");
1999 llmsglit ("/*@noaccess <type>@*/");
2000 llmsglit (" Hides the representation of <type>");
2001 llmsglit ("");
2002 llmsglit ("Macro Expansion");
2003 llmsglit ("");
2004 llmsglit ("/*@notfunction@*/");
2005 llgenindentmsgnoloc
2006 (cstring_makeLiteral
2007 ("Indicates that the next macro definition is not intended to be a "
2008 "function, and should be expanded in line instead of checked as a "
2009 "macro function definition."));
2010}
2011
2012
2013void
2014printFlags (void)
2015{
2016 llmsglit ("Flag Categories");
2017 llmsglit ("---------------");
2018 listAllCategories ();
2019 llmsglit ("\nTo see the flags in a flag category, do\n lclint -help flags <category>");
2020 llmsglit ("To see a list of all flags in alphabetical order, do\n lclint -help flags alpha");
2021 llmsglit ("To see a full description of all flags, do\n lclint -help flags full");
2022}
2023
2024void
2025printMaintainer (void)
2026{
2027 llmsg (message ("Maintainer: %s", cstring_makeLiteralTemp (LCLINT_MAINTAINER)));
2028 llmsglit (LCL_COMPILE);
2029}
2030
2031void
2032printMail (void)
2033{
2034 llmsglit ("Mailing Lists");
2035 llmsglit ("-------------");
2036 llmsglit ("");
11db3170 2037 llmsglit ("There are two mailing lists associated with Splint: ");
616915dd 2038 llmsglit ("");
2039 llmsglit (" lclint-announce@virginia.edu");
2040 llmsglit ("");
2041 llmsglit (" Reserved for announcements of new releases and bug fixes.");
2042 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
2043 llmsglit (" subscribe lclint-announce");
2044 llmsglit ("");
2045 llmsglit (" lclint-interest@virginia.edu");
2046 llmsglit ("");
2047 llmsglit (" Informal discussions on the use and development of lclint.");
2048 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
2049 llmsglit (" subscribe lclint-interest");
2050}
2051
2052void
2053printReferences (void)
2054{
2055 llmsglit ("References");
2056 llmsglit ("----------");
2057 llmsglit ("");
11db3170 2058 llmsglit ("For more information, see the Splint web site: http://www.splint.org");
616915dd 2059}
2060
2061void
2062describePrefixCodes (void)
2063{
2064 llmsglit ("Prefix Codes");
2065 llmsglit ("------------");
2066 llmsglit ("");
2067 llmsglit ("These characters have special meaning in name prefixes:");
2068 llmsglit ("");
2069 llmsg (message (" %h Any uppercase letter [A-Z]", PFX_UPPERCASE));
2070 llmsg (message (" %h Any lowercase letter [a-z]", PFX_LOWERCASE));
2071 llmsg (message (" %h Any character (valid in a C identifier)", PFX_ANY));
2072 llmsg (message (" %h Any digit [0-9]", PFX_DIGIT));
2073 llmsg (message (" %h Any non-uppercase letter [a-z0-9_]", PFX_NOTUPPER));
2074 llmsg (message (" %h Any non-lowercase letter [A-Z0-9_]", PFX_NOTLOWER));
2075 llmsg (message (" %h Any letter [A-Za-z]", PFX_ANYLETTER));
2076 llmsg (message (" %h Any letter or digit [A-Za-z0-9]", PFX_ANYLETTERDIGIT));
2077 llmsglit (" * Zero or more repetitions of the previous character class until the end of the name");
2078}
2079
2080void
2081describeVars (void)
2082{
2083 cstring eval;
28bf4b0b 2084 cstring def;
616915dd 2085
2086 eval = context_getLarchPath ();
2087 def = osd_getEnvironmentVariable (LARCH_PATH);
2088
28bf4b0b 2089 if (cstring_isDefined (def) ||
616915dd 2090 !cstring_equal (eval, cstring_fromChars (DEFAULT_LARCHPATH)))
2091 {
2092 llmsg (message ("LARCH_PATH = %s", eval));
2093 }
2094 else
2095 {
2096 llmsg (message ("LARCH_PATH = <not set> (default = %s)",
2097 cstring_fromChars (DEFAULT_LARCHPATH)));
2098 }
2099
2100 llmsglit (" --- path used to find larch initialization files and LSL traits");
2101
2102 eval = context_getLCLImportDir ();
28bf4b0b 2103 def = osd_getEnvironmentVariable (cstring_makeLiteralTemp (LCLIMPORTDIR));
616915dd 2104
28bf4b0b 2105 if (cstring_isDefined (def) ||
616915dd 2106 !cstring_equal (eval, cstring_fromChars (DEFAULT_LCLIMPORTDIR)))
2107 {
2108 llmsg (message ("%q = %s", cstring_makeLiteral (LCLIMPORTDIR), eval));
2109 }
2110 else
2111 {
2112 llmsg (message ("%s = <not set, default: %s>", cstring_makeLiteralTemp (LCLIMPORTDIR),
2113 cstring_makeLiteralTemp (DEFAULT_LCLIMPORTDIR)));
2114 }
2115
2116 llmsglit (" --- directory containing lcl standard library files "
2117 "(import with < ... >)");;
2118
7272a1c1 2119 llmsg (message
2120 ("include path = %q (set by environment variable %s and -I flags)",
2121 cppReader_getIncludePath (), INCLUDEPATH_VAR));
616915dd 2122
7272a1c1 2123 llmsglit (" --- path used to find #include'd files");
2124
2125 llmsg (message
68de3f33 2126 ("systemdirs = %s (set by -systemdirs or environment variable %s)", /*@i413223@*/
7272a1c1 2127 context_getString (FLG_SYSTEMDIRS),
2128 INCLUDEPATH_VAR));
2129
2130 llmsglit (" --- if file is found on this path, it is treated as a system file for error reporting");
616915dd 2131}
2132
2133void
2134interrupt (int i)
2135{
2136 switch (i)
2137 {
2138 case SIGINT:
2139 fprintf (stderr, "*** Interrupt\n");
2140 llexit (LLINTERRUPT);
2141 case SIGSEGV:
2142 {
2143 cstring loc;
2144
2145 /* Cheat when there are parse errors */
2146 checkParseError ();
2147
2148 fprintf (stderr, "*** Segmentation Violation\n");
2149
2150 /* Don't catch it if fileloc_unparse causes a signal */
2151 (void) signal (SIGSEGV, NULL);
2152
2153 loc = fileloc_unparse (g_currentloc);
2154
2155 fprintf (stderr, "*** Location (not trusted): %s\n",
2156 cstring_toCharsSafe (loc));
2157 cstring_free (loc);
2158 printCodePoint ();
2159 fprintf (stderr, "*** Please report bug to %s\n", LCLINT_MAINTAINER);
2160 exit (LLGIVEUP);
2161 }
2162 default:
2163 fprintf (stderr, "*** Signal: %d\n", i);
2164 /*@-mustfree@*/
2165 fprintf (stderr, "*** Location (not trusted): %s\n",
2166 cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
2167 /*@=mustfree@*/
2168 printCodePoint ();
2169 fprintf (stderr, "*** Please report bug to %s ***\n", LCLINT_MAINTAINER);
2170 exit (LLGIVEUP);
2171 }
2172}
2173
2174void
2175cleanupFiles (void)
2176{
2177 static bool doneCleanup = FALSE;
2178
2179 /* make sure this is only called once! */
2180
2181 if (doneCleanup) return;
2182
2183 setCodePoint ();
2184
dfd82dce 2185 /*
2186 ** Close all open files
2187 ** (There should only be open files, if we exited after a fatal error.)
2188 */
2189
2190 fileTable_closeAll (context_fileTable ());
2191
616915dd 2192 if (context_getFlag (FLG_KEEP))
2193 {
2194 check (fputs ("Temporary files kept:\n", stderr) != EOF);
2195 fileTable_printTemps (context_fileTable ());
2196 }
2197 else
2198 {
2199# ifdef WIN32
2200 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
2201
2202 if (nfiles != 0)
2203 {
2204 llbug (message ("Files unclosed: %d", nfiles));
2205 }
2206# endif
2207 fileTable_cleanup (context_fileTable ());
2208 }
2209
2210 doneCleanup = TRUE;
2211}
2212
2213/*
11db3170 2214** cleans up temp files (if necessary) and exits
616915dd 2215*/
2216
2217/*@exits@*/ void
2218llexit (int status)
2219{
2220 DPRINTF (("llexit: %d", status));
2221
2222# ifdef WIN32
2223 if (status == LLFAILURE)
2224 {
2225 _fcloseall ();
2226 }
2227# endif
2228
2229 cleanupFiles ();
2230
2231 if (status != LLFAILURE)
2232 {
2233 context_destroyMod ();
2234 exprNode_destroyMod ();
2235
2236 sRef_destroyMod ();
2237 uentry_destroyMod ();
2238 typeIdSet_destroyMod ();
2239
2240# ifdef USEDMALLOC
2241 dmalloc_shutdown ();
2242# endif
2243 }
2244
2245 exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
2246}
2247
f2b6724f 2248bool readOptionsFile (cstring fname, cstringSList *passThroughArgs, bool report)
2249{
2250 bool res = FALSE;
2251
2252 if (fileTable_exists (context_fileTable (), fname))
2253 {
2254 if (report)
2255 {
2256 voptgenerror
2257 (FLG_WARNRC,
2258 message ("Multiple attempts to read options file: %s", fname),
2259 g_currentloc);
2260 }
2261 }
2262 else
2263 {
2264 FILE *innerf = fileTable_openFile (context_fileTable (), fname, "r");
2265
2266 if (innerf != NULL)
2267 {
2268 fileloc fc = g_currentloc;
2269 g_currentloc = fileloc_createRc (fname);
2270
2271 if (context_getFlag (FLG_SHOWSCAN))
2272 {
2273 lldiagmsg (message ("< reading options from %s >",
2274 fileloc_outputFilename (g_currentloc)));
2275 }
2276
2277 loadrc (innerf, passThroughArgs);
2278 fileloc_reallyFree (g_currentloc);
2279 g_currentloc = fc;
2280 res = TRUE;
2281 }
2282 else
2283 {
2284 if (report)
2285 {
2286 voptgenerror
2287 (FLG_WARNRC,
2288 message ("Cannot open options file: %s", fname),
2289 g_currentloc);
2290 }
2291 }
2292 }
2293
2294 return res;
2295}
2296
ee229125 2297/*
2298** This shouldn't be necessary, but Apple Darwin can't handle '"''s.
2299*/
2300
616915dd 2301void
15b3d2b2 2302loadrc (/*:open:*/ FILE *rcfile, cstringSList *passThroughArgs)
b9904f57 2303 /*@ensures closed rcfile@*/
616915dd 2304{
2305 char *s = mstring_create (MAX_LINE_LENGTH);
2306 char *os = s;
f2b6724f 2307
616915dd 2308 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2309
2310 s = os;
2311
28bf4b0b 2312 while (reader_readLine (rcfile, s, MAX_LINE_LENGTH) != NULL)
616915dd 2313 {
2314 char c;
2315 bool set = FALSE;
2316 char *thisflag;
2317 flagcode opt;
2318
2319 DPRINTF (("Line: %s", s));
2320 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
616915dd 2321
28bf4b0b 2322 while (*s == ' ' || *s == '\t')
616915dd 2323 {
2324 s++;
2325 incColumn ();
2326 }
2327
2328 while (*s != '\0')
2329 {
2330 bool escaped = FALSE;
2331 bool quoted = FALSE;
2332 c = *s;
2333
2334 DPRINTF (("Process: %s", s));
2335 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2336 /* comment characters */
2337 if (c == '#' || c == ';' || c == '\n')
2338 {
2339 /*@innerbreak@*/
2340 break;
2341 }
2342
2343 if (c == '-' || c == '+')
2344 {
2345 set = (c == '+');
2346 }
2347 else
2348 {
2349 showHerald ();
ccf0a4a8 2350 voptgenerror (FLG_BADFLAG,
2351 message ("Bad flag syntax (+ or - expected, "
2352 "+ is assumed): %s",
2353 cstring_fromChars (s)),
2354 g_currentloc);
616915dd 2355 s--;
2356 set = TRUE;
2357 }
2358
2359 s++;
2360 incColumn ();
2361
2362 thisflag = s;
2363
2364 while ((c = *s) != '\0')
2365 { /* remember to handle spaces and quotes in -D and -U ... */
2366 if (escaped)
2367 {
2368 escaped = FALSE;
2369 }
2370 else if (quoted)
2371 {
2372 if (c == '\\')
2373 {
2374 escaped = TRUE;
2375 }
2376 else if (c == '\"')
2377 {
2378 quoted = FALSE;
2379 }
2380 else
2381 {
2382 ;
2383 }
2384 }
2385 else if (c == '\"')
2386 {
2387 quoted = TRUE;
2388 }
2389 else
2390 {
2391 if (c == ' ' || c == '\t' || c == '\n')
2392 {
2393 /*@innerbreak@*/ break;
2394 }
2395 }
2396
2397 s++;
2398 incColumn ();
2399 }
2400
2401 DPRINTF (("Nulling: %c", *s));
2402 *s = '\0';
2403
2404 if (mstring_isEmpty (thisflag))
2405 {
2406 llfatalerror (message ("Missing flag: %s",
2407 cstring_fromChars (os)));
2408 }
2409
2410 DPRINTF (("Flag: %s", thisflag));
2411
2412 opt = identifyFlag (cstring_fromChars (thisflag));
2413
2414 if (flagcode_isSkip (opt))
2415 {
2416 ;
2417 }
2418 else if (flagcode_isInvalid (opt))
2419 {
28bf4b0b 2420 DPRINTF (("Invalid: %s", thisflag));
2421
616915dd 2422 if (isMode (cstring_fromChars (thisflag)))
2423 {
2424 context_setMode (cstring_fromChars (thisflag));
2425 }
2426 else
2427 {
ccf0a4a8 2428 voptgenerror (FLG_BADFLAG,
2429 message ("Unrecognized option: %s",
2430 cstring_fromChars (thisflag)),
2431 g_currentloc);
616915dd 2432 }
2433 }
2434 else
2435 {
2436 context_userSetFlag (opt, set);
2437
2438 if (flagcode_hasArgument (opt))
2439 {
2440 if (opt == FLG_HELP)
2441 {
2442 showHerald ();
ccf0a4a8 2443 voptgenerror (FLG_BADFLAG,
2444 message ("Cannot use help in rc files"),
2445 g_currentloc);
616915dd 2446 }
2447 else if (flagcode_isPassThrough (opt)) /* -D or -U */
2448 {
2449 cstring arg = cstring_fromCharsNew (thisflag);
2450 cstring_markOwned (arg);
2451 *passThroughArgs = cstringSList_add (*passThroughArgs, arg);
2452 DPRINTF (("Pass through: %s",
2453 cstringSList_unparse (*passThroughArgs)));
2454 }
2455 else if (opt == FLG_INCLUDEPATH
2456 || opt == FLG_SPECPATH)
2457 {
2458 cstring dir = cstring_suffix (cstring_fromChars (thisflag), 1); /* skip over I/S */
2459
2460 switch (opt)
2461 {
2462 case FLG_INCLUDEPATH:
2463 cppAddIncludeDir (dir);
2464 /*@switchbreak@*/ break;
2465 case FLG_SPECPATH:
2466 /*@-mustfree@*/
2467 g_localSpecPath = cstring_toCharsSafe
2468 (message ("%s:%s", cstring_fromChars (g_localSpecPath), dir));
2469 /*@=mustfree@*/
2470 /*@switchbreak@*/ break;
2471 BADDEFAULT;
2472 }
2473 }
2474 else if (flagcode_hasString (opt)
2475 || flagcode_hasValue (opt)
2476 || opt == FLG_INIT || opt == FLG_OPTF)
2477 {
2478 cstring extra = cstring_undefined;
2479 char *rest, *orest;
2480 char rchar;
2481
2482 *s = c;
2483 rest = mstring_copy (s);
2484 DPRINTF (("Here: rest = %s", rest));
2485 orest = rest;
2486 *s = '\0';
2487
2488 while ((rchar = *rest) != '\0'
2489 && (isspace ((int) rchar)))
2490 {
2491 rest++;
2492 s++;
2493 }
2494
2495 DPRINTF (("Yo: %s", rest));
2496
2497 while ((rchar = *rest) != '\0'
2498 && !isspace ((int) rchar))
2499 {
2500 extra = cstring_appendChar (extra, rchar);
2501 rest++;
2502 s++;
2503 }
2504
2505 DPRINTF (("Yo: %s", extra));
2506 sfree (orest);
2507
2508 if (cstring_isUndefined (extra))
2509 {
2510 showHerald ();
ccf0a4a8 2511 voptgenerror
616915dd 2512 (FLG_BADFLAG,
2513 message
2514 ("Flag %s must be followed by an argument",
ccf0a4a8 2515 flagcode_unparse (opt)),
2516 g_currentloc);
616915dd 2517 }
2518 else
2519 {
2520 s--;
2521
2522 DPRINTF (("Here we are: %s", extra));
2523
2524 if (flagcode_hasValue (opt))
2525 {
2526 DPRINTF (("Set value flag: %s", extra));
2527 setValueFlag (opt, extra);
2528 cstring_free (extra);
2529 }
2530 else if (opt == FLG_OPTF)
2531 {
f2b6724f 2532 (void) readOptionsFile (extra, passThroughArgs, TRUE);
616915dd 2533 }
2534 else if (opt == FLG_INIT)
2535 {
2536# ifndef NOLCL
28bf4b0b 2537 llassert (inputStream_isUndefined (initFile));
616915dd 2538
28bf4b0b 2539 initFile = inputStream_create
2540 (extra,
2541 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
2542 FALSE);
616915dd 2543# else
2544 cstring_free (extra);
2545# endif
2546 }
2547 else if (flagcode_hasString (opt))
2548 {
ee229125 2549 if (cstring_firstChar (extra) == '\"')
616915dd 2550 {
ee229125 2551 if (cstring_lastChar (extra) == '\"')
616915dd 2552 {
2553 char *extras = cstring_toCharsSafe (extra);
2554
ee229125 2555 llassert (extras[strlen(extras) - 1] == '\"');
616915dd 2556 extras[strlen(extras) - 1] = '\0';
2557 extra = cstring_fromChars (extras + 1);
ee229125 2558 DPRINTF (("Remove quotes: %s", extra));
616915dd 2559 }
2560 else
2561 {
ccf0a4a8 2562 voptgenerror
2563 (FLG_BADFLAG,
616915dd 2564 message ("Unmatched \" in option string: %s",
ccf0a4a8 2565 extra),
2566 g_currentloc);
616915dd 2567 }
2568 }
2569
2570 setStringFlag (opt, extra);
2571 }
2572 else
2573 {
2574 cstring_free (extra);
2575 BADEXIT;
2576 }
2577 }
2578 }
2579 else
2580 {
2581 BADEXIT;
2582 }
2583 }
2584 }
2585
2586 *s = c;
2587 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2588 while ((c == ' ') || (c == '\t'))
2589 {
2590 c = *(++s);
2591 incColumn ();
2592 }
2593 }
2594 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2595 s = os;
2596 }
2597
2598 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2599 sfree (os);
dfd82dce 2600 check (fileTable_closeFile (context_fileTable (), rcfile));
616915dd 2601}
2602
28bf4b0b 2603static fileIdList preprocessFiles (fileIdList fl, bool xhfiles)
616915dd 2604 /*@modifies fileSystem@*/
2605{
2606 bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
2607 int skip = (fileIdList_size (fl) / 5);
2608 int filesprocessed = 0;
2609 fileIdList dfiles = fileIdList_create ();
2610
2611 fileloc_free (g_currentloc);
2612 g_currentloc = fileloc_createBuiltin ();
2613
2614 fileIdList_elements (fl, fid)
2615 {
28bf4b0b 2616 cstring ppfname = fileName (fid);
616915dd 2617
53a89507 2618 if (!(osd_fileIsReadable (ppfname)))
616915dd 2619 {
53a89507 2620 lldiagmsg (message ("Cannot open file: %s", osd_outputPath (ppfname)));
2621 ppfname = cstring_undefined;
28bf4b0b 2622 }
2623
2624 if (cstring_isDefined (ppfname))
2625 {
2626 fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
53a89507 2627
2628 if (xhfiles)
2629 {
2630 llassert (fileTable_isXHFile (context_fileTable (), dfile));
2631 }
2632
28bf4b0b 2633 llassert (cstring_isNonEmpty (ppfname));
616915dd 2634
2635 if (msg)
2636 {
2637 if ((filesprocessed % skip) == 0)
2638 {
2639 if (filesprocessed == 0) {
2640 fprintf (stderr, " ");
2641 }
2642 else {
2643 fprintf (stderr, ".");
2644 }
2645
2646 (void) fflush (stderr);
2647 }
2648 filesprocessed++;
2649 }
2650
28bf4b0b 2651 if (cppProcess (ppfname, fileName (dfile)) != 0)
616915dd 2652 {
2653 llfatalerror (message ("Preprocessing error for file: %s",
2654 rootFileName (fid)));
2655 }
2656
2657 fileIdList_add (dfiles, dfile);
2658 }
2659 } end_fileIdList_elements;
2660
2661 return dfiles;
2662}
28bf4b0b 2663
2664/* This should be in an lclUtils.c file... */
2665# ifndef NOLCL
2666char *specFullName (char *specfile, /*@out@*/ char **inpath)
2667{
2668 /* extract the path and the specname associated with the given file */
2669 char *specname = (char *) dmalloc (sizeof (*specname)
2670 * (strlen (specfile) + 9));
2671 char *ospecname = specname;
2672 char *path = (char *) dmalloc (sizeof (*path) * (strlen (specfile)));
2673 size_t size;
2674 long int i, j;
2675
2676 /* initialized path to empty string or may have accidental garbage */
2677 *path = '\0';
2678
2679 /*@-mayaliasunique@*/
2680 strcpy (specname, specfile);
2681 /*@=mayaliasunique@*/
2682
2683 /* trim off pathnames in specfile */
2684 size = strlen (specname);
2685
2686 for (i = size_toInt (size) - 1; i >= 0; i--)
2687 {
2688 if (specname[i] == CONNECTCHAR)
2689 {
2690 /* strcpy (specname, (char *)specname+i+1); */
2691 for (j = 0; j <= i; j++) /* include '/' */
2692 {
2693 path[j] = specname[j];
2694 }
2695
2696 path[i + 1] = '\0';
2697 specname += i + 1;
2698 break;
2699 }
2700 }
2701
2702 /*
2703 ** also remove .lcl file extension, assume it's the last extension
2704 ** of the file name
2705 */
2706
2707 size = strlen (specname);
2708
2709 for (i = size_toInt (size) - 1; i >= 0; i--)
2710 {
2711 if (specname[i] == '.')
2712 {
2713 specname[i] = '\0';
2714 break;
2715 }
2716 }
2717
2718 *inpath = path;
2719
2720 /*
2721 ** If specname no longer points to the original char,
2722 ** we need to allocate a new pointer and copy the string.
2723 */
2724
2725 if (specname != ospecname) {
2726 char *rspecname = (char *) dmalloc (sizeof (*rspecname) * (strlen (specname) + 1));
2727 strcpy (rspecname, specname); /* evs 2000-05-16: Bug: was ospecname! */
2728 sfree (ospecname);
2729 return rspecname;
2730 }
2731
2732 return specname;
2733}
2734# endif
This page took 0.463118 seconds and 5 git commands to generate.