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