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