]> andersk Git - splint.git/blame - src/llmain.c
unrecognizeddirective->unrecogdirective
[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**
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
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;
326 cstring fname = 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
372 /* Open source file */
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 ();
53a89507 550 lldiagmsg (message ("Cannot find file on LARCHPATH: %s", s));
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/*
619** Disable MSVC++ warning about return value. Methinks humbly lclint control
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 }
f2b6724f 801 else if (opt == FLG_SHOWSCAN || opt == FLG_WARNRC)
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 /*
849 ** Try ~/.lclintrc also for historical accuracy
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
f2b6724f 1011 if (flagcode_isSkip (opt) || opt == FLG_SHOWSCAN || opt == FLG_WARNRC)
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 }
1048 else if (flagcode_hasValue (opt))
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 }
1062 else if (opt == FLG_INCLUDEPATH || opt == FLG_SPECPATH)
1063 {
1064 cstring dir = cstring_suffix (cstring_fromChars (thisarg), 1); /* skip over I */
1065
1066 switch (opt)
1067 {
1068 case FLG_INCLUDEPATH:
1069 cppAddIncludeDir (dir);
1070 /*@switchbreak@*/ break;
1071 case FLG_SPECPATH:
1072 /*@-mustfree@*/
1073 g_localSpecPath = cstring_toCharsSafe
1074 (message ("%s%h%s",
1075 cstring_fromChars (g_localSpecPath),
7272a1c1 1076 PATH_SEPARATOR,
616915dd 1077 dir));
1078 /*@=mustfree@*/
1079 /*@switchbreak@*/ break;
1080 BADDEFAULT;
1081 }
1082 }
1083 else if (flagcode_hasString (opt)
1084 || opt == FLG_INIT || opt == FLG_OPTF)
1085 {
1086 if (++i < argc)
1087 {
1088 cstring arg = cstring_fromChars (argv[i]);
1089
1090 if (opt == FLG_OPTF)
1091 {
1092 ; /* -f already processed */
1093 }
1094 else if (opt == FLG_INIT)
1095 {
1096# ifndef NOLCL
28bf4b0b 1097 initFile = inputStream_create
1098 (arg,
1099 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
1100 FALSE);
616915dd 1101# endif
1102 break;
1103 }
1104 else
1105 {
28bf4b0b 1106 DPRINTF (("String flag: %s / %s",
1107 flagcode_unparse (opt), arg));
1108 if (opt == FLG_MTSFILE)
1109 {
1110 /*
1111 ** arg identifies mts files
1112 */
53a89507 1113 cstring tmp = message ("%s%s", arg, MTS_EXTENSION);
1114 addLarchPathFile (mtfiles, tmp);
1115 cstring_free (tmp);
1116 tmp = message ("%s%s", arg, XH_EXTENSION);
1117 addXHFile (xfiles, tmp);
1118 cstring_free (tmp);
28bf4b0b 1119 }
1120 else
1121 {
1122 setStringFlag (opt, arg);
1123 }
616915dd 1124 }
1125 }
1126 else
1127 {
1128 llfatalerror
1129 (message
1130 ("Flag %s must be followed by a string",
1131 flagcode_unparse (opt)));
1132 }
1133 }
1134 else
1135 {
1136 /* no argument */
1137 }
1138 }
1139 }
1140 }
1141 else /* its a filename */
1142 {
28bf4b0b 1143 DPRINTF (("Adding filename: %s", thisarg));
616915dd 1144 fl = cstringSList_add (fl, cstring_fromChars (thisarg));
1145 }
1146 }
1147 }
1148
1149 setCodePoint ();
f2b6724f 1150 showHerald ();
1151
616915dd 1152 /*
1153 ** create lists of C and LCL files
1154 */
1155
1156 cstringSList_elements (fl, current)
1157 {
28bf4b0b 1158 cstring ext = fileLib_getExtension (current);
1159
1160 if (cstring_isUndefined (ext))
616915dd 1161 {
1162 /* no extension --- both C and LCL with default extensions */
1163
28bf4b0b 1164 addFile (cfiles, message ("%s%s", current, C_EXTENSION));
1165 addFile (lclfiles, message ("%s%s", current, LCL_EXTENSION));
1166 }
1167 else if (cstring_equal (ext, XH_EXTENSION))
1168 {
53a89507 1169 addXHFile (xfiles, current);
28bf4b0b 1170 }
68de3f33 1171 else if (cstring_equal (ext, PP_EXTENSION))
1172 {
1173 if (!context_getFlag (FLG_NOPP))
1174 {
1175 voptgenerror
1176 (FLG_FILEEXTENSIONS,
1177 message ("File extension %s used without +nopp flag (will be processed as C source code): %s",
1178 ext, current),
1179 g_currentloc);
1180 }
1181
1182 addFile (cfiles, cstring_copy (current));
1183 }
28bf4b0b 1184 else if (cstring_equal (ext, LCL_EXTENSION))
1185 {
1186 addFile (lclfiles, cstring_copy (current));
616915dd 1187 }
28bf4b0b 1188 else if (fileLib_isCExtension (ext))
616915dd 1189 {
28bf4b0b 1190 addFile (cfiles, cstring_copy (current));
1191 }
1192 else if (cstring_equal (ext, MTS_EXTENSION))
1193 {
53a89507 1194 addLarchPathFile (mtfiles, current);
616915dd 1195 }
1196 else
1197 {
28bf4b0b 1198 voptgenerror
1199 (FLG_FILEEXTENSIONS,
1200 message ("Unrecognized file extension: %s (assuming %s is C source code)",
1201 current, ext),
1202 g_currentloc);
1203
1204 addFile (cfiles, cstring_copy (current));
616915dd 1205 }
1206 } end_cstringSList_elements;
1207
616915dd 1208 if (showhelp)
1209 {
1210 if (allhelp)
1211 {
1212 showHelp ();
1213 }
1214 fprintf (g_msgstream, "\n");
1215
1216 fileIdList_free (cfiles);
28bf4b0b 1217 fileIdList_free (xfiles);
616915dd 1218 fileIdList_free (lclfiles);
1219
1220 llexit (LLSUCCESS);
1221 }
1222
1223# ifdef DOANNOTS
1224 initAnnots ();
1225# endif
1226
1227 inittime = clock ();
1228
1229 context_resetErrors ();
1230 context_clearInCommandLine ();
1231
1232 anylcl = !fileIdList_isEmpty (lclfiles);
1233
1234 if (context_doMerge ())
1235 {
1236 cstring m = context_getMerge ();
1237
1238 if (context_getFlag (FLG_SHOWSCAN))
1239 {
1240 fprintf (g_msgstream, "< loading %s ", cstring_toCharsSafe (m));
1241 }
1242
1243 loadState (m);
1244
1245 if (context_getFlag (FLG_SHOWSCAN))
1246 {
1247 fprintf (g_msgstream, " >\n");
1248 }
1249
1250 if (!usymtab_existsType (context_getBoolName ()))
1251 {
1252 usymtab_initBool ();
1253 }
1254 }
1255 else
1256 {
1257 if (!context_getFlag (FLG_NOLIB) && loadStandardState ())
1258 {
1259 ;
1260 }
1261 else
1262 {
1263 ctype_initTable ();
1264 }
1265
1266 /* setup bool type and constants */
1267 usymtab_initBool ();
1268 }
1269
1270 fileloc_free (g_currentloc);
1271 g_currentloc = fileloc_createBuiltin ();
1272
28bf4b0b 1273 /*
1274 ** Read metastate files (must happen before loading libraries)
1275 */
1276
1277 fileIdList_elements (mtfiles, mtfile)
1278 {
1279 context_setFileId (mtfile);
1280
1281 if (context_getFlag (FLG_SHOWSCAN))
1282 {
1283 lldiagmsg (message ("< processing %s >", rootFileName (mtfile)));
1284 }
1285
1286 mtreader_readFile (cstring_copy (fileName (mtfile)));
1287 } end_fileIdList_elements;
1288
616915dd 1289 libtime = clock ();
28bf4b0b 1290
616915dd 1291 if (anylcl)
1292 {
1293# ifdef NOLCL
11db3170 1294 llfatalerror (cstring_makeLiteral ("This version of Splint does not handle LCL files."));
616915dd 1295# else
1296 lslProcess (lclfiles);
1297# endif
1298 }
1299
28bf4b0b 1300 usymtab_initGlobalMarker ();
1301
616915dd 1302 /*
1303 ** pre-processing
1304 **
1305 ** call the pre-preprocessor and /lib/cpp to generate appropriate
1306 ** files
1307 **
1308 */
1309
1310 context_setInCommandLine ();
1311
616915dd 1312 DPRINTF (("Pass through: %s", cstringSList_unparse (passThroughArgs)));
1313
1314 cstringSList_elements (passThroughArgs, thisarg) {
1315 handlePassThroughFlag (cstring_toCharsSafe (thisarg));
1316 } end_cstringSList_elements;
1317
1318 cstringSList_free (passThroughArgs);
1319
1320 cleanupMessages ();
1321
28bf4b0b 1322 DPRINTF (("Initializing cpp reader!"));
1323 cppReader_initialize ();
616915dd 1324 cppReader_saveDefinitions ();
1325
1326 context_clearInCommandLine ();
1327
1328 if (!context_getFlag (FLG_NOPP))
1329 {
28bf4b0b 1330 fileIdList tfiles;
1331
616915dd 1332 llflush ();
1333
1334 if (context_getFlag (FLG_SHOWSCAN))
1335 {
1336 fprintf (stderr, "< preprocessing");
1337 }
1338
1339 lcltime = clock ();
1340
1341 context_setPreprocessing ();
28bf4b0b 1342 dercfiles = preprocessFiles (xfiles, TRUE);
1343 tfiles = preprocessFiles (cfiles, FALSE);
1344 dercfiles = fileIdList_append (dercfiles, tfiles);
1345 fileIdList_free (tfiles);
1346
616915dd 1347 context_clearPreprocessing ();
1348
1349 fileIdList_free (cfiles);
1350
1351 if (context_getFlag (FLG_SHOWSCAN))
1352 {
1353 fprintf (stderr, " >\n");
1354 }
1355
1356 pptime = clock ();
1357 }
1358 else
1359 {
1360 lcltime = clock ();
28bf4b0b 1361 dercfiles = fileIdList_append (cfiles, xfiles);
616915dd 1362 pptime = clock ();
1363 }
28bf4b0b 1364
616915dd 1365 /*
1366 ** now, check all the corresponding C files
1367 **
1368 ** (for now these are just <file>.c, but after pre-processing
1369 ** will be <tmpprefix>.<file>.c)
1370 */
1371
1372 {
1373# ifdef WIN32
1374 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1375
1376 if (nfiles != 0)
1377 {
1378 llbug (message ("Files unclosed: %d", nfiles));
1379 }
1380# endif
1381 }
1382
28bf4b0b 1383 DPRINTF (("Initializing..."));
1384
616915dd 1385 exprNode_initMod ();
1386
28bf4b0b 1387 DPRINTF (("Okay..."));
1388
616915dd 1389 fileIdList_elements (dercfiles, fid)
1390 {
28bf4b0b 1391 sourceFile = inputStream_create (cstring_copy (fileName (fid)), C_EXTENSION, TRUE);
616915dd 1392 context_setFileId (fid);
1393
1394 /* Open source file */
1395
28bf4b0b 1396 if (inputStream_isUndefined (sourceFile) || (!inputStream_open (sourceFile)))
616915dd 1397 {
1398 /* previously, this was ignored ?! */
1399 llbug (message ("Could not open temp file: %s", fileName (fid)));
1400 }
1401 else
1402 {
28bf4b0b 1403 yyin = inputStream_getFile (sourceFile); /*< shared <- only */
616915dd 1404
1405 llassert (yyin != NULL);
1406
1407 if (context_getFlag (FLG_SHOWSCAN))
1408 {
53a89507 1409 lldiagmsg (message ("< checking %q >", osd_outputPath (rootFileName (fid))));
616915dd 1410 }
1411
1412 /*
1413 ** Every time, except the first time, through the loop,
1414 ** need to call yyrestart to clean up the parse buffer.
1415 */
1416
1417 if (!first_time)
1418 {
1419 (void) yyrestart (yyin);
1420 }
1421 else
1422 {
1423 first_time = FALSE;
1424 }
1425
28bf4b0b 1426 DPRINTF (("Entering..."));
616915dd 1427 context_enterFile ();
1428 (void) yyparse ();
28bf4b0b 1429 context_exitCFile ();
616915dd 1430
28bf4b0b 1431 (void) inputStream_close (sourceFile);
1432 }
616915dd 1433 } end_fileIdList_elements;
1434
1435 cptime = clock ();
1436
1437 /* process any leftover macros */
1438
1439 context_processAllMacros ();
1440
1441 /* check everything that was specified was defined */
1442
1443 /* don't check if no c files were processed ?
1444 ** is this correct behaviour?
1445 */
1446
1447 if (context_getFlag (FLG_SHOWSCAN))
1448 {
1449 lldiagmsg (cstring_makeLiteral ("< global checks >"));
1450 }
1451
1452 cleanupMessages ();
1453
1454 if (context_getLinesProcessed () > 0)
1455 {
1456 usymtab_allDefined ();
1457 }
1458
1459 if (context_maybeSet (FLG_TOPUNUSED))
1460 {
1461 uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main"));
1462
1463 if (uentry_isValid (ue))
1464 {
1465 uentry_setUsed (ue, fileloc_observeBuiltin ());
1466 }
1467
1468 usymtab_allUsed ();
1469 }
1470
1471 if (context_maybeSet (FLG_EXPORTLOCAL))
1472 {
1473 usymtab_exportLocal ();
1474 }
1475
1476
1477 if (context_maybeSet (FLG_EXPORTHEADER))
1478 {
1479 usymtab_exportHeader ();
1480 }
1481
1482 if (context_getFlag (FLG_SHOWUSES))
1483 {
1484 usymtab_displayAllUses ();
1485 }
1486
1487 context_checkSuppressCounts ();
1488
1489 if (context_doDump ())
1490 {
1491 cstring dump = context_getDump ();
1492
1493 dumpState (dump);
1494 }
1495
1496# ifdef DOANNOTS
1497 printAnnots ();
1498# endif
1499
1500 cleanupFiles ();
1501
1502 if (context_getFlag (FLG_SHOWSUMMARY))
1503 {
1504 summarizeErrors ();
1505 }
1506
1507
1508 {
1509 bool isQuiet = context_getFlag (FLG_QUIET);
1510 cstring specErrors = cstring_undefined;
1511# ifndef NOLCL
1512 int nspecErrors = lclNumberErrors ();
1513# endif
1514
1515 expsuccess = TRUE;
1516
1517 if (context_neednl ())
1518 fprintf (g_msgstream, "\n");
1519
1520# ifndef NOLCL
1521 if (nspecErrors > 0)
1522 {
1523 if (nspecErrors == context_getLCLExpect ())
1524 {
1525 specErrors =
11db3170 1526 message ("%d spec warning%&, as expected\n ",
616915dd 1527 nspecErrors);
1528 }
1529 else
1530 {
1531 if (context_getLCLExpect () > 0)
1532 {
1533 specErrors =
11db3170 1534 message ("%d spec warning%&, expected %d\n ",
616915dd 1535 nspecErrors,
1536 (int) context_getLCLExpect ());
1537 }
1538 else
1539 {
2e127cb8 1540 specErrors = message ("%d spec warning%&\n ",
616915dd 1541 nspecErrors);
1542 expsuccess = FALSE;
1543 }
1544 }
1545 }
1546 else
1547 {
1548 if (context_getLCLExpect () > 0)
1549 {
11db3170 1550 specErrors = message ("No spec warnings, expected %d\n ",
616915dd 1551 (int) context_getLCLExpect ());
1552 expsuccess = FALSE;
1553 }
1554 }
1555# endif
1556
1557 if (context_anyErrors ())
1558 {
1559 if (context_numErrors () == context_getExpect ())
1560 {
1561 if (!isQuiet) {
11db3170 1562 llmsg (message ("Finished checking --- "
1563 "%s%d code warning%&, as expected",
616915dd 1564 specErrors, context_numErrors ()));
1565 }
1566 }
1567 else
1568 {
1569 if (context_getExpect () > 0)
1570 {
1571 if (!isQuiet) {
1572 llmsg (message
11db3170 1573 ("Finished checking --- "
1574 "%s%d code warning%&, expected %d",
616915dd 1575 specErrors, context_numErrors (),
1576 (int) context_getExpect ()));
1577 }
1578
1579 expsuccess = FALSE;
1580 }
1581 else
1582 {
1583
28bf4b0b 1584 if (!isQuiet)
1585 {
11db3170 1586 llmsg (message ("Finished checking --- "
2e127cb8 1587 "%s%d code warning%&",
28bf4b0b 1588 specErrors, context_numErrors ()));
1589 }
616915dd 1590
1591 expsuccess = FALSE;
1592 }
1593 }
1594 }
1595 else
1596 {
1597 if (context_getExpect () > 0)
1598 {
1599 if (!isQuiet) {
1600 llmsg (message
11db3170 1601 ("Finished checking --- "
1602 "%sno code warnings, expected %d",
616915dd 1603 specErrors,
1604 (int) context_getExpect ()));
1605 }
1606
1607 expsuccess = FALSE;
1608 }
1609 else
1610 {
1611 if (context_getLinesProcessed () > 0)
1612 {
11db3170 1613 if (cstring_isEmpty (specErrors))
1614 {
1615 if (!isQuiet)
1616 {
1617 llmsg (message ("Finished checking --- no warnings"));
1618 }
1619 }
1620 else
146e25eb 1621 {
11db3170 1622 if (!isQuiet)
1623 {
1624 llmsg (message ("Finished checking --- %sno code warnings",
1625 specErrors));
1626 }
146e25eb 1627 }
616915dd 1628 }
1629 else
1630 {
1631 if (!isQuiet) {
11db3170 1632 llmsg (message ("Finished checking --- %sno code processed",
616915dd 1633 specErrors));
1634 }
1635 }
1636 }
1637 }
1638
1639 cstring_free (specErrors);
1640 }
1641
1642 if (context_getFlag (FLG_STATS))
1643 {
1644 clock_t ttime = clock () - before;
1645 int specLines = context_getSpecLinesProcessed ();
1646
1647 rstime = clock ();
1648
1649 if (specLines > 0)
1650 {
1651 fprintf (g_msgstream, "%d spec, ", specLines);
1652 }
1653
1654# ifndef CLOCKS_PER_SEC
1655 fprintf (g_msgstream, "%d source lines in %ld time steps (steps/sec unknown)\n",
1656 context_getLinesProcessed (),
1657 (long) ttime);
1658# else
1659 fprintf (g_msgstream, "%d source lines in %.2f s.\n",
1660 context_getLinesProcessed (),
1661 (double) ttime / CLOCKS_PER_SEC);
1662# endif
1663 }
1664 else
1665 {
1666 rstime = clock ();
1667 }
1668
1669 if (context_getFlag (FLG_TIMEDIST))
1670 {
1671 clock_t ttime = clock () - before;
1672
1673 if (ttime > 0)
1674 {
1675 char *msg = (char *) dmalloc (256 * sizeof (*msg));
1676
1677 if (anylcl)
1678 {
1679 sprintf (msg,
1680 "Time distribution (percent): initialize %.2f / lcl %.2f / "
1681 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1682 (100.0 * (double) (libtime - before) / ttime),
1683 (100.0 * (double) (lcltime - libtime) / ttime),
1684 (100.0 * (double) (pptime - lcltime) / ttime),
1685 (100.0 * (double) (cptime - pptime) / ttime),
1686 (100.0 * (double) (rstime - cptime) / ttime));
1687 }
1688 else
1689 {
1690 sprintf (msg,
1691 "Time distribution (percent): initialize %.2f / "
1692 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1693 (100.0 * (double) (libtime - before) / ttime),
1694 (100.0 * (double) (pptime - libtime) / ttime),
1695 (100.0 * (double) (cptime - pptime) / ttime),
1696 (100.0 * (double) (rstime - cptime) / ttime));
1697 }
1698
1699 llgenindentmsgnoloc (cstring_fromCharsO (msg));
1700 }
1701 }
1702
1703 llexit (expsuccess ? LLSUCCESS : LLFAILURE);
8250fa4a 1704 BADBRANCHRET (LLFAILURE);
616915dd 1705}
1706
28bf4b0b 1707# ifdef WIN32
616915dd 1708/*
1709** Reenable return value warnings.
1710*/
28bf4b0b 1711# pragma warning (default:4035)
1712# endif
616915dd 1713
1714void
1715showHelp (void)
1716{
1717 showHerald ();
1718
28bf4b0b 1719 llmsg (message ("Source files are .c, .h and %s files. If there is no suffix,",
1720 LCL_EXTENSION));
11db3170 1721 llmsg (message (" Splint will look for <file>.c and <file>%s.", LCL_EXTENSION));
616915dd 1722 llmsglit ("");
11db3170 1723 llmsglit ("Use splint -help <topic or flag name> for more information");
616915dd 1724 llmsglit ("");
1725 llmsglit ("Topics:");
1726 llmsglit ("");
1727 llmsglit (" annotations (describes source-code annotations)");
1728 llmsglit (" comments (describes control comments)");
1729 llmsglit (" flags (describes flag categories)");
1730 llmsglit (" flags <category> (describes flags in category)");
1731 llmsglit (" flags all (short description of all flags)");
1732 llmsglit (" flags alpha (list all flags alphabetically)");
1733 llmsglit (" flags full (full description of all flags)");
1734 llmsglit (" mail (information on mailing lists)");
1735 llmsglit (" modes (show mode settings)");
1736 llmsglit (" parseerrors (help on handling parser errors)");
1737 llmsglit (" prefixcodes (character codes in namespace prefixes)");
1738 llmsglit (" references (sources for more information)");
1739 llmsglit (" vars (environment variables)");
1740 llmsglit (" version (information on compilation, maintainer)");
1741 llmsglit ("");
1742}
1743
1744static bool
1745specialFlagsHelp (char *next)
1746{
1747 if ((next != NULL) && (*next != '-') && (*next != '+'))
1748 {
1749 if (mstring_equal (next, "alpha"))
1750 {
1751 printAlphaFlags ();
1752 return TRUE;
1753 }
1754 else if (mstring_equal (next, "all"))
1755 {
1756 printAllFlags (TRUE, FALSE);
1757 return TRUE;
1758 }
1759 else if (mstring_equal (next, "categories")
1760 || mstring_equal (next, "cats"))
1761 {
1762 listAllCategories ();
1763 return TRUE;
1764 }
1765 else if (mstring_equal (next, "full"))
1766 {
1767 printAllFlags (FALSE, TRUE);
1768 return TRUE;
1769 }
1770 else
1771 {
1772 return FALSE;
1773 }
1774 }
1775 else
1776 {
1777 return FALSE;
1778 }
1779}
1780
1781void
1782printParseErrors (void)
1783{
1784 llmsglit ("Parse Errors");
1785 llmsglit ("------------");
1786 llmsglit ("");
1787 llmsglit ("LCLint will sometimes encounter a parse error for code that "
1788 "can be parsed with a local compiler. There are a few likely "
1789 "causes for this and a number of techniques that can be used "
1790 "to work around the problem.");
1791 llmsglit ("");
1792 llmsglit ("Compiler extensions --- compilers sometimes extend the C "
1793 "language with compiler-specific keywords and syntax. While "
1794 "it is not advisible to use these, oftentimes one has no choice "
1795 "when the system header files use compiler extensions. ");
1796 llmsglit ("");
11db3170 1797 llmsglit ("Splint supports some of the GNU (gcc) compiler extensions, "
616915dd 1798 "if the +gnuextensions flag is set. You may be able to workaround "
1799 "other compiler extensions by using a pre-processor define. "
1800 "Alternately, you can surround the unparseable code with");
1801 llmsglit ("");
3e3ec469 1802 llmsglit (" # ifndef S_SPLINT_S");
616915dd 1803 llmsglit (" ...");
1804 llmsglit (" # endif");
1805 llmsglit ("");
28bf4b0b 1806 /* evans 2000-12-21 fixed typo reported by Jeroen Ruigrok/Asmodai */
616915dd 1807 llmsglit ("Missing type definitions --- an undefined type name will usually "
28bf4b0b 1808 "lead to a parse error. This often occurs when a standard header "
616915dd 1809 "file defines some type that is not part of the standard library. ");
11db3170 1810 llmsglit ("By default, Splint does not process the local files corresponding "
616915dd 1811 "to standard library headers, but uses a library specification "
1812 "instead so dependencies on local system headers can be detected. "
1813 "If another system header file that does not correspond to a "
1814 "standard library header uses one of these superfluous types, "
1815 "a parse error will result.");
1816 llmsglit ("");
1817 llmsglit ("If the parse error is inside a posix standard header file, the "
11db3170 1818 "first thing to try is +posixlib. This makes Splint use "
616915dd 1819 "the posix library specification instead of reading the posix "
1820 "header files.");
1821 llmsglit ("");
1822 llmsglit ("Otherwise, you may need to either manually define the problematic "
1823 "type (e.g., add -Dmlink_t=int to your .lclintrc file) or force "
1824 "lclint to process the header file that defines it. This is done "
1825 "by setting -skipansiheaders or -skipposixheaders before "
1826 "the file that defines the type is #include'd.");
1827 llmsglit ("(See lclint -help "
1828 "skipansiheaders and lclint -help skipposixheaders for a list of "
1829 "standard headers.) For example, if <sys/local.h> uses a type "
1830 "defined by posix header <sys/types.h> but not defined by the "
1831 "posix library, we might do: ");
1832 llmsglit ("");
1833 llmsglit (" /*@-skipposixheaders@*/");
1834 llmsglit (" # include <sys/types.h>");
1835 llmsglit (" /*@=skipposixheaders@*/");
1836 llmsglit (" # include <sys/local.h>");
1837 llmsglit ("");
11db3170 1838 llmsglit ("to force Splint to process <sys/types.h>.");
616915dd 1839 llmsglit ("");
11db3170 1840 llmsglit ("At last resort, +trytorecover can be used to make Splint attempt "
616915dd 1841 "to continue after a parse error. This is usually not successful "
1842 "and the author does not consider assertion failures when +trytorecover "
1843 "is used to be bugs.");
1844}
1845
1846void
1847printAnnotations (void)
1848{
1849 llmsglit ("Annotations");
1850 llmsglit ("-----------");
1851 llmsglit ("");
28bf4b0b 1852 llmsglit ("Annotations are semantic comments that document certain "
616915dd 1853 "assumptions about functions, variables, parameters, and types. ");
1854 llmsglit ("");
1855 llmsglit ("They may be used to indicate where the representation of a "
1856 "user-defined type is hidden, to limit where a global variable may "
1857 "be used or modified, to constrain what a function implementation "
1858 "may do to its parameters, and to express checked assumptions about "
1859 "variables, types, structure fields, function parameters, and "
1860 "function results.");
1861 llmsglit ("");
1862 llmsglit ("Annotations are introduced by \"/*@\". The role of the @ may be "
1863 "played by any printable character, selected using -commentchar <char>.");
1864 llmsglit ("");
1865 llmsglit ("Consult the User's Guide for descriptions of checking associated with each annotation.");
1866 llmsglit ("");
1867 llmsglit ("Globals: (in function declarations)");
1868 llmsglit (" /*@globals <globitem>,+ @*/");
1869 llmsglit (" globitem is an identifier, internalState or fileSystem");
1870 llmsglit ("");
1871 llmsglit ("Modifies: (in function declarations)");
1872 llmsglit (" /*@modifies <moditem>,+ @*/");
1873 llmsglit (" moditem is an lvalue");
1874 llmsglit (" /*@modifies nothing @*/");
1875 llmsglit (" /*@*/ (Abbreviation for no globals and modifies nothing.)");
1876 llmsglit ("");
1877 llmsglit ("Iterators:");
1878 llmsglit (" /*@iter <identifier> (<parameter-type-list>) @*/ - declare an iterator");
1879 llmsglit ("");
1880 llmsglit ("Constants:");
1881 llmsglit (" /*@constant <declaration> @*/ - declares a constant");
1882 llmsglit ("");
1883 llmsglit ("Alternate Types:");
1884 llmsglit (" /*@alt <basic-type>,+ @*/");
1885 llmsglit (" (e.g., int /*@alt char@*/ is a type matching either int or char)");
1886 llmsglit ("");
1887 llmsglit ("Declarator Annotations");
1888 llmsglit ("");
1889 llmsglit ("Type Definitions:");
1890 llmsglit (" /*@abstract@*/ - representation is hidden from clients");
1891 llmsglit (" /*@concrete@*/ - representation is visible to clients");
1892 llmsglit (" /*@immutable@*/ - instances of the type cannot change value");
1893 llmsglit (" /*@mutable@*/ - instances of the type can change value");
1894 llmsglit (" /*@refcounted@*/ - reference counted type");
1895 llmsglit ("");
1896 llmsglit ("Global Variables:");
1897 llmsglit (" /*@unchecked@*/ - weakest checking for global use");
1898 llmsglit (" /*@checkmod@*/ - check modification by not use of global");
1899 llmsglit (" /*@checked@*/ - check use and modification of global");
1900 llmsglit (" /*@checkedstrict@*/ - check use of global strictly");
1901 llmsglit ("");
1902 llmsglit ("Memory Management:");
1903 llmsglit (" /*@dependent@*/ - a reference to externally-owned storage");
1904 llmsglit (" /*@keep@*/ - a parameter that is kept by the called function");
1905 llmsglit (" /*@killref@*/ - a refcounted parameter, killed by the call");
1906 llmsglit (" /*@only@*/ - an unshared reference");
1907 llmsglit (" /*@owned@*/ - owner of storage that may be shared by /*@dependent@*/ references");
1908 llmsglit (" /*@shared@*/ - shared reference that is never deallocated");
1909 llmsglit (" /*@temp@*/ - temporary parameter");
1910 llmsglit ("");
1911 llmsglit ("Aliasing:");
1912 llmsglit (" /*@unique@*/ - may not be aliased by any other visible reference");
1913 llmsglit (" /*@returned@*/ - may be aliased by the return value");
1914 llmsglit ("");
1915 llmsglit ("Exposure:");
1916 llmsglit (" /*@observer@*/ - reference that cannot be modified");
1917 llmsglit (" /*@exposed@*/ - exposed reference to storage in another object");
1918 llmsglit ("");
1919 llmsglit ("Definition State:");
1920 llmsglit (" /*@out@*/ - storage reachable from reference need not be defined");
1921 llmsglit (" /*@in@*/ - all storage reachable from reference must be defined");
1922 llmsglit (" /*@partial@*/ - partially defined, may have undefined fields");
1923 llmsglit (" /*@reldef@*/ - relax definition checking");
1924 llmsglit ("");
1925 llmsglit ("Global State: (for globals lists, no /*@, since list is already in /*@\'s)");
1926 llmsglit (" undef - variable is undefined before the call");
1927 llmsglit (" killed - variable is undefined after the call");
1928 llmsglit ("");
1929 llmsglit ("Null State:");
1930 llmsglit (" /*@null@*/ - possibly null pointer");
0e41eb0e 1931 llmsglit (" /*@notnull@*/ - definitely non-null pointer");
616915dd 1932 llmsglit (" /*@relnull@*/ - relax null checking");
1933 llmsglit ("");
1934 llmsglit ("Null Predicates:");
0e41eb0e 1935 llmsglit (" /*@nullwhentrue@*/ - if result is TRUE, first parameter is NULL");
1936 llmsglit (" /*@falsewhennull@*/ - if result is TRUE, first parameter is not NULL");
616915dd 1937 llmsglit ("");
1938 llmsglit ("Execution:");
27c9e640 1939 llmsglit (" /*@noreturn@*/ - function never returns");
1940 llmsglit (" /*@maynotreturn@*/ - function may or may not return");
1941 llmsglit (" /*@noreturnwhentrue@*/ - function does not return if first parameter is TRUE");
1942 llmsglit (" /*@noreturnwhenfalse@*/ - function does not return if first parameter if FALSE");
1943 llmsglit (" /*@alwaysreturns@*/ - function always returns");
616915dd 1944 llmsglit ("");
1945 llmsglit ("Side-Effects:");
1946 llmsglit (" /*@sef@*/ - corresponding actual parameter has no side effects");
1947 llmsglit ("");
1948 llmsglit ("Declaration:");
1949 llmsglit (" /*@unused@*/ - need not be used (no unused errors reported)");
1950 llmsglit (" /*@external@*/ - defined externally (no undefined error reported)");
1951 llmsglit ("");
1952 llmsglit ("Case:");
1953 llmsglit (" /*@fallthrough@*/ - fall-through case");
1954 llmsglit ("");
1955 llmsglit ("Break:");
1956 llmsglit (" /*@innerbreak@*/ - break is breaking an inner loop or switch");
1957 llmsglit (" /*@loopbreak@*/ - break is breaking a loop");
1958 llmsglit (" /*@switchbreak@*/ - break is breaking a switch");
1959 llmsglit (" /*@innercontinue@*/ - continue is continuing an inner loop");
1960 llmsglit ("");
1961 llmsglit ("Unreachable Code:");
1962 llmsglit (" /*@notreached@*/ - statement may be unreachable.");
1963 llmsglit ("");
1964 llmsglit ("Special Functions:");
1965 llmsglit (" /*@printflike@*/ - check variable arguments like printf");
1966 llmsglit (" /*@scanflike@*/ - check variable arguments like scanf");
1967}
1968
1969void
1970printComments (void)
1971{
1972 llmsglit ("Control Comments");
1973 llmsglit ("----------------");
1974 llmsglit ("");
1975 llmsglit ("Setting Flags");
1976 llmsglit ("");
1977 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.");
1978 llmsglit ("");
1979 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,");
1980 llmsglit (" /*@+boolint -modifies =showfunc@*/");
1981 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).");
1982 llmsglit ("");
1983 llmsglit ("Error Suppression");
1984 llmsglit ("");
1985 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.");
1986 llmsglit ("");
1987 llmsglit ("/*@ignore@*/ ... /*@end@*/");
1988 llgenindentmsgnoloc
1989 (cstring_makeLiteral
1990 ("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."));
1991 llmsglit ("/*@i@*/");
1992 llgenindentmsgnoloc
1993 (cstring_makeLiteral
1994 ("No errors will be reported from an /*@i@*/ comment to the end of the line."));
1995 llmsglit ("/*@i<n>@*/");
1996 llgenindentmsgnoloc
1997 (cstring_makeLiteral
11db3170 1998 ("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 1999 llmsglit ("/*@t@*/, /*@t<n>@*/");
2000 llgenindentmsgnoloc
2001 (cstring_makeLiteral
2002 ("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."));
2003 llmsglit ("");
2004 llmsglit ("Type Access");
2005 llmsglit ("");
2006 llmsglit ("/*@access <type>@*/");
2007 llmsglit (" Allows the following code to access the representation of <type>");
2008 llmsglit ("/*@noaccess <type>@*/");
2009 llmsglit (" Hides the representation of <type>");
2010 llmsglit ("");
2011 llmsglit ("Macro Expansion");
2012 llmsglit ("");
2013 llmsglit ("/*@notfunction@*/");
2014 llgenindentmsgnoloc
2015 (cstring_makeLiteral
2016 ("Indicates that the next macro definition is not intended to be a "
2017 "function, and should be expanded in line instead of checked as a "
2018 "macro function definition."));
2019}
2020
2021
2022void
2023printFlags (void)
2024{
2025 llmsglit ("Flag Categories");
2026 llmsglit ("---------------");
2027 listAllCategories ();
2028 llmsglit ("\nTo see the flags in a flag category, do\n lclint -help flags <category>");
2029 llmsglit ("To see a list of all flags in alphabetical order, do\n lclint -help flags alpha");
2030 llmsglit ("To see a full description of all flags, do\n lclint -help flags full");
2031}
2032
2033void
2034printMaintainer (void)
2035{
2036 llmsg (message ("Maintainer: %s", cstring_makeLiteralTemp (LCLINT_MAINTAINER)));
2037 llmsglit (LCL_COMPILE);
2038}
2039
2040void
2041printMail (void)
2042{
2043 llmsglit ("Mailing Lists");
2044 llmsglit ("-------------");
2045 llmsglit ("");
11db3170 2046 llmsglit ("There are two mailing lists associated with Splint: ");
616915dd 2047 llmsglit ("");
2048 llmsglit (" lclint-announce@virginia.edu");
2049 llmsglit ("");
2050 llmsglit (" Reserved for announcements of new releases and bug fixes.");
2051 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
2052 llmsglit (" subscribe lclint-announce");
2053 llmsglit ("");
2054 llmsglit (" lclint-interest@virginia.edu");
2055 llmsglit ("");
2056 llmsglit (" Informal discussions on the use and development of lclint.");
2057 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
2058 llmsglit (" subscribe lclint-interest");
2059}
2060
2061void
2062printReferences (void)
2063{
2064 llmsglit ("References");
2065 llmsglit ("----------");
2066 llmsglit ("");
11db3170 2067 llmsglit ("For more information, see the Splint web site: http://www.splint.org");
616915dd 2068}
2069
2070void
2071describePrefixCodes (void)
2072{
2073 llmsglit ("Prefix Codes");
2074 llmsglit ("------------");
2075 llmsglit ("");
2076 llmsglit ("These characters have special meaning in name prefixes:");
2077 llmsglit ("");
2078 llmsg (message (" %h Any uppercase letter [A-Z]", PFX_UPPERCASE));
2079 llmsg (message (" %h Any lowercase letter [a-z]", PFX_LOWERCASE));
2080 llmsg (message (" %h Any character (valid in a C identifier)", PFX_ANY));
2081 llmsg (message (" %h Any digit [0-9]", PFX_DIGIT));
2082 llmsg (message (" %h Any non-uppercase letter [a-z0-9_]", PFX_NOTUPPER));
2083 llmsg (message (" %h Any non-lowercase letter [A-Z0-9_]", PFX_NOTLOWER));
2084 llmsg (message (" %h Any letter [A-Za-z]", PFX_ANYLETTER));
2085 llmsg (message (" %h Any letter or digit [A-Za-z0-9]", PFX_ANYLETTERDIGIT));
2086 llmsglit (" * Zero or more repetitions of the previous character class until the end of the name");
2087}
2088
2089void
2090describeVars (void)
2091{
2092 cstring eval;
28bf4b0b 2093 cstring def;
616915dd 2094
2095 eval = context_getLarchPath ();
2096 def = osd_getEnvironmentVariable (LARCH_PATH);
2097
28bf4b0b 2098 if (cstring_isDefined (def) ||
616915dd 2099 !cstring_equal (eval, cstring_fromChars (DEFAULT_LARCHPATH)))
2100 {
2101 llmsg (message ("LARCH_PATH = %s", eval));
2102 }
2103 else
2104 {
2105 llmsg (message ("LARCH_PATH = <not set> (default = %s)",
2106 cstring_fromChars (DEFAULT_LARCHPATH)));
2107 }
2108
2109 llmsglit (" --- path used to find larch initialization files and LSL traits");
2110
2111 eval = context_getLCLImportDir ();
28bf4b0b 2112 def = osd_getEnvironmentVariable (cstring_makeLiteralTemp (LCLIMPORTDIR));
616915dd 2113
28bf4b0b 2114 if (cstring_isDefined (def) ||
616915dd 2115 !cstring_equal (eval, cstring_fromChars (DEFAULT_LCLIMPORTDIR)))
2116 {
2117 llmsg (message ("%q = %s", cstring_makeLiteral (LCLIMPORTDIR), eval));
2118 }
2119 else
2120 {
2121 llmsg (message ("%s = <not set, default: %s>", cstring_makeLiteralTemp (LCLIMPORTDIR),
2122 cstring_makeLiteralTemp (DEFAULT_LCLIMPORTDIR)));
2123 }
2124
2125 llmsglit (" --- directory containing lcl standard library files "
2126 "(import with < ... >)");;
2127
7272a1c1 2128 llmsg (message
2129 ("include path = %q (set by environment variable %s and -I flags)",
2130 cppReader_getIncludePath (), INCLUDEPATH_VAR));
616915dd 2131
7272a1c1 2132 llmsglit (" --- path used to find #include'd files");
2133
2134 llmsg (message
68de3f33 2135 ("systemdirs = %s (set by -systemdirs or environment variable %s)", /*@i413223@*/
7272a1c1 2136 context_getString (FLG_SYSTEMDIRS),
2137 INCLUDEPATH_VAR));
2138
2139 llmsglit (" --- if file is found on this path, it is treated as a system file for error reporting");
616915dd 2140}
2141
2142void
2143interrupt (int i)
2144{
2145 switch (i)
2146 {
2147 case SIGINT:
2148 fprintf (stderr, "*** Interrupt\n");
2149 llexit (LLINTERRUPT);
2150 case SIGSEGV:
2151 {
2152 cstring loc;
2153
2154 /* Cheat when there are parse errors */
2155 checkParseError ();
2156
2157 fprintf (stderr, "*** Segmentation Violation\n");
2158
2159 /* Don't catch it if fileloc_unparse causes a signal */
2160 (void) signal (SIGSEGV, NULL);
2161
2162 loc = fileloc_unparse (g_currentloc);
2163
2164 fprintf (stderr, "*** Location (not trusted): %s\n",
2165 cstring_toCharsSafe (loc));
2166 cstring_free (loc);
2167 printCodePoint ();
2168 fprintf (stderr, "*** Please report bug to %s\n", LCLINT_MAINTAINER);
2169 exit (LLGIVEUP);
2170 }
2171 default:
2172 fprintf (stderr, "*** Signal: %d\n", i);
2173 /*@-mustfree@*/
2174 fprintf (stderr, "*** Location (not trusted): %s\n",
2175 cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
2176 /*@=mustfree@*/
2177 printCodePoint ();
2178 fprintf (stderr, "*** Please report bug to %s ***\n", LCLINT_MAINTAINER);
2179 exit (LLGIVEUP);
2180 }
2181}
2182
2183void
2184cleanupFiles (void)
2185{
2186 static bool doneCleanup = FALSE;
2187
2188 /* make sure this is only called once! */
2189
2190 if (doneCleanup) return;
2191
2192 setCodePoint ();
2193
dfd82dce 2194 /*
2195 ** Close all open files
2196 ** (There should only be open files, if we exited after a fatal error.)
2197 */
2198
2199 fileTable_closeAll (context_fileTable ());
2200
616915dd 2201 if (context_getFlag (FLG_KEEP))
2202 {
2203 check (fputs ("Temporary files kept:\n", stderr) != EOF);
2204 fileTable_printTemps (context_fileTable ());
2205 }
2206 else
2207 {
2208# ifdef WIN32
2209 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
2210
2211 if (nfiles != 0)
2212 {
2213 llbug (message ("Files unclosed: %d", nfiles));
2214 }
2215# endif
2216 fileTable_cleanup (context_fileTable ());
2217 }
2218
2219 doneCleanup = TRUE;
2220}
2221
2222/*
11db3170 2223** cleans up temp files (if necessary) and exits
616915dd 2224*/
2225
27c9e640 2226/*@noreturn@*/ void
616915dd 2227llexit (int status)
2228{
2229 DPRINTF (("llexit: %d", status));
2230
2231# ifdef WIN32
2232 if (status == LLFAILURE)
2233 {
2234 _fcloseall ();
2235 }
2236# endif
2237
2238 cleanupFiles ();
2239
2240 if (status != LLFAILURE)
2241 {
2242 context_destroyMod ();
2243 exprNode_destroyMod ();
2244
2245 sRef_destroyMod ();
2246 uentry_destroyMod ();
2247 typeIdSet_destroyMod ();
2248
2249# ifdef USEDMALLOC
2250 dmalloc_shutdown ();
2251# endif
2252 }
2253
2254 exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
2255}
2256
f2b6724f 2257bool readOptionsFile (cstring fname, cstringSList *passThroughArgs, bool report)
2258{
2259 bool res = FALSE;
2260
2261 if (fileTable_exists (context_fileTable (), fname))
2262 {
2263 if (report)
2264 {
2265 voptgenerror
2266 (FLG_WARNRC,
2267 message ("Multiple attempts to read options file: %s", fname),
2268 g_currentloc);
2269 }
2270 }
2271 else
2272 {
2273 FILE *innerf = fileTable_openFile (context_fileTable (), fname, "r");
2274
2275 if (innerf != NULL)
2276 {
2277 fileloc fc = g_currentloc;
2278 g_currentloc = fileloc_createRc (fname);
2279
2280 if (context_getFlag (FLG_SHOWSCAN))
2281 {
146e25eb 2282 lldiagmsg (message ("< reading options from %q >",
f2b6724f 2283 fileloc_outputFilename (g_currentloc)));
2284 }
2285
2286 loadrc (innerf, passThroughArgs);
2287 fileloc_reallyFree (g_currentloc);
2288 g_currentloc = fc;
2289 res = TRUE;
2290 }
2291 else
2292 {
2293 if (report)
2294 {
2295 voptgenerror
2296 (FLG_WARNRC,
2297 message ("Cannot open options file: %s", fname),
2298 g_currentloc);
2299 }
2300 }
2301 }
2302
2303 return res;
2304}
2305
ee229125 2306/*
2307** This shouldn't be necessary, but Apple Darwin can't handle '"''s.
2308*/
2309
616915dd 2310void
15b3d2b2 2311loadrc (/*:open:*/ FILE *rcfile, cstringSList *passThroughArgs)
146e25eb 2312 /*@modifies rcfile@*/
b9904f57 2313 /*@ensures closed rcfile@*/
616915dd 2314{
2315 char *s = mstring_create (MAX_LINE_LENGTH);
2316 char *os = s;
f2b6724f 2317
616915dd 2318 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2319
2320 s = os;
2321
28bf4b0b 2322 while (reader_readLine (rcfile, s, MAX_LINE_LENGTH) != NULL)
616915dd 2323 {
2324 char c;
2325 bool set = FALSE;
2326 char *thisflag;
2327 flagcode opt;
2328
2329 DPRINTF (("Line: %s", s));
2330 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
616915dd 2331
28bf4b0b 2332 while (*s == ' ' || *s == '\t')
616915dd 2333 {
2334 s++;
2335 incColumn ();
2336 }
2337
2338 while (*s != '\0')
2339 {
2340 bool escaped = FALSE;
2341 bool quoted = FALSE;
2342 c = *s;
2343
2344 DPRINTF (("Process: %s", s));
2345 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2346 /* comment characters */
2347 if (c == '#' || c == ';' || c == '\n')
2348 {
2349 /*@innerbreak@*/
2350 break;
2351 }
2352
2353 if (c == '-' || c == '+')
2354 {
2355 set = (c == '+');
2356 }
2357 else
2358 {
2359 showHerald ();
ccf0a4a8 2360 voptgenerror (FLG_BADFLAG,
2361 message ("Bad flag syntax (+ or - expected, "
2362 "+ is assumed): %s",
2363 cstring_fromChars (s)),
2364 g_currentloc);
616915dd 2365 s--;
2366 set = TRUE;
2367 }
2368
2369 s++;
2370 incColumn ();
2371
2372 thisflag = s;
2373
2374 while ((c = *s) != '\0')
2375 { /* remember to handle spaces and quotes in -D and -U ... */
2376 if (escaped)
2377 {
2378 escaped = FALSE;
2379 }
2380 else if (quoted)
2381 {
2382 if (c == '\\')
2383 {
2384 escaped = TRUE;
2385 }
2386 else if (c == '\"')
2387 {
2388 quoted = FALSE;
2389 }
2390 else
2391 {
2392 ;
2393 }
2394 }
2395 else if (c == '\"')
2396 {
2397 quoted = TRUE;
2398 }
2399 else
2400 {
2401 if (c == ' ' || c == '\t' || c == '\n')
2402 {
2403 /*@innerbreak@*/ break;
2404 }
2405 }
2406
2407 s++;
2408 incColumn ();
2409 }
2410
2411 DPRINTF (("Nulling: %c", *s));
2412 *s = '\0';
2413
2414 if (mstring_isEmpty (thisflag))
2415 {
2416 llfatalerror (message ("Missing flag: %s",
2417 cstring_fromChars (os)));
2418 }
2419
2420 DPRINTF (("Flag: %s", thisflag));
2421
a956d444 2422 opt = flags_identifyFlag (cstring_fromChars (thisflag));
616915dd 2423
2424 if (flagcode_isSkip (opt))
2425 {
2426 ;
2427 }
2428 else if (flagcode_isInvalid (opt))
2429 {
28bf4b0b 2430 DPRINTF (("Invalid: %s", thisflag));
2431
616915dd 2432 if (isMode (cstring_fromChars (thisflag)))
2433 {
2434 context_setMode (cstring_fromChars (thisflag));
2435 }
2436 else
2437 {
ccf0a4a8 2438 voptgenerror (FLG_BADFLAG,
2439 message ("Unrecognized option: %s",
2440 cstring_fromChars (thisflag)),
2441 g_currentloc);
616915dd 2442 }
2443 }
2444 else
2445 {
2446 context_userSetFlag (opt, set);
2447
2448 if (flagcode_hasArgument (opt))
2449 {
2450 if (opt == FLG_HELP)
2451 {
2452 showHerald ();
ccf0a4a8 2453 voptgenerror (FLG_BADFLAG,
2454 message ("Cannot use help in rc files"),
2455 g_currentloc);
616915dd 2456 }
2457 else if (flagcode_isPassThrough (opt)) /* -D or -U */
2458 {
2459 cstring arg = cstring_fromCharsNew (thisflag);
2460 cstring_markOwned (arg);
2461 *passThroughArgs = cstringSList_add (*passThroughArgs, arg);
2462 DPRINTF (("Pass through: %s",
2463 cstringSList_unparse (*passThroughArgs)));
2464 }
2465 else if (opt == FLG_INCLUDEPATH
2466 || opt == FLG_SPECPATH)
2467 {
2468 cstring dir = cstring_suffix (cstring_fromChars (thisflag), 1); /* skip over I/S */
2469
2470 switch (opt)
2471 {
2472 case FLG_INCLUDEPATH:
2473 cppAddIncludeDir (dir);
2474 /*@switchbreak@*/ break;
2475 case FLG_SPECPATH:
2476 /*@-mustfree@*/
2477 g_localSpecPath = cstring_toCharsSafe
2478 (message ("%s:%s", cstring_fromChars (g_localSpecPath), dir));
2479 /*@=mustfree@*/
2480 /*@switchbreak@*/ break;
2481 BADDEFAULT;
2482 }
2483 }
2484 else if (flagcode_hasString (opt)
2485 || flagcode_hasValue (opt)
2486 || opt == FLG_INIT || opt == FLG_OPTF)
2487 {
2488 cstring extra = cstring_undefined;
2489 char *rest, *orest;
2490 char rchar;
2491
2492 *s = c;
2493 rest = mstring_copy (s);
2494 DPRINTF (("Here: rest = %s", rest));
2495 orest = rest;
2496 *s = '\0';
2497
2498 while ((rchar = *rest) != '\0'
2499 && (isspace ((int) rchar)))
2500 {
2501 rest++;
2502 s++;
2503 }
2504
2505 DPRINTF (("Yo: %s", rest));
2506
2507 while ((rchar = *rest) != '\0'
2508 && !isspace ((int) rchar))
2509 {
2510 extra = cstring_appendChar (extra, rchar);
2511 rest++;
2512 s++;
2513 }
2514
2515 DPRINTF (("Yo: %s", extra));
2516 sfree (orest);
2517
2518 if (cstring_isUndefined (extra))
2519 {
2520 showHerald ();
ccf0a4a8 2521 voptgenerror
616915dd 2522 (FLG_BADFLAG,
2523 message
2524 ("Flag %s must be followed by an argument",
ccf0a4a8 2525 flagcode_unparse (opt)),
2526 g_currentloc);
616915dd 2527 }
2528 else
2529 {
2530 s--;
2531
2532 DPRINTF (("Here we are: %s", extra));
2533
2534 if (flagcode_hasValue (opt))
2535 {
2536 DPRINTF (("Set value flag: %s", extra));
2537 setValueFlag (opt, extra);
616915dd 2538 }
2539 else if (opt == FLG_OPTF)
2540 {
f2b6724f 2541 (void) readOptionsFile (extra, passThroughArgs, TRUE);
616915dd 2542 }
2543 else if (opt == FLG_INIT)
2544 {
2545# ifndef NOLCL
28bf4b0b 2546 llassert (inputStream_isUndefined (initFile));
616915dd 2547
28bf4b0b 2548 initFile = inputStream_create
146e25eb 2549 (cstring_copy (extra),
28bf4b0b 2550 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
2551 FALSE);
616915dd 2552# endif
2553 }
2554 else if (flagcode_hasString (opt))
2555 {
146e25eb 2556 DPRINTF (("Here: %s", extra));
2557
2558 /*
2559 ** If it has "'s, we need to remove them.
2560 */
2561
ee229125 2562 if (cstring_firstChar (extra) == '\"')
616915dd 2563 {
ee229125 2564 if (cstring_lastChar (extra) == '\"')
616915dd 2565 {
146e25eb 2566 cstring unquoted = cstring_copyLength
2567 (cstring_toCharsSafe (cstring_suffix (extra, 1)),
2568 cstring_length (extra) - 2);
2569
2570 DPRINTF (("string flag: %s -> %s", extra, unquoted));
2571 setStringFlag (opt, unquoted);
2572 cstring_free (extra);
616915dd 2573 }
2574 else
2575 {
ccf0a4a8 2576 voptgenerror
2577 (FLG_BADFLAG,
616915dd 2578 message ("Unmatched \" in option string: %s",
ccf0a4a8 2579 extra),
2580 g_currentloc);
146e25eb 2581 setStringFlag (opt, extra);
616915dd 2582 }
2583 }
146e25eb 2584 else
2585 {
2586 DPRINTF (("No quotes: %s", extra));
2587 setStringFlag (opt, extra);
2588 }
2589
2590 extra = cstring_undefined;
616915dd 2591 }
2592 else
2593 {
616915dd 2594 BADEXIT;
2595 }
2596 }
146e25eb 2597
2598 cstring_free (extra);
616915dd 2599 }
2600 else
2601 {
2602 BADEXIT;
2603 }
2604 }
2605 }
2606
2607 *s = c;
2608 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2609 while ((c == ' ') || (c == '\t'))
2610 {
2611 c = *(++s);
2612 incColumn ();
2613 }
2614 }
2615 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2616 s = os;
2617 }
2618
2619 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2620 sfree (os);
dfd82dce 2621 check (fileTable_closeFile (context_fileTable (), rcfile));
616915dd 2622}
2623
28bf4b0b 2624static fileIdList preprocessFiles (fileIdList fl, bool xhfiles)
616915dd 2625 /*@modifies fileSystem@*/
2626{
2627 bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
2628 int skip = (fileIdList_size (fl) / 5);
2629 int filesprocessed = 0;
2630 fileIdList dfiles = fileIdList_create ();
2631
2632 fileloc_free (g_currentloc);
2633 g_currentloc = fileloc_createBuiltin ();
2634
2635 fileIdList_elements (fl, fid)
2636 {
28bf4b0b 2637 cstring ppfname = fileName (fid);
616915dd 2638
53a89507 2639 if (!(osd_fileIsReadable (ppfname)))
616915dd 2640 {
146e25eb 2641 lldiagmsg (message ("Cannot open file: %q", osd_outputPath (ppfname)));
53a89507 2642 ppfname = cstring_undefined;
28bf4b0b 2643 }
2644
2645 if (cstring_isDefined (ppfname))
2646 {
2647 fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
53a89507 2648
2649 if (xhfiles)
2650 {
2651 llassert (fileTable_isXHFile (context_fileTable (), dfile));
2652 }
2653
28bf4b0b 2654 llassert (cstring_isNonEmpty (ppfname));
616915dd 2655
2656 if (msg)
2657 {
2658 if ((filesprocessed % skip) == 0)
2659 {
2660 if (filesprocessed == 0) {
2661 fprintf (stderr, " ");
2662 }
2663 else {
2664 fprintf (stderr, ".");
2665 }
2666
2667 (void) fflush (stderr);
2668 }
2669 filesprocessed++;
2670 }
2671
28bf4b0b 2672 if (cppProcess (ppfname, fileName (dfile)) != 0)
616915dd 2673 {
2674 llfatalerror (message ("Preprocessing error for file: %s",
2675 rootFileName (fid)));
2676 }
2677
2678 fileIdList_add (dfiles, dfile);
2679 }
2680 } end_fileIdList_elements;
2681
2682 return dfiles;
2683}
28bf4b0b 2684
2685/* This should be in an lclUtils.c file... */
2686# ifndef NOLCL
2687char *specFullName (char *specfile, /*@out@*/ char **inpath)
2688{
2689 /* extract the path and the specname associated with the given file */
2690 char *specname = (char *) dmalloc (sizeof (*specname)
2691 * (strlen (specfile) + 9));
2692 char *ospecname = specname;
2693 char *path = (char *) dmalloc (sizeof (*path) * (strlen (specfile)));
2694 size_t size;
2695 long int i, j;
2696
2697 /* initialized path to empty string or may have accidental garbage */
2698 *path = '\0';
2699
2700 /*@-mayaliasunique@*/
2701 strcpy (specname, specfile);
2702 /*@=mayaliasunique@*/
2703
2704 /* trim off pathnames in specfile */
2705 size = strlen (specname);
2706
2707 for (i = size_toInt (size) - 1; i >= 0; i--)
2708 {
2709 if (specname[i] == CONNECTCHAR)
2710 {
2711 /* strcpy (specname, (char *)specname+i+1); */
2712 for (j = 0; j <= i; j++) /* include '/' */
2713 {
2714 path[j] = specname[j];
2715 }
2716
2717 path[i + 1] = '\0';
2718 specname += i + 1;
2719 break;
2720 }
2721 }
2722
2723 /*
2724 ** also remove .lcl file extension, assume it's the last extension
2725 ** of the file name
2726 */
2727
2728 size = strlen (specname);
2729
2730 for (i = size_toInt (size) - 1; i >= 0; i--)
2731 {
2732 if (specname[i] == '.')
2733 {
2734 specname[i] = '\0';
2735 break;
2736 }
2737 }
2738
2739 *inpath = path;
2740
2741 /*
2742 ** If specname no longer points to the original char,
2743 ** we need to allocate a new pointer and copy the string.
2744 */
2745
2746 if (specname != ospecname) {
2747 char *rspecname = (char *) dmalloc (sizeof (*rspecname) * (strlen (specname) + 1));
2748 strcpy (rspecname, specname); /* evs 2000-05-16: Bug: was ospecname! */
2749 sfree (ospecname);
2750 return rspecname;
2751 }
2752
2753 return specname;
2754}
2755# endif
This page took 0.453245 seconds and 5 git commands to generate.