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