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