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