]> andersk Git - splint.git/blame - src/llmain.c
Fixed problem with assertion checking for negative shifts in
[splint.git] / src / llmain.c
CommitLineData
616915dd 1/*
11db3170 2** Splint - annotation-assisted static program checker
c59f5181 3** Copyright (C) 1994-2003 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"
b73d1009 52# include "basic.h"
616915dd 53# include "osd.h"
140c27a8 54# include "help.h"
616915dd 55# include "gram.h"
56# include "lclscan.h"
57# include "scanline.h"
58# include "lclscanline.h"
59# include "lclsyntable.h"
60# include "lcltokentable.h"
61# include "lslparse.h"
62# include "scan.h"
63# include "syntable.h"
64# include "tokentable.h"
65# include "lslinit.h"
66# include "lclinit.h"
67# include "lh.h"
68# include "imports.h"
616915dd 69
4dd72714 70# include "Headers/version.h" /* Visual C++ finds the wrong version.h */
616915dd 71# include "lcllib.h"
72# include "cgrammar.h"
4caf866b 73# include "rcfiles.h"
616915dd 74# include "llmain.h"
616915dd 75
76extern /*@external@*/ int yydebug;
616915dd 77static void cleanupFiles (void);
ce7034f0 78/*
79** evans 2002-07-03: renamed from interrupt to avoid conflict with WATCOM compiler keyword
80** (Suggested by Adam Clarke)
81*/
82
83static void llinterrupt (int p_i);
990ec868 84
616915dd 85static void describeVars (void);
86static bool specialFlagsHelp (char *p_next);
87static bool hasShownHerald = FALSE;
28bf4b0b 88static char *specFullName (char *p_specfile, /*@out@*/ char **p_inpath)
89 /*@modifies *p_inpath@*/ ;
616915dd 90
91static bool anylcl = FALSE;
92static clock_t inittime;
93
28bf4b0b 94static fileIdList preprocessFiles (fileIdList, bool)
616915dd 95 /*@modifies fileSystem@*/ ;
96
0e5499ac 97static void warnSysFiles(fileIdList p_files) /*@modifies fileSystem@*/;
e55c0c6d 98
616915dd 99static
100void lslCleanup (void)
101 /*@globals killed g_symtab@*/
102 /*@modifies internalState, g_symtab@*/
103{
104 /*
105 ** Cleanup all the LCL/LSL.
106 */
107
108 static bool didCleanup = FALSE;
109
110 llassert (!didCleanup);
111 llassert (anylcl);
112
113 didCleanup = TRUE;
114
115 lsymbol_destroyMod ();
116 LCLSynTableCleanup ();
117 LCLTokenTableCleanup ();
118 LCLScanLineCleanup ();
119 LCLScanCleanup ();
120
121 /* clean up LSL parsing */
122
123 lsynTableCleanup ();
124 ltokenTableCleanup ();
125 lscanLineCleanup ();
126 LSLScanCleanup ();
127
128 symtable_free (g_symtab);
129 sort_destroyMod ();
130}
131
616915dd 132static void
133lslProcess (fileIdList lclfiles)
134 /*@globals undef g_currentSpec, undef g_currentSpecName, g_currentloc,
135 undef killed g_symtab; @*/
136 /*@modifies g_currentSpec, g_currentSpecName, g_currentloc, internalState, fileSystem; @*/
137{
138 char *path = NULL;
139 bool parser_status = FALSE;
140 bool overallStatus = FALSE;
141
140c27a8 142 lslinit_process ();
143 inittime = clock ();
144
616915dd 145 context_resetSpecLines ();
146
147 fileIdList_elements (lclfiles, fid)
148 {
28bf4b0b 149 cstring actualName = cstring_undefined;
4dd72714 150 cstring fname = fileTable_fileName (fid);
616915dd 151
28bf4b0b 152 if (osd_getPath (cstring_fromChars (g_localSpecPath),
153 fname, &actualName) == OSD_FILENOTFOUND)
616915dd 154 {
155 if (mstring_equal (g_localSpecPath, "."))
156 {
53a89507 157 lldiagmsg (message ("Spec file not found: %q", osd_outputPath (fname)));
616915dd 158 }
159 else
160 {
53a89507 161 lldiagmsg (message ("Spec file not found: %q (on %s)",
162 osd_outputPath (fname),
616915dd 163 cstring_fromChars (g_localSpecPath)));
164 }
165 }
166 else
167 {
28bf4b0b 168 inputStream specFile;
169 /*@access cstring@*/
170 char *namePtr = actualName;
171
172 while (*namePtr == '.' && *(namePtr + 1) == CONNECTCHAR)
616915dd 173 {
28bf4b0b 174 namePtr += 2;
616915dd 175 }
28bf4b0b 176 /*@noaccess cstring@*/
177
178 g_currentSpec = cstring_fromCharsNew (namePtr);
179
180 specFile = inputStream_create (cstring_copy (g_currentSpec),
181 LCL_EXTENSION, TRUE);
616915dd 182
28bf4b0b 183 llassert (inputStream_isDefined (specFile));
616915dd 184
616915dd 185 g_currentSpecName = specFullName
186 (cstring_toCharsSafe (g_currentSpec),
187 &path);
188
189 setSpecFileId (fid);
190
80489f0a 191 displayScan (message ("reading spec %s", g_currentSpec));
616915dd 192
f7bbce9e 193 /* Open the source file */
616915dd 194
28bf4b0b 195 if (!inputStream_open (specFile))
616915dd 196 {
53a89507 197 lldiagmsg (message ("Cannot open file: %q",
198 osd_outputPath (inputStream_fileName (specFile))));
28bf4b0b 199 inputStream_free (specFile);
616915dd 200 }
201 else
202 {
203 scopeInfo dummy_scope = (scopeInfo) dmalloc (sizeof (*dummy_scope));
204 dummy_scope->kind = SPE_INVALID;
205
206 lhInit (specFile);
207 LCLScanReset (specFile);
208
209 /*
210 ** Minor hacks to allow more than one LCL file to
211 ** be scanned, while keeping initializations
212 */
213
214 symtable_enterScope (g_symtab, dummy_scope);
215 resetImports (cstring_fromChars (g_currentSpecName));
216 context_enterLCLfile ();
217 (void) lclHadNewError ();
218
219 parser_status = (ylparse () != 0);
220 context_exitLCLfile ();
221 lhCleanup ();
222 overallStatus = parser_status || lclHadNewError ();
223
224 if (context_getFlag (FLG_DOLCS))
225 {
226 if (overallStatus)
227 {
28bf4b0b 228 outputLCSFile (path, "%FAILED Output from ",
616915dd 229 g_currentSpecName);
230 }
231 else
232 {
28bf4b0b 233 outputLCSFile (path, "%PASSED Output from ",
616915dd 234 g_currentSpecName);
235 }
236 }
237
28bf4b0b 238 (void) inputStream_close (specFile);
239 inputStream_free (specFile);
616915dd 240
241 symtable_exitScope (g_symtab);
28bf4b0b 242 }
616915dd 243 }
28bf4b0b 244 cstring_free (actualName);
616915dd 245 } end_fileIdList_elements;
28bf4b0b 246
616915dd 247 /* Can cleanup lsl stuff right away */
28bf4b0b 248
249 lslCleanup ();
250
251 g_currentSpec = cstring_undefined;
252 g_currentSpecName = NULL;
616915dd 253}
616915dd 254
255static void handlePassThroughFlag (char *arg)
256{
257 char *curarg = arg;
258 char *quotechar = strchr (curarg, '\"');
259 int offset = 0;
260 bool open = FALSE;
b37cf05e 261 char *freearg = NULL;
616915dd 262
263 while (quotechar != NULL)
264 {
265 if (*(quotechar - 1) == '\\')
266 {
267 char *tp = quotechar - 2;
268 bool escape = TRUE;
269
270 while (*tp == '\\')
271 {
272 escape = !escape;
273 tp--;
274 }
275
276 if (escape)
277 {
278 curarg = quotechar + 1;
279 quotechar = strchr (curarg, '\"');
280 continue;
281 }
282 }
283
b37cf05e 284 llassert (quotechar != NULL);
616915dd 285 *quotechar = '\0';
286 offset = (quotechar - arg) + 2;
287
288 if (open)
289 {
290 arg = cstring_toCharsSafe
291 (message ("%s\"\'%s",
292 cstring_fromChars (arg),
293 cstring_fromChars (quotechar + 1)));
b37cf05e 294 freearg = arg;
616915dd 295 open = FALSE;
296 }
297 else
298 {
299 arg = cstring_toCharsSafe
300 (message ("%s\'\"%s",
301 cstring_fromChars (arg),
302 cstring_fromChars (quotechar + 1)));
b37cf05e 303 freearg = arg;
616915dd 304 open = TRUE;
305 }
306
307 curarg = arg + offset;
308 quotechar = strchr (curarg, '\"');
309 }
310
311 if (open)
312 {
313 showHerald ();
ccf0a4a8 314 voptgenerror (FLG_BADFLAG,
315 message ("Unclosed quote in flag: %s",
316 cstring_fromChars (arg)),
317 g_currentloc);
616915dd 318 }
319 else
320 {
321 if (arg[0] == 'D') {
322 cstring def;
323
324 /*
325 ** If the value is surrounded by single quotes ('), remove
326 ** them. This is an artifact of UNIX command line?
327 */
328
28bf4b0b 329 def = osd_fixDefine (cstring_fromChars (arg + 1));
616915dd 330 DPRINTF (("Do define: %s", def));
331 cppDoDefine (def);
332 DPRINTF (("After define"));
333 cstring_free (def);
334 } else if (arg[0] == 'U') {
335 cppDoUndefine (cstring_fromChars (arg + 1));
336 } else {
337 BADBRANCH;
338 }
339 }
b37cf05e 340
341 sfree (freearg);
616915dd 342}
343
344void showHerald (void)
345{
80489f0a 346 if (hasShownHerald || context_getFlag (FLG_QUIET))
347 {
348 return;
349 }
616915dd 350 else
351 {
80489f0a 352 fprintf (g_messagestream, "%s\n\n", SPLINT_VERSION);
616915dd 353 hasShownHerald = TRUE;
354 llflush ();
355 }
356}
357
616915dd 358/*
1b8ae690 359** Disable MSVC++ warning about return value. Methinks humbly splint control
616915dd 360** comments are a mite more legible.
361*/
362
363# ifdef WIN32
364# pragma warning (disable:4035)
365# endif
366
367int main (int argc, char *argv[])
616915dd 368 /*@globals killed undef g_currentloc,
616915dd 369 killed g_localSpecPath,
370 killed undef g_currentSpec,
371 killed undef g_currentSpecName,
372 killed undef yyin,
80489f0a 373 undef g_warningstream, g_messagestream, g_errorstream;
616915dd 374 @*/
140c27a8 375 /*@modifies g_currentloc, g_localSpecPath, g_currentSpec, g_currentSpecName,
376 fileSystem, yyin;
616915dd 377 @*/
616915dd 378{
379 bool first_time = TRUE;
616915dd 380 bool expsuccess;
28bf4b0b 381 inputStream sourceFile = inputStream_undefined;
616915dd 382
383 fileIdList dercfiles;
6fcd0b1e 384 cstringList passThroughArgs = cstringList_undefined;
28bf4b0b 385 fileIdList cfiles, xfiles, lclfiles, mtfiles;
616915dd 386 clock_t before, lcltime, libtime, pptime, cptime, rstime;
387 int i = 0;
388
22367f91 389# ifdef __EMX__
390 _wildcard (&argc, &argv);
391# endif
392
80489f0a 393 g_warningstream = stdout;
394 g_messagestream = stderr;
395 g_errorstream = stderr;
616915dd 396
ce7034f0 397 (void) signal (SIGINT, llinterrupt);
398 (void) signal (SIGSEGV, llinterrupt);
616915dd 399
616915dd 400 flags_initMod ();
6fcd0b1e 401 qual_initMod ();
28bf4b0b 402 clabstract_initMod ();
616915dd 403 typeIdSet_initMod ();
53a89507 404 osd_initMod ();
6fcd0b1e 405 cppReader_initMod ();
53a89507 406
616915dd 407 setCodePoint ();
28bf4b0b 408
616915dd 409 g_currentloc = fileloc_createBuiltin ();
80489f0a 410
616915dd 411 before = clock ();
412 context_initMod ();
28bf4b0b 413
616915dd 414 context_setInCommandLine ();
415
416 if (argc <= 1)
417 {
140c27a8 418 help_showAvailableHelp ();
aa9c1601 419 llexit (LLSUCCESS);
420 }
421
422 /* -help must be the first flag to get help */
140c27a8 423 if (flagcode_isHelpFlag (flags_identifyFlag (cstring_fromChars (argv[1]))))
aa9c1601 424 {
140c27a8 425 /*
426 ** Skip first flag and help flag
427 */
428
429 help_processFlags (argc - 2, argv + 2);
aa9c1601 430 llexit (LLSUCCESS);
616915dd 431 }
432
433 setCodePoint ();
434 yydebug = 0;
435
436 /*
437 ** Add include directories from environment.
438 */
439
440 {
7272a1c1 441 cstring incval = cstring_copy (osd_getEnvironmentVariable (INCLUDEPATH_VAR));
b37cf05e 442 cstring oincval = incval;
616915dd 443
28bf4b0b 444 if (cstring_isDefined (incval))
616915dd 445 {
446 /*
447 ** Each directory on the include path is a system include directory.
448 */
449
450 DPRINTF (("include: %s", incval));
28bf4b0b 451 context_setString (FLG_SYSTEMDIRS, cstring_copy (incval));
616915dd 452
28bf4b0b 453 while (cstring_isDefined (incval))
616915dd 454 {
28bf4b0b 455 /*@access cstring@*/
7272a1c1 456 char *nextsep = strchr (incval, PATH_SEPARATOR);
616915dd 457
458 if (nextsep != NULL)
459 {
460 cstring dir;
461 *nextsep = '\0';
28bf4b0b 462 dir = cstring_copy (incval);
616915dd 463
464 if (cstring_length (dir) == 0
465 || !isalpha ((int) cstring_firstChar (dir)))
466 {
467 /*
468 ** win32 environment values can have special values,
469 ** ignore them
470 */
471 }
472 else
473 {
616915dd 474 cppAddIncludeDir (dir);
475 }
476
7272a1c1 477 *nextsep = PATH_SEPARATOR;
28bf4b0b 478 incval = cstring_fromChars (nextsep + 1);
616915dd 479 cstring_free (dir);
480 }
481 else
482 {
483 break;
484 }
28bf4b0b 485
486 /*@noaccess cstring@*/
616915dd 487 }
488 }
68de3f33 489 else /* 2001-09-09: herbert */
490 {
491 /* Put C_INCLUDE_PATH directories in sysdirs */
492 cstring cincval = osd_getEnvironmentVariable (cstring_makeLiteralTemp ("C_INCLUDE_PATH"));
aa9c1601 493
68de3f33 494 if (cstring_isDefined (cincval))
495 {
496 context_setString (FLG_SYSTEMDIRS, cstring_copy (cincval));
497 }
498 }
499 /* /herbert */
28bf4b0b 500
b37cf05e 501 cstring_free (oincval);
616915dd 502 }
503
504 /*
505 ** check RCFILE for default flags
506 */
507
140c27a8 508 /*
509 ** Process command line message formatting flags before reading rc file
510 */
511
616915dd 512 {
28bf4b0b 513 cstring home = osd_getHomeDir ();
60868d40 514 cstring fname = cstring_undefined;
616915dd 515 bool defaultf = TRUE;
516 bool nof = FALSE;
517
518 for (i = 1; i < argc; i++)
519 {
520 char *thisarg;
521 thisarg = argv[i];
522
523 if (*thisarg == '-' || *thisarg == '+')
524 {
f2b6724f 525 bool set = (*thisarg == '+');
526 flagcode opt;
527
616915dd 528 thisarg++;
a956d444 529
530 /*
531 ** Don't report warnings this time
532 */
533
534 opt = flags_identifyFlagQuiet (cstring_fromChars (thisarg));
616915dd 535
f2b6724f 536 if (opt == FLG_NOF)
616915dd 537 {
538 nof = TRUE;
539 }
80489f0a 540 else if (flagcode_isMessageControlFlag (opt))
f2b6724f 541 {
542 /*
543 ** Need to set it immediately, so rc file scan is displayed
544 */
545
546 context_userSetFlag (opt, set);
80489f0a 547
548 if (flagcode_hasArgument (opt))
549 {
550 llassert (flagcode_hasString (opt));
551
552 if (++i < argc)
553 {
554 fname = cstring_fromChars (argv[i]);
16c024b5 555 flags_setStringFlag (opt, fname);
80489f0a 556 }
557 else
558 {
140c27a8 559 voptgenerror
560 (FLG_BADFLAG,
561 message
80489f0a 562 ("Flag %s must be followed by a string",
140c27a8 563 flagcode_unparse (opt)),
564 g_currentloc);
80489f0a 565 }
566 }
f2b6724f 567 }
568 else if (opt == FLG_OPTF)
616915dd 569 {
570 if (++i < argc)
571 {
572 defaultf = FALSE;
60868d40 573 fname = cstring_fromChars (argv[i]);
140c27a8 574 (void) rcfiles_read (fname, &passThroughArgs, TRUE);
616915dd 575 }
576 else
577 llfatalerror
578 (cstring_makeLiteral ("Flag f to select options file "
579 "requires an argument"));
580 }
581 else
582 {
583 ; /* wait to process later */
584 }
585 }
586 }
f2b6724f 587
616915dd 588 setCodePoint ();
589
590 if (!nof && defaultf)
591 {
60868d40 592 /*
f2b6724f 593 ** No explicit rc file, first try reading ~/.splintrc
60868d40 594 */
616915dd 595
f2b6724f 596 if (cstring_isUndefined (fname))
60868d40 597 {
f2b6724f 598 if (!cstring_isEmpty (home))
60868d40 599 {
f2b6724f 600 bool readhomerc, readaltrc;
601 cstring homename, altname;
602
603 homename = message ("%s%h%s", home, CONNECTCHAR,
604 cstring_fromChars (RCFILE));
140c27a8 605 readhomerc = rcfiles_read (homename, &passThroughArgs, FALSE);
60868d40 606
f2b6724f 607 /*
1b8ae690 608 ** Try ~/.splintrc also for historical accuracy
f2b6724f 609 */
610
611 altname = message ("%s%h%s", home, CONNECTCHAR,
612 cstring_fromChars (ALTRCFILE));
140c27a8 613 readaltrc = rcfiles_read (altname, &passThroughArgs, FALSE);
f2b6724f 614
615 if (readhomerc && readaltrc)
616 {
617
618 voptgenerror
619 (FLG_WARNRC,
620 message ("Found both %s and %s files. Using both files, "
621 "but recommend using only %s to avoid confusion.",
622 homename, altname, homename),
623 g_currentloc);
624 }
146e25eb 625
626 cstring_free (homename);
627 cstring_free (altname);
60868d40 628 }
629 }
630
f2b6724f 631 /*
632 ** Next, read .splintrc in the current working directory
633 */
634
635 {
636 cstring rcname = message ("%s%s",osd_getCurrentDirectory (), cstring_fromChars (RCFILE));
637 cstring altname = message ("%s%s",osd_getCurrentDirectory (), cstring_fromChars (ALTRCFILE));
638 bool readrc, readaltrc;
639
140c27a8 640 readrc = rcfiles_read (rcname, &passThroughArgs, FALSE);
641 readaltrc = rcfiles_read (altname, &passThroughArgs, FALSE);
f2b6724f 642
643 if (readrc && readaltrc)
644 {
645 voptgenerror (FLG_WARNRC,
646 message ("Found both %s and %s files. Using both files, "
647 "but recommend using only %s to avoid confusion.",
648 rcname, altname, rcname),
649 g_currentloc);
650
651 }
616915dd 652
f2b6724f 653 cstring_free (rcname);
654 cstring_free (altname);
655 }
616915dd 656 }
657 }
658
659 setCodePoint ();
140c27a8 660 llassert (fileloc_isBuiltin (g_currentloc));
661
662 cfiles = fileIdList_create ();
663 xfiles = fileIdList_create ();
664 lclfiles = fileIdList_create ();
665 mtfiles = fileIdList_create ();
28bf4b0b 666
aa9c1601 667 /* argv[0] is the program name, don't pass it to flags_processFlags */
140c27a8 668 flags_processFlags (TRUE, xfiles, cfiles,
669 lclfiles, mtfiles,
670 &passThroughArgs,
671 argc - 1, argv + 1);
616915dd 672
f2b6724f 673 showHerald ();
53306cab 674
675 if (context_getFlag (FLG_CSV)) {
676 cstring fname = context_getString (FLG_CSV);
677
678 if (cstring_isDefined (fname)) {
679 if (osd_fileExists (fname) && !context_getFlag (FLG_CSVOVERWRITE)) {
680 lldiagmsg (message ("Specified CSV output file already exists (use +csvoverwrite to automatically overwrite): %s",
681 fname));
682 } else {
683 g_csvstream = fopen (cstring_toCharsSafe (fname), "w");
684
685 DPRINTF (("Creating: %s", fname));
686 if (g_csvstream == NULL) {
687 lldiagmsg (message ("Cannot open file for CSV output: %s", fname));
688 } else {
689 displayScan (message ("Starting CSV output file: %s", context_getString (FLG_CSV)));
690 fprintf (g_csvstream,
691 "Warning, Flag Code, Flag Name, Priority, File, Line, Column, Warning Text, Additional Text\n");
692 }
693 }
694 }
695 }
696
616915dd 697# ifdef DOANNOTS
698 initAnnots ();
699# endif
700
701 inittime = clock ();
702
703 context_resetErrors ();
704 context_clearInCommandLine ();
705
706 anylcl = !fileIdList_isEmpty (lclfiles);
707
708 if (context_doMerge ())
709 {
710 cstring m = context_getMerge ();
711
80489f0a 712 displayScanOpen (message ("< loading %s ", m));
616915dd 713 loadState (m);
80489f0a 714 displayScanClose ();
616915dd 715
716 if (!usymtab_existsType (context_getBoolName ()))
717 {
718 usymtab_initBool ();
719 }
720 }
721 else
722 {
723 if (!context_getFlag (FLG_NOLIB) && loadStandardState ())
724 {
725 ;
726 }
727 else
728 {
729 ctype_initTable ();
730 }
731
732 /* setup bool type and constants */
733 usymtab_initBool ();
734 }
735
736 fileloc_free (g_currentloc);
737 g_currentloc = fileloc_createBuiltin ();
738
28bf4b0b 739 /*
740 ** Read metastate files (must happen before loading libraries)
741 */
742
743 fileIdList_elements (mtfiles, mtfile)
744 {
745 context_setFileId (mtfile);
80489f0a 746 displayScan (message ("processing %s", fileTable_rootFileName (mtfile)));
4dd72714 747 mtreader_readFile (cstring_copy (fileTable_fileName (mtfile)));
28bf4b0b 748 } end_fileIdList_elements;
749
616915dd 750 libtime = clock ();
28bf4b0b 751
616915dd 752 if (anylcl)
753 {
616915dd 754 lslProcess (lclfiles);
616915dd 755 }
756
28bf4b0b 757 usymtab_initGlobalMarker ();
758
616915dd 759 /*
760 ** pre-processing
761 **
762 ** call the pre-preprocessor and /lib/cpp to generate appropriate
763 ** files
764 **
765 */
766
767 context_setInCommandLine ();
140c27a8 768
616915dd 769 DPRINTF (("Pass through: %s", cstringSList_unparse (passThroughArgs)));
770
6fcd0b1e 771 cstringList_elements (passThroughArgs, thisarg)
140c27a8 772 {
773 handlePassThroughFlag (cstring_toCharsSafe (thisarg));
774 }
6fcd0b1e 775 end_cstringList_elements;
616915dd 776
6fcd0b1e 777 cstringList_free (passThroughArgs);
616915dd 778
779 cleanupMessages ();
780
28bf4b0b 781 DPRINTF (("Initializing cpp reader!"));
782 cppReader_initialize ();
616915dd 783 cppReader_saveDefinitions ();
784
785 context_clearInCommandLine ();
786
787 if (!context_getFlag (FLG_NOPP))
788 {
28bf4b0b 789 fileIdList tfiles;
790
616915dd 791 llflush ();
792
80489f0a 793 displayScanOpen (cstring_makeLiteral ("preprocessing"));
616915dd 794
795 lcltime = clock ();
796
797 context_setPreprocessing ();
28bf4b0b 798 dercfiles = preprocessFiles (xfiles, TRUE);
799 tfiles = preprocessFiles (cfiles, FALSE);
e55c0c6d 800 warnSysFiles(cfiles);
28bf4b0b 801 dercfiles = fileIdList_append (dercfiles, tfiles);
802 fileIdList_free (tfiles);
803
616915dd 804 context_clearPreprocessing ();
805
806 fileIdList_free (cfiles);
807
80489f0a 808 displayScanClose ();
616915dd 809 pptime = clock ();
810 }
811 else
812 {
813 lcltime = clock ();
28bf4b0b 814 dercfiles = fileIdList_append (cfiles, xfiles);
616915dd 815 pptime = clock ();
816 }
28bf4b0b 817
616915dd 818 /*
819 ** now, check all the corresponding C files
820 **
821 ** (for now these are just <file>.c, but after pre-processing
822 ** will be <tmpprefix>.<file>.c)
823 */
824
abc07c2c 825 /* Why was this here? It is always a bug... */
826# if 0
616915dd 827 {
6ee276d2 828# if defined (WIN32) || defined (OS2) && defined (__IBMC__)
616915dd 829 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
830
831 if (nfiles != 0)
832 {
833 llbug (message ("Files unclosed: %d", nfiles));
834 }
835# endif
836 }
abc07c2c 837# endif
616915dd 838
28bf4b0b 839 DPRINTF (("Initializing..."));
840
616915dd 841 exprNode_initMod ();
842
28bf4b0b 843 DPRINTF (("Okay..."));
844
616915dd 845 fileIdList_elements (dercfiles, fid)
846 {
4dd72714 847 sourceFile = inputStream_create (cstring_copy (fileTable_fileName (fid)), C_EXTENSION, TRUE);
616915dd 848 context_setFileId (fid);
849
850 /* Open source file */
851
28bf4b0b 852 if (inputStream_isUndefined (sourceFile) || (!inputStream_open (sourceFile)))
616915dd 853 {
854 /* previously, this was ignored ?! */
4dd72714 855 llbug (message ("Could not open temp file: %s", fileTable_fileName (fid)));
616915dd 856 }
857 else
858 {
28bf4b0b 859 yyin = inputStream_getFile (sourceFile); /*< shared <- only */
616915dd 860
861 llassert (yyin != NULL);
862
80489f0a 863 displayScan (message ("checking %q", osd_outputPath (fileTable_rootFileName (fid))));
616915dd 864
865 /*
866 ** Every time, except the first time, through the loop,
867 ** need to call yyrestart to clean up the parse buffer.
868 */
869
870 if (!first_time)
871 {
872 (void) yyrestart (yyin);
873 }
874 else
875 {
876 first_time = FALSE;
877 }
878
28bf4b0b 879 DPRINTF (("Entering..."));
616915dd 880 context_enterFile ();
881 (void) yyparse ();
28bf4b0b 882 context_exitCFile ();
616915dd 883
28bf4b0b 884 (void) inputStream_close (sourceFile);
885 }
6fcd0b1e 886
887 inputStream_free (sourceFile); /* evans 2002-07-12: why no warning without this?!! */
616915dd 888 } end_fileIdList_elements;
889
6fcd0b1e 890 fileIdList_free (dercfiles); /* evans 2002-07-12: why no warning without this?!! */
616915dd 891 cptime = clock ();
892
893 /* process any leftover macros */
894
895 context_processAllMacros ();
896
897 /* check everything that was specified was defined */
898
899 /* don't check if no c files were processed ?
900 ** is this correct behaviour?
901 */
902
80489f0a 903 displayScan (cstring_makeLiteral ("global checks"));
616915dd 904
905 cleanupMessages ();
906
907 if (context_getLinesProcessed () > 0)
908 {
909 usymtab_allDefined ();
910 }
911
912 if (context_maybeSet (FLG_TOPUNUSED))
913 {
914 uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main"));
915
916 if (uentry_isValid (ue))
917 {
918 uentry_setUsed (ue, fileloc_observeBuiltin ());
919 }
920
921 usymtab_allUsed ();
922 }
923
924 if (context_maybeSet (FLG_EXPORTLOCAL))
925 {
926 usymtab_exportLocal ();
927 }
928
929
930 if (context_maybeSet (FLG_EXPORTHEADER))
931 {
932 usymtab_exportHeader ();
933 }
934
935 if (context_getFlag (FLG_SHOWUSES))
936 {
937 usymtab_displayAllUses ();
938 }
939
940 context_checkSuppressCounts ();
941
942 if (context_doDump ())
943 {
944 cstring dump = context_getDump ();
945
946 dumpState (dump);
947 }
948
949# ifdef DOANNOTS
950 printAnnots ();
951# endif
952
953 cleanupFiles ();
53306cab 954
955 if (g_csvstream != NULL) {
956 displayScan (message ("Closing CSV file: %s", context_getString (FLG_CSV)));
957 check (fclose (g_csvstream) == 0);
958 }
959
616915dd 960 if (context_getFlag (FLG_SHOWSUMMARY))
961 {
962 summarizeErrors ();
963 }
616915dd 964
965 {
966 bool isQuiet = context_getFlag (FLG_QUIET);
967 cstring specErrors = cstring_undefined;
616915dd 968 int nspecErrors = lclNumberErrors ();
616915dd 969
970 expsuccess = TRUE;
971
972 if (context_neednl ())
80489f0a 973 fprintf (g_warningstream, "\n");
616915dd 974
616915dd 975 if (nspecErrors > 0)
976 {
977 if (nspecErrors == context_getLCLExpect ())
978 {
979 specErrors =
11db3170 980 message ("%d spec warning%&, as expected\n ",
616915dd 981 nspecErrors);
982 }
983 else
984 {
985 if (context_getLCLExpect () > 0)
986 {
987 specErrors =
11db3170 988 message ("%d spec warning%&, expected %d\n ",
616915dd 989 nspecErrors,
990 (int) context_getLCLExpect ());
991 }
992 else
993 {
2e127cb8 994 specErrors = message ("%d spec warning%&\n ",
616915dd 995 nspecErrors);
996 expsuccess = FALSE;
997 }
998 }
999 }
1000 else
1001 {
1002 if (context_getLCLExpect () > 0)
1003 {
11db3170 1004 specErrors = message ("No spec warnings, expected %d\n ",
616915dd 1005 (int) context_getLCLExpect ());
1006 expsuccess = FALSE;
1007 }
1008 }
616915dd 1009
1010 if (context_anyErrors ())
1011 {
1012 if (context_numErrors () == context_getExpect ())
1013 {
1014 if (!isQuiet) {
11db3170 1015 llmsg (message ("Finished checking --- "
1016 "%s%d code warning%&, as expected",
616915dd 1017 specErrors, context_numErrors ()));
1018 }
1019 }
1020 else
1021 {
1022 if (context_getExpect () > 0)
1023 {
1024 if (!isQuiet) {
1025 llmsg (message
11db3170 1026 ("Finished checking --- "
1027 "%s%d code warning%&, expected %d",
616915dd 1028 specErrors, context_numErrors (),
1029 (int) context_getExpect ()));
1030 }
1031
1032 expsuccess = FALSE;
1033 }
1034 else
1035 {
1036
28bf4b0b 1037 if (!isQuiet)
1038 {
11db3170 1039 llmsg (message ("Finished checking --- "
2e127cb8 1040 "%s%d code warning%&",
28bf4b0b 1041 specErrors, context_numErrors ()));
1042 }
616915dd 1043
1044 expsuccess = FALSE;
1045 }
1046 }
1047 }
1048 else
1049 {
1050 if (context_getExpect () > 0)
1051 {
1052 if (!isQuiet) {
1053 llmsg (message
11db3170 1054 ("Finished checking --- "
1055 "%sno code warnings, expected %d",
616915dd 1056 specErrors,
1057 (int) context_getExpect ()));
1058 }
1059
1060 expsuccess = FALSE;
1061 }
1062 else
1063 {
1064 if (context_getLinesProcessed () > 0)
1065 {
11db3170 1066 if (cstring_isEmpty (specErrors))
1067 {
1068 if (!isQuiet)
1069 {
1070 llmsg (message ("Finished checking --- no warnings"));
1071 }
1072 }
1073 else
146e25eb 1074 {
11db3170 1075 if (!isQuiet)
1076 {
1077 llmsg (message ("Finished checking --- %sno code warnings",
1078 specErrors));
1079 }
146e25eb 1080 }
616915dd 1081 }
1082 else
1083 {
1084 if (!isQuiet) {
11db3170 1085 llmsg (message ("Finished checking --- %sno code processed",
616915dd 1086 specErrors));
1087 }
1088 }
1089 }
1090 }
1091
1092 cstring_free (specErrors);
909cf5eb 1093
1094 if (context_numBugs () > 0) {
1095 expsuccess = FALSE;
1096 if (!isQuiet) {
1097 llmsg (message (" %d internal bugs reported", context_numBugs ()));
1098 }
1099 }
616915dd 1100 }
1101
1102 if (context_getFlag (FLG_STATS))
1103 {
1104 clock_t ttime = clock () - before;
1105 int specLines = context_getSpecLinesProcessed ();
140c27a8 1106 cstring specmsg = cstring_undefined;
909cf5eb 1107
616915dd 1108 rstime = clock ();
1109
1110 if (specLines > 0)
1111 {
140c27a8 1112 specmsg = message ("%d spec, ", specLines);
616915dd 1113 }
1114
6fcd0b1e 1115 /* The clock might wrap around, not platform-independent easy way to deal with this... */
1116 if (ttime > 0)
1117 {
616915dd 1118# ifndef CLOCKS_PER_SEC
6fcd0b1e 1119 lldiagmsg (message ("%s%d source lines in %d time steps (steps/sec unknown)\n",
1120 specmsg,
1121 context_getLinesProcessed (),
1122 (int) ttime));
616915dd 1123# else
6fcd0b1e 1124 lldiagmsg (message ("%s%d source lines in %f s.\n",
1125 specmsg,
1126 context_getLinesProcessed (),
1127 (double) ttime / CLOCKS_PER_SEC));
1128 DPRINTF (("Time: %ld [%ld - %ld]", ttime, rstime, before));
616915dd 1129# endif
6fcd0b1e 1130 }
1131 else
1132 {
1133 lldiagmsg (message ("%s%d source lines\n",
1134 specmsg,
1135 context_getLinesProcessed ()));
1136 }
1137
616915dd 1138 }
1139 else
1140 {
1141 rstime = clock ();
1142 }
1143
1144 if (context_getFlag (FLG_TIMEDIST))
1145 {
1146 clock_t ttime = clock () - before;
1147
1148 if (ttime > 0)
1149 {
1150 char *msg = (char *) dmalloc (256 * sizeof (*msg));
1151
1152 if (anylcl)
1153 {
e5081f8c 1154 /* Gack: really should figure out how to make configure find snprintf... */
1155# ifdef WIN32
1156 (void) _snprintf (msg, 256,
1157# else
f9264521 1158 (void) snprintf (msg, 256,
e5081f8c 1159# endif
f9264521 1160 "Time distribution (percent): initialize %.2f / lcl %.2f / "
1161 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1162 (100.0 * (double) (libtime - before) / ttime),
1163 (100.0 * (double) (lcltime - libtime) / ttime),
1164 (100.0 * (double) (pptime - lcltime) / ttime),
1165 (100.0 * (double) (cptime - pptime) / ttime),
1166 (100.0 * (double) (rstime - cptime) / ttime));
616915dd 1167 }
1168 else
1169 {
e5081f8c 1170# ifdef WIN32
1171 (void) _snprintf (msg, 256,
1172# else
f9264521 1173 (void) snprintf (msg, 256,
e5081f8c 1174# endif
f9264521 1175 "Time distribution (percent): initialize %.2f / "
1176 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1177 (100.0 * (double) (libtime - before) / ttime),
1178 (100.0 * (double) (pptime - libtime) / ttime),
1179 (100.0 * (double) (cptime - pptime) / ttime),
1180 (100.0 * (double) (rstime - cptime) / ttime));
616915dd 1181 }
1182
1183 llgenindentmsgnoloc (cstring_fromCharsO (msg));
1184 }
1185 }
1186
1187 llexit (expsuccess ? LLSUCCESS : LLFAILURE);
8250fa4a 1188 BADBRANCHRET (LLFAILURE);
616915dd 1189}
1190
28bf4b0b 1191# ifdef WIN32
616915dd 1192/*
1193** Reenable return value warnings.
1194*/
28bf4b0b 1195# pragma warning (default:4035)
1196# endif
616915dd 1197
616915dd 1198void
ce7034f0 1199llinterrupt (int i)
616915dd 1200{
1201 switch (i)
1202 {
1203 case SIGINT:
80489f0a 1204 fprintf (g_errorstream, "*** Interrupt\n");
616915dd 1205 llexit (LLINTERRUPT);
1206 case SIGSEGV:
1207 {
1208 cstring loc;
1209
1210 /* Cheat when there are parse errors */
1211 checkParseError ();
1212
80489f0a 1213 fprintf (g_errorstream, "*** Segmentation Violation\n");
616915dd 1214
1215 /* Don't catch it if fileloc_unparse causes a signal */
1216 (void) signal (SIGSEGV, NULL);
1217
1218 loc = fileloc_unparse (g_currentloc);
1219
80489f0a 1220 fprintf (g_errorstream, "*** Location (not trusted): %s\n",
616915dd 1221 cstring_toCharsSafe (loc));
1222 cstring_free (loc);
1223 printCodePoint ();
b8dce3c7 1224 fprintf (g_errorstream, "*** Please report bug to %s\n*** A useful bug report should include everything we need to reproduce the bug.\n", SPLINT_MAINTAINER);
616915dd 1225 exit (LLGIVEUP);
1226 }
1227 default:
80489f0a 1228 fprintf (g_errorstream, "*** Signal: %d\n", i);
616915dd 1229 /*@-mustfree@*/
80489f0a 1230 fprintf (g_errorstream, "*** Location (not trusted): %s\n",
616915dd 1231 cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
1232 /*@=mustfree@*/
1233 printCodePoint ();
b8dce3c7 1234 fprintf (g_errorstream, "*** Please report bug to %s\n*** A useful bug report should include everything we need to reproduce the bug.", SPLINT_MAINTAINER);
616915dd 1235 exit (LLGIVEUP);
1236 }
1237}
1238
1239void
1240cleanupFiles (void)
1241{
1242 static bool doneCleanup = FALSE;
1243
1244 /* make sure this is only called once! */
1245
1246 if (doneCleanup) return;
1247
1248 setCodePoint ();
1249
dfd82dce 1250 /*
1251 ** Close all open files
1252 ** (There should only be open files, if we exited after a fatal error.)
1253 */
1254
1255 fileTable_closeAll (context_fileTable ());
1256
616915dd 1257 if (context_getFlag (FLG_KEEP))
1258 {
80489f0a 1259 check (fputs ("Temporary files kept:\n", g_messagestream) != EOF);
616915dd 1260 fileTable_printTemps (context_fileTable ());
1261 }
1262 else
1263 {
6ee276d2 1264# if defined (WIN32) || defined (OS2) && defined (__IBMC__)
616915dd 1265 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1266
1267 if (nfiles != 0)
1268 {
1269 llbug (message ("Files unclosed: %d", nfiles));
1270 }
1271# endif
1272 fileTable_cleanup (context_fileTable ());
1273 }
1274
1275 doneCleanup = TRUE;
1276}
1277
1278/*
11db3170 1279** cleans up temp files (if necessary) and exits
616915dd 1280*/
1281
27c9e640 1282/*@noreturn@*/ void
616915dd 1283llexit (int status)
1284{
1285 DPRINTF (("llexit: %d", status));
1286
6ee276d2 1287# if defined (WIN32) || defined (OS2) && defined (__IBMC__)
616915dd 1288 if (status == LLFAILURE)
1289 {
1290 _fcloseall ();
1291 }
1292# endif
1293
1294 cleanupFiles ();
1295
1296 if (status != LLFAILURE)
1297 {
6fcd0b1e 1298 usymtab_destroyMod ();
66a0043d 1299
1300 /*drl I'm commenting this line out
1301 because it is causing Splint to crash when built with
1302 2.95 I'm not sure if this is a compiler bug or if if has to do with bool
1303 Any way if we're going to exist the program why do we bother freeing stuff...
1304 */
1305 /* context_destroyMod (); */
616915dd 1306 exprNode_destroyMod ();
6fcd0b1e 1307 cppReader_destroyMod ();
616915dd 1308 sRef_destroyMod ();
1309 uentry_destroyMod ();
1310 typeIdSet_destroyMod ();
6fcd0b1e 1311 qual_destroyMod ();
1312 osd_destroyMod ();
1313 fileloc_destroyMod ();
616915dd 1314# ifdef USEDMALLOC
1315 dmalloc_shutdown ();
1316# endif
1317 }
1318
1319 exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
1320}
1321
28bf4b0b 1322static fileIdList preprocessFiles (fileIdList fl, bool xhfiles)
616915dd 1323 /*@modifies fileSystem@*/
1324{
1325 bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
1326 int skip = (fileIdList_size (fl) / 5);
1327 int filesprocessed = 0;
1328 fileIdList dfiles = fileIdList_create ();
1329
1330 fileloc_free (g_currentloc);
1331 g_currentloc = fileloc_createBuiltin ();
1332
1333 fileIdList_elements (fl, fid)
1334 {
4dd72714 1335 cstring ppfname = fileTable_fileName (fid);
616915dd 1336
53a89507 1337 if (!(osd_fileIsReadable (ppfname)))
616915dd 1338 {
146e25eb 1339 lldiagmsg (message ("Cannot open file: %q", osd_outputPath (ppfname)));
53a89507 1340 ppfname = cstring_undefined;
28bf4b0b 1341 }
1342
1343 if (cstring_isDefined (ppfname))
1344 {
1345 fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
53a89507 1346
1347 if (xhfiles)
1348 {
1349 llassert (fileTable_isXHFile (context_fileTable (), dfile));
1350 }
1351
28bf4b0b 1352 llassert (cstring_isNonEmpty (ppfname));
616915dd 1353
1354 if (msg)
1355 {
1356 if ((filesprocessed % skip) == 0)
1357 {
1358 if (filesprocessed == 0) {
ce7034f0 1359 displayScanContinue (cstring_makeLiteral (" "));
616915dd 1360 }
1361 else {
ce7034f0 1362 displayScanContinue (cstring_makeLiteral ("."));
616915dd 1363 }
616915dd 1364 }
1365 filesprocessed++;
1366 }
1367
4dd72714 1368 DPRINTF (("outfile: %s", fileTable_fileName (dfile)));
1369
1370 if (cppProcess (ppfname, fileTable_fileName (dfile)) != 0)
616915dd 1371 {
1372 llfatalerror (message ("Preprocessing error for file: %s",
4dd72714 1373 fileTable_rootFileName (fid)));
616915dd 1374 }
1375
1376 fileIdList_add (dfiles, dfile);
1377 }
1378 } end_fileIdList_elements;
6fcd0b1e 1379
1380 return dfiles;
616915dd 1381}
28bf4b0b 1382
1383/* This should be in an lclUtils.c file... */
28bf4b0b 1384char *specFullName (char *specfile, /*@out@*/ char **inpath)
1385{
1386 /* extract the path and the specname associated with the given file */
1387 char *specname = (char *) dmalloc (sizeof (*specname)
1388 * (strlen (specfile) + 9));
1389 char *ospecname = specname;
1390 char *path = (char *) dmalloc (sizeof (*path) * (strlen (specfile)));
1391 size_t size;
1392 long int i, j;
1393
1394 /* initialized path to empty string or may have accidental garbage */
1395 *path = '\0';
1396
1397 /*@-mayaliasunique@*/
1398 strcpy (specname, specfile);
1399 /*@=mayaliasunique@*/
1400
1401 /* trim off pathnames in specfile */
1402 size = strlen (specname);
1403
1404 for (i = size_toInt (size) - 1; i >= 0; i--)
1405 {
1406 if (specname[i] == CONNECTCHAR)
1407 {
1408 /* strcpy (specname, (char *)specname+i+1); */
1409 for (j = 0; j <= i; j++) /* include '/' */
1410 {
1411 path[j] = specname[j];
1412 }
1413
1414 path[i + 1] = '\0';
1415 specname += i + 1;
1416 break;
1417 }
1418 }
1419
1420 /*
1421 ** also remove .lcl file extension, assume it's the last extension
1422 ** of the file name
1423 */
1424
1425 size = strlen (specname);
1426
1427 for (i = size_toInt (size) - 1; i >= 0; i--)
1428 {
1429 if (specname[i] == '.')
1430 {
1431 specname[i] = '\0';
1432 break;
1433 }
1434 }
1435
1436 *inpath = path;
1437
1438 /*
1439 ** If specname no longer points to the original char,
1440 ** we need to allocate a new pointer and copy the string.
1441 */
1442
1443 if (specname != ospecname) {
1444 char *rspecname = (char *) dmalloc (sizeof (*rspecname) * (strlen (specname) + 1));
1445 strcpy (rspecname, specname); /* evs 2000-05-16: Bug: was ospecname! */
1446 sfree (ospecname);
1447 return rspecname;
1448 }
1449
1450 return specname;
1451}
e55c0c6d 1452
1453void warnSysFiles(fileIdList files)
1454{
1455 fileIdList_elements (files, file)
1456 {
1457
1458 if (fileTable_isSystemFile (context_fileTable (), file) )
1459 {
d0fa7de4 1460 if (!context_getFlag( FLG_SYSTEMDIRERRORS ) )
1461 {
1462 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);
1463 }
e55c0c6d 1464 }
1465 }
1466 end_fileIdList_elements;
1467}
This page took 0.316154 seconds and 5 git commands to generate.