]> andersk Git - splint.git/blame - src/llmain.c
Cleaned up flags to generate manual help.
[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 }
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 {
1136 setStringFlag (opt, arg);
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 {
1297 lldiagmsg (message ("< processing %s >", rootFileName (mtfile)));
1298 }
1299
1300 mtreader_readFile (cstring_copy (fileName (mtfile)));
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 {
28bf4b0b 1405 sourceFile = inputStream_create (cstring_copy (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 ?! */
1413 llbug (message ("Could not open temp file: %s", fileName (fid)));
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 {
53a89507 1423 lldiagmsg (message ("< checking %q >", osd_outputPath (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 {
1786 printFlagManual ();
1787 return TRUE;
1788 }
616915dd 1789 else
1790 {
1791 return FALSE;
1792 }
1793 }
1794 else
1795 {
1796 return FALSE;
1797 }
1798}
1799
1800void
1801printParseErrors (void)
1802{
1803 llmsglit ("Parse Errors");
1804 llmsglit ("------------");
1805 llmsglit ("");
1806 llmsglit ("LCLint will sometimes encounter a parse error for code that "
1807 "can be parsed with a local compiler. There are a few likely "
1808 "causes for this and a number of techniques that can be used "
1809 "to work around the problem.");
1810 llmsglit ("");
1811 llmsglit ("Compiler extensions --- compilers sometimes extend the C "
1812 "language with compiler-specific keywords and syntax. While "
1813 "it is not advisible to use these, oftentimes one has no choice "
1814 "when the system header files use compiler extensions. ");
1815 llmsglit ("");
11db3170 1816 llmsglit ("Splint supports some of the GNU (gcc) compiler extensions, "
616915dd 1817 "if the +gnuextensions flag is set. You may be able to workaround "
1818 "other compiler extensions by using a pre-processor define. "
1819 "Alternately, you can surround the unparseable code with");
1820 llmsglit ("");
3e3ec469 1821 llmsglit (" # ifndef S_SPLINT_S");
616915dd 1822 llmsglit (" ...");
1823 llmsglit (" # endif");
1824 llmsglit ("");
28bf4b0b 1825 /* evans 2000-12-21 fixed typo reported by Jeroen Ruigrok/Asmodai */
616915dd 1826 llmsglit ("Missing type definitions --- an undefined type name will usually "
28bf4b0b 1827 "lead to a parse error. This often occurs when a standard header "
616915dd 1828 "file defines some type that is not part of the standard library. ");
11db3170 1829 llmsglit ("By default, Splint does not process the local files corresponding "
616915dd 1830 "to standard library headers, but uses a library specification "
1831 "instead so dependencies on local system headers can be detected. "
1832 "If another system header file that does not correspond to a "
1833 "standard library header uses one of these superfluous types, "
1834 "a parse error will result.");
1835 llmsglit ("");
1836 llmsglit ("If the parse error is inside a posix standard header file, the "
11db3170 1837 "first thing to try is +posixlib. This makes Splint use "
616915dd 1838 "the posix library specification instead of reading the posix "
1839 "header files.");
1840 llmsglit ("");
1841 llmsglit ("Otherwise, you may need to either manually define the problematic "
1842 "type (e.g., add -Dmlink_t=int to your .lclintrc file) or force "
1843 "lclint to process the header file that defines it. This is done "
1844 "by setting -skipansiheaders or -skipposixheaders before "
1845 "the file that defines the type is #include'd.");
1846 llmsglit ("(See lclint -help "
1847 "skipansiheaders and lclint -help skipposixheaders for a list of "
1848 "standard headers.) For example, if <sys/local.h> uses a type "
1849 "defined by posix header <sys/types.h> but not defined by the "
1850 "posix library, we might do: ");
1851 llmsglit ("");
1852 llmsglit (" /*@-skipposixheaders@*/");
1853 llmsglit (" # include <sys/types.h>");
1854 llmsglit (" /*@=skipposixheaders@*/");
1855 llmsglit (" # include <sys/local.h>");
1856 llmsglit ("");
11db3170 1857 llmsglit ("to force Splint to process <sys/types.h>.");
616915dd 1858 llmsglit ("");
11db3170 1859 llmsglit ("At last resort, +trytorecover can be used to make Splint attempt "
616915dd 1860 "to continue after a parse error. This is usually not successful "
1861 "and the author does not consider assertion failures when +trytorecover "
1862 "is used to be bugs.");
1863}
1864
1865void
1866printAnnotations (void)
1867{
1868 llmsglit ("Annotations");
1869 llmsglit ("-----------");
1870 llmsglit ("");
28bf4b0b 1871 llmsglit ("Annotations are semantic comments that document certain "
616915dd 1872 "assumptions about functions, variables, parameters, and types. ");
1873 llmsglit ("");
1874 llmsglit ("They may be used to indicate where the representation of a "
1875 "user-defined type is hidden, to limit where a global variable may "
1876 "be used or modified, to constrain what a function implementation "
1877 "may do to its parameters, and to express checked assumptions about "
1878 "variables, types, structure fields, function parameters, and "
1879 "function results.");
1880 llmsglit ("");
1881 llmsglit ("Annotations are introduced by \"/*@\". The role of the @ may be "
1882 "played by any printable character, selected using -commentchar <char>.");
1883 llmsglit ("");
1884 llmsglit ("Consult the User's Guide for descriptions of checking associated with each annotation.");
1885 llmsglit ("");
1886 llmsglit ("Globals: (in function declarations)");
1887 llmsglit (" /*@globals <globitem>,+ @*/");
1888 llmsglit (" globitem is an identifier, internalState or fileSystem");
1889 llmsglit ("");
1890 llmsglit ("Modifies: (in function declarations)");
1891 llmsglit (" /*@modifies <moditem>,+ @*/");
1892 llmsglit (" moditem is an lvalue");
1893 llmsglit (" /*@modifies nothing @*/");
1894 llmsglit (" /*@*/ (Abbreviation for no globals and modifies nothing.)");
1895 llmsglit ("");
1896 llmsglit ("Iterators:");
1897 llmsglit (" /*@iter <identifier> (<parameter-type-list>) @*/ - declare an iterator");
1898 llmsglit ("");
1899 llmsglit ("Constants:");
1900 llmsglit (" /*@constant <declaration> @*/ - declares a constant");
1901 llmsglit ("");
1902 llmsglit ("Alternate Types:");
1903 llmsglit (" /*@alt <basic-type>,+ @*/");
1904 llmsglit (" (e.g., int /*@alt char@*/ is a type matching either int or char)");
1905 llmsglit ("");
1906 llmsglit ("Declarator Annotations");
1907 llmsglit ("");
1908 llmsglit ("Type Definitions:");
1909 llmsglit (" /*@abstract@*/ - representation is hidden from clients");
1910 llmsglit (" /*@concrete@*/ - representation is visible to clients");
1911 llmsglit (" /*@immutable@*/ - instances of the type cannot change value");
1912 llmsglit (" /*@mutable@*/ - instances of the type can change value");
1913 llmsglit (" /*@refcounted@*/ - reference counted type");
1914 llmsglit ("");
1915 llmsglit ("Global Variables:");
1916 llmsglit (" /*@unchecked@*/ - weakest checking for global use");
1917 llmsglit (" /*@checkmod@*/ - check modification by not use of global");
1918 llmsglit (" /*@checked@*/ - check use and modification of global");
1919 llmsglit (" /*@checkedstrict@*/ - check use of global strictly");
1920 llmsglit ("");
1921 llmsglit ("Memory Management:");
1922 llmsglit (" /*@dependent@*/ - a reference to externally-owned storage");
1923 llmsglit (" /*@keep@*/ - a parameter that is kept by the called function");
1924 llmsglit (" /*@killref@*/ - a refcounted parameter, killed by the call");
1925 llmsglit (" /*@only@*/ - an unshared reference");
1926 llmsglit (" /*@owned@*/ - owner of storage that may be shared by /*@dependent@*/ references");
1927 llmsglit (" /*@shared@*/ - shared reference that is never deallocated");
1928 llmsglit (" /*@temp@*/ - temporary parameter");
1929 llmsglit ("");
1930 llmsglit ("Aliasing:");
1931 llmsglit (" /*@unique@*/ - may not be aliased by any other visible reference");
1932 llmsglit (" /*@returned@*/ - may be aliased by the return value");
1933 llmsglit ("");
1934 llmsglit ("Exposure:");
1935 llmsglit (" /*@observer@*/ - reference that cannot be modified");
1936 llmsglit (" /*@exposed@*/ - exposed reference to storage in another object");
1937 llmsglit ("");
1938 llmsglit ("Definition State:");
1939 llmsglit (" /*@out@*/ - storage reachable from reference need not be defined");
1940 llmsglit (" /*@in@*/ - all storage reachable from reference must be defined");
1941 llmsglit (" /*@partial@*/ - partially defined, may have undefined fields");
1942 llmsglit (" /*@reldef@*/ - relax definition checking");
1943 llmsglit ("");
1944 llmsglit ("Global State: (for globals lists, no /*@, since list is already in /*@\'s)");
1945 llmsglit (" undef - variable is undefined before the call");
1946 llmsglit (" killed - variable is undefined after the call");
1947 llmsglit ("");
1948 llmsglit ("Null State:");
1949 llmsglit (" /*@null@*/ - possibly null pointer");
0e41eb0e 1950 llmsglit (" /*@notnull@*/ - definitely non-null pointer");
616915dd 1951 llmsglit (" /*@relnull@*/ - relax null checking");
1952 llmsglit ("");
1953 llmsglit ("Null Predicates:");
0e41eb0e 1954 llmsglit (" /*@nullwhentrue@*/ - if result is TRUE, first parameter is NULL");
1955 llmsglit (" /*@falsewhennull@*/ - if result is TRUE, first parameter is not NULL");
616915dd 1956 llmsglit ("");
1957 llmsglit ("Execution:");
27c9e640 1958 llmsglit (" /*@noreturn@*/ - function never returns");
1959 llmsglit (" /*@maynotreturn@*/ - function may or may not return");
1960 llmsglit (" /*@noreturnwhentrue@*/ - function does not return if first parameter is TRUE");
1961 llmsglit (" /*@noreturnwhenfalse@*/ - function does not return if first parameter if FALSE");
1962 llmsglit (" /*@alwaysreturns@*/ - function always returns");
616915dd 1963 llmsglit ("");
1964 llmsglit ("Side-Effects:");
1965 llmsglit (" /*@sef@*/ - corresponding actual parameter has no side effects");
1966 llmsglit ("");
1967 llmsglit ("Declaration:");
1968 llmsglit (" /*@unused@*/ - need not be used (no unused errors reported)");
1969 llmsglit (" /*@external@*/ - defined externally (no undefined error reported)");
1970 llmsglit ("");
1971 llmsglit ("Case:");
1972 llmsglit (" /*@fallthrough@*/ - fall-through case");
1973 llmsglit ("");
1974 llmsglit ("Break:");
1975 llmsglit (" /*@innerbreak@*/ - break is breaking an inner loop or switch");
1976 llmsglit (" /*@loopbreak@*/ - break is breaking a loop");
1977 llmsglit (" /*@switchbreak@*/ - break is breaking a switch");
1978 llmsglit (" /*@innercontinue@*/ - continue is continuing an inner loop");
1979 llmsglit ("");
1980 llmsglit ("Unreachable Code:");
1981 llmsglit (" /*@notreached@*/ - statement may be unreachable.");
1982 llmsglit ("");
1983 llmsglit ("Special Functions:");
1984 llmsglit (" /*@printflike@*/ - check variable arguments like printf");
1985 llmsglit (" /*@scanflike@*/ - check variable arguments like scanf");
1986}
1987
1988void
1989printComments (void)
1990{
1991 llmsglit ("Control Comments");
1992 llmsglit ("----------------");
1993 llmsglit ("");
1994 llmsglit ("Setting Flags");
1995 llmsglit ("");
1996 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.");
1997 llmsglit ("");
1998 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,");
1999 llmsglit (" /*@+boolint -modifies =showfunc@*/");
2000 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).");
2001 llmsglit ("");
2002 llmsglit ("Error Suppression");
2003 llmsglit ("");
2004 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.");
2005 llmsglit ("");
2006 llmsglit ("/*@ignore@*/ ... /*@end@*/");
2007 llgenindentmsgnoloc
2008 (cstring_makeLiteral
2009 ("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."));
2010 llmsglit ("/*@i@*/");
2011 llgenindentmsgnoloc
2012 (cstring_makeLiteral
2013 ("No errors will be reported from an /*@i@*/ comment to the end of the line."));
2014 llmsglit ("/*@i<n>@*/");
2015 llgenindentmsgnoloc
2016 (cstring_makeLiteral
11db3170 2017 ("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 2018 llmsglit ("/*@t@*/, /*@t<n>@*/");
2019 llgenindentmsgnoloc
2020 (cstring_makeLiteral
2021 ("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."));
2022 llmsglit ("");
2023 llmsglit ("Type Access");
2024 llmsglit ("");
2025 llmsglit ("/*@access <type>@*/");
2026 llmsglit (" Allows the following code to access the representation of <type>");
2027 llmsglit ("/*@noaccess <type>@*/");
2028 llmsglit (" Hides the representation of <type>");
2029 llmsglit ("");
2030 llmsglit ("Macro Expansion");
2031 llmsglit ("");
2032 llmsglit ("/*@notfunction@*/");
2033 llgenindentmsgnoloc
2034 (cstring_makeLiteral
2035 ("Indicates that the next macro definition is not intended to be a "
2036 "function, and should be expanded in line instead of checked as a "
2037 "macro function definition."));
2038}
2039
2040
2041void
2042printFlags (void)
2043{
2044 llmsglit ("Flag Categories");
2045 llmsglit ("---------------");
2046 listAllCategories ();
2047 llmsglit ("\nTo see the flags in a flag category, do\n lclint -help flags <category>");
2048 llmsglit ("To see a list of all flags in alphabetical order, do\n lclint -help flags alpha");
2049 llmsglit ("To see a full description of all flags, do\n lclint -help flags full");
2050}
2051
2052void
2053printMaintainer (void)
2054{
2055 llmsg (message ("Maintainer: %s", cstring_makeLiteralTemp (LCLINT_MAINTAINER)));
2056 llmsglit (LCL_COMPILE);
2057}
2058
2059void
2060printMail (void)
2061{
2062 llmsglit ("Mailing Lists");
2063 llmsglit ("-------------");
2064 llmsglit ("");
11db3170 2065 llmsglit ("There are two mailing lists associated with Splint: ");
616915dd 2066 llmsglit ("");
2067 llmsglit (" lclint-announce@virginia.edu");
2068 llmsglit ("");
2069 llmsglit (" Reserved for announcements of new releases and bug fixes.");
2070 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
2071 llmsglit (" subscribe lclint-announce");
2072 llmsglit ("");
2073 llmsglit (" lclint-interest@virginia.edu");
2074 llmsglit ("");
2075 llmsglit (" Informal discussions on the use and development of lclint.");
2076 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
2077 llmsglit (" subscribe lclint-interest");
2078}
2079
2080void
2081printReferences (void)
2082{
2083 llmsglit ("References");
2084 llmsglit ("----------");
2085 llmsglit ("");
11db3170 2086 llmsglit ("For more information, see the Splint web site: http://www.splint.org");
616915dd 2087}
2088
2089void
2090describePrefixCodes (void)
2091{
2092 llmsglit ("Prefix Codes");
2093 llmsglit ("------------");
2094 llmsglit ("");
2095 llmsglit ("These characters have special meaning in name prefixes:");
2096 llmsglit ("");
2097 llmsg (message (" %h Any uppercase letter [A-Z]", PFX_UPPERCASE));
2098 llmsg (message (" %h Any lowercase letter [a-z]", PFX_LOWERCASE));
2099 llmsg (message (" %h Any character (valid in a C identifier)", PFX_ANY));
2100 llmsg (message (" %h Any digit [0-9]", PFX_DIGIT));
2101 llmsg (message (" %h Any non-uppercase letter [a-z0-9_]", PFX_NOTUPPER));
2102 llmsg (message (" %h Any non-lowercase letter [A-Z0-9_]", PFX_NOTLOWER));
2103 llmsg (message (" %h Any letter [A-Za-z]", PFX_ANYLETTER));
2104 llmsg (message (" %h Any letter or digit [A-Za-z0-9]", PFX_ANYLETTERDIGIT));
2105 llmsglit (" * Zero or more repetitions of the previous character class until the end of the name");
2106}
2107
2108void
2109describeVars (void)
2110{
2111 cstring eval;
28bf4b0b 2112 cstring def;
616915dd 2113
2114 eval = context_getLarchPath ();
2115 def = osd_getEnvironmentVariable (LARCH_PATH);
2116
28bf4b0b 2117 if (cstring_isDefined (def) ||
616915dd 2118 !cstring_equal (eval, cstring_fromChars (DEFAULT_LARCHPATH)))
2119 {
2120 llmsg (message ("LARCH_PATH = %s", eval));
2121 }
2122 else
2123 {
2124 llmsg (message ("LARCH_PATH = <not set> (default = %s)",
2125 cstring_fromChars (DEFAULT_LARCHPATH)));
2126 }
2127
2128 llmsglit (" --- path used to find larch initialization files and LSL traits");
2129
2130 eval = context_getLCLImportDir ();
28bf4b0b 2131 def = osd_getEnvironmentVariable (cstring_makeLiteralTemp (LCLIMPORTDIR));
616915dd 2132
28bf4b0b 2133 if (cstring_isDefined (def) ||
616915dd 2134 !cstring_equal (eval, cstring_fromChars (DEFAULT_LCLIMPORTDIR)))
2135 {
2136 llmsg (message ("%q = %s", cstring_makeLiteral (LCLIMPORTDIR), eval));
2137 }
2138 else
2139 {
2140 llmsg (message ("%s = <not set, default: %s>", cstring_makeLiteralTemp (LCLIMPORTDIR),
2141 cstring_makeLiteralTemp (DEFAULT_LCLIMPORTDIR)));
2142 }
2143
2144 llmsglit (" --- directory containing lcl standard library files "
2145 "(import with < ... >)");;
2146
7272a1c1 2147 llmsg (message
2148 ("include path = %q (set by environment variable %s and -I flags)",
2149 cppReader_getIncludePath (), INCLUDEPATH_VAR));
616915dd 2150
7272a1c1 2151 llmsglit (" --- path used to find #include'd files");
2152
2153 llmsg (message
68de3f33 2154 ("systemdirs = %s (set by -systemdirs or environment variable %s)", /*@i413223@*/
7272a1c1 2155 context_getString (FLG_SYSTEMDIRS),
2156 INCLUDEPATH_VAR));
2157
2158 llmsglit (" --- if file is found on this path, it is treated as a system file for error reporting");
616915dd 2159}
2160
2161void
2162interrupt (int i)
2163{
2164 switch (i)
2165 {
2166 case SIGINT:
2167 fprintf (stderr, "*** Interrupt\n");
2168 llexit (LLINTERRUPT);
2169 case SIGSEGV:
2170 {
2171 cstring loc;
2172
2173 /* Cheat when there are parse errors */
2174 checkParseError ();
2175
2176 fprintf (stderr, "*** Segmentation Violation\n");
2177
2178 /* Don't catch it if fileloc_unparse causes a signal */
2179 (void) signal (SIGSEGV, NULL);
2180
2181 loc = fileloc_unparse (g_currentloc);
2182
2183 fprintf (stderr, "*** Location (not trusted): %s\n",
2184 cstring_toCharsSafe (loc));
2185 cstring_free (loc);
2186 printCodePoint ();
2187 fprintf (stderr, "*** Please report bug to %s\n", LCLINT_MAINTAINER);
2188 exit (LLGIVEUP);
2189 }
2190 default:
2191 fprintf (stderr, "*** Signal: %d\n", i);
2192 /*@-mustfree@*/
2193 fprintf (stderr, "*** Location (not trusted): %s\n",
2194 cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
2195 /*@=mustfree@*/
2196 printCodePoint ();
2197 fprintf (stderr, "*** Please report bug to %s ***\n", LCLINT_MAINTAINER);
2198 exit (LLGIVEUP);
2199 }
2200}
2201
2202void
2203cleanupFiles (void)
2204{
2205 static bool doneCleanup = FALSE;
2206
2207 /* make sure this is only called once! */
2208
2209 if (doneCleanup) return;
2210
2211 setCodePoint ();
2212
dfd82dce 2213 /*
2214 ** Close all open files
2215 ** (There should only be open files, if we exited after a fatal error.)
2216 */
2217
2218 fileTable_closeAll (context_fileTable ());
2219
616915dd 2220 if (context_getFlag (FLG_KEEP))
2221 {
2222 check (fputs ("Temporary files kept:\n", stderr) != EOF);
2223 fileTable_printTemps (context_fileTable ());
2224 }
2225 else
2226 {
2227# ifdef WIN32
2228 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
2229
2230 if (nfiles != 0)
2231 {
2232 llbug (message ("Files unclosed: %d", nfiles));
2233 }
2234# endif
2235 fileTable_cleanup (context_fileTable ());
2236 }
2237
2238 doneCleanup = TRUE;
2239}
2240
2241/*
11db3170 2242** cleans up temp files (if necessary) and exits
616915dd 2243*/
2244
27c9e640 2245/*@noreturn@*/ void
616915dd 2246llexit (int status)
2247{
2248 DPRINTF (("llexit: %d", status));
2249
2250# ifdef WIN32
2251 if (status == LLFAILURE)
2252 {
2253 _fcloseall ();
2254 }
2255# endif
2256
2257 cleanupFiles ();
2258
2259 if (status != LLFAILURE)
2260 {
2261 context_destroyMod ();
2262 exprNode_destroyMod ();
2263
2264 sRef_destroyMod ();
2265 uentry_destroyMod ();
2266 typeIdSet_destroyMod ();
2267
2268# ifdef USEDMALLOC
2269 dmalloc_shutdown ();
2270# endif
2271 }
2272
2273 exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
2274}
2275
f2b6724f 2276bool readOptionsFile (cstring fname, cstringSList *passThroughArgs, bool report)
2277{
2278 bool res = FALSE;
2279
2280 if (fileTable_exists (context_fileTable (), fname))
2281 {
2282 if (report)
2283 {
2284 voptgenerror
2285 (FLG_WARNRC,
2286 message ("Multiple attempts to read options file: %s", fname),
2287 g_currentloc);
2288 }
2289 }
2290 else
2291 {
2292 FILE *innerf = fileTable_openFile (context_fileTable (), fname, "r");
2293
2294 if (innerf != NULL)
2295 {
2296 fileloc fc = g_currentloc;
2297 g_currentloc = fileloc_createRc (fname);
2298
2299 if (context_getFlag (FLG_SHOWSCAN))
2300 {
146e25eb 2301 lldiagmsg (message ("< reading options from %q >",
f2b6724f 2302 fileloc_outputFilename (g_currentloc)));
2303 }
2304
2305 loadrc (innerf, passThroughArgs);
2306 fileloc_reallyFree (g_currentloc);
2307 g_currentloc = fc;
2308 res = TRUE;
2309 }
2310 else
2311 {
2312 if (report)
2313 {
2314 voptgenerror
2315 (FLG_WARNRC,
2316 message ("Cannot open options file: %s", fname),
2317 g_currentloc);
2318 }
2319 }
2320 }
2321
2322 return res;
2323}
2324
ee229125 2325/*
2326** This shouldn't be necessary, but Apple Darwin can't handle '"''s.
2327*/
2328
616915dd 2329void
15b3d2b2 2330loadrc (/*:open:*/ FILE *rcfile, cstringSList *passThroughArgs)
146e25eb 2331 /*@modifies rcfile@*/
b9904f57 2332 /*@ensures closed rcfile@*/
616915dd 2333{
2334 char *s = mstring_create (MAX_LINE_LENGTH);
2335 char *os = s;
f2b6724f 2336
616915dd 2337 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2338
2339 s = os;
2340
28bf4b0b 2341 while (reader_readLine (rcfile, s, MAX_LINE_LENGTH) != NULL)
616915dd 2342 {
2343 char c;
2344 bool set = FALSE;
2345 char *thisflag;
2346 flagcode opt;
2347
2348 DPRINTF (("Line: %s", s));
2349 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
616915dd 2350
28bf4b0b 2351 while (*s == ' ' || *s == '\t')
616915dd 2352 {
2353 s++;
2354 incColumn ();
2355 }
2356
2357 while (*s != '\0')
2358 {
2359 bool escaped = FALSE;
2360 bool quoted = FALSE;
2361 c = *s;
2362
2363 DPRINTF (("Process: %s", s));
2364 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2365 /* comment characters */
2366 if (c == '#' || c == ';' || c == '\n')
2367 {
2368 /*@innerbreak@*/
2369 break;
2370 }
2371
2372 if (c == '-' || c == '+')
2373 {
2374 set = (c == '+');
2375 }
2376 else
2377 {
2378 showHerald ();
ccf0a4a8 2379 voptgenerror (FLG_BADFLAG,
2380 message ("Bad flag syntax (+ or - expected, "
2381 "+ is assumed): %s",
2382 cstring_fromChars (s)),
2383 g_currentloc);
616915dd 2384 s--;
2385 set = TRUE;
2386 }
2387
2388 s++;
2389 incColumn ();
2390
2391 thisflag = s;
2392
2393 while ((c = *s) != '\0')
2394 { /* remember to handle spaces and quotes in -D and -U ... */
2395 if (escaped)
2396 {
2397 escaped = FALSE;
2398 }
2399 else if (quoted)
2400 {
2401 if (c == '\\')
2402 {
2403 escaped = TRUE;
2404 }
2405 else if (c == '\"')
2406 {
2407 quoted = FALSE;
2408 }
2409 else
2410 {
2411 ;
2412 }
2413 }
2414 else if (c == '\"')
2415 {
2416 quoted = TRUE;
2417 }
2418 else
2419 {
2420 if (c == ' ' || c == '\t' || c == '\n')
2421 {
2422 /*@innerbreak@*/ break;
2423 }
2424 }
2425
2426 s++;
2427 incColumn ();
2428 }
2429
2430 DPRINTF (("Nulling: %c", *s));
2431 *s = '\0';
2432
2433 if (mstring_isEmpty (thisflag))
2434 {
2435 llfatalerror (message ("Missing flag: %s",
2436 cstring_fromChars (os)));
2437 }
2438
2439 DPRINTF (("Flag: %s", thisflag));
2440
a956d444 2441 opt = flags_identifyFlag (cstring_fromChars (thisflag));
616915dd 2442
2443 if (flagcode_isSkip (opt))
2444 {
2445 ;
2446 }
2447 else if (flagcode_isInvalid (opt))
2448 {
28bf4b0b 2449 DPRINTF (("Invalid: %s", thisflag));
2450
616915dd 2451 if (isMode (cstring_fromChars (thisflag)))
2452 {
2453 context_setMode (cstring_fromChars (thisflag));
2454 }
2455 else
2456 {
ccf0a4a8 2457 voptgenerror (FLG_BADFLAG,
2458 message ("Unrecognized option: %s",
2459 cstring_fromChars (thisflag)),
2460 g_currentloc);
616915dd 2461 }
2462 }
2463 else
2464 {
2465 context_userSetFlag (opt, set);
2466
2467 if (flagcode_hasArgument (opt))
2468 {
2469 if (opt == FLG_HELP)
2470 {
2471 showHerald ();
ccf0a4a8 2472 voptgenerror (FLG_BADFLAG,
2473 message ("Cannot use help in rc files"),
2474 g_currentloc);
616915dd 2475 }
2476 else if (flagcode_isPassThrough (opt)) /* -D or -U */
2477 {
2478 cstring arg = cstring_fromCharsNew (thisflag);
2479 cstring_markOwned (arg);
2480 *passThroughArgs = cstringSList_add (*passThroughArgs, arg);
2481 DPRINTF (("Pass through: %s",
2482 cstringSList_unparse (*passThroughArgs)));
2483 }
2484 else if (opt == FLG_INCLUDEPATH
2485 || opt == FLG_SPECPATH)
2486 {
2487 cstring dir = cstring_suffix (cstring_fromChars (thisflag), 1); /* skip over I/S */
2488
2489 switch (opt)
2490 {
2491 case FLG_INCLUDEPATH:
2492 cppAddIncludeDir (dir);
2493 /*@switchbreak@*/ break;
2494 case FLG_SPECPATH:
2495 /*@-mustfree@*/
2496 g_localSpecPath = cstring_toCharsSafe
2497 (message ("%s:%s", cstring_fromChars (g_localSpecPath), dir));
2498 /*@=mustfree@*/
2499 /*@switchbreak@*/ break;
2500 BADDEFAULT;
2501 }
2502 }
2503 else if (flagcode_hasString (opt)
4f43223c 2504 || flagcode_hasNumber (opt)
2505 || flagcode_hasChar (opt)
616915dd 2506 || opt == FLG_INIT || opt == FLG_OPTF)
2507 {
2508 cstring extra = cstring_undefined;
2509 char *rest, *orest;
2510 char rchar;
2511
2512 *s = c;
2513 rest = mstring_copy (s);
2514 DPRINTF (("Here: rest = %s", rest));
2515 orest = rest;
2516 *s = '\0';
2517
2518 while ((rchar = *rest) != '\0'
2519 && (isspace ((int) rchar)))
2520 {
2521 rest++;
2522 s++;
2523 }
2524
2525 DPRINTF (("Yo: %s", rest));
2526
2527 while ((rchar = *rest) != '\0'
2528 && !isspace ((int) rchar))
2529 {
2530 extra = cstring_appendChar (extra, rchar);
2531 rest++;
2532 s++;
2533 }
2534
2535 DPRINTF (("Yo: %s", extra));
2536 sfree (orest);
2537
2538 if (cstring_isUndefined (extra))
2539 {
2540 showHerald ();
ccf0a4a8 2541 voptgenerror
616915dd 2542 (FLG_BADFLAG,
2543 message
2544 ("Flag %s must be followed by an argument",
ccf0a4a8 2545 flagcode_unparse (opt)),
2546 g_currentloc);
616915dd 2547 }
2548 else
2549 {
2550 s--;
2551
2552 DPRINTF (("Here we are: %s", extra));
2553
4f43223c 2554 if (flagcode_hasNumber (opt) || flagcode_hasChar (opt))
616915dd 2555 {
2556 DPRINTF (("Set value flag: %s", extra));
2557 setValueFlag (opt, extra);
616915dd 2558 }
2559 else if (opt == FLG_OPTF)
2560 {
f2b6724f 2561 (void) readOptionsFile (extra, passThroughArgs, TRUE);
616915dd 2562 }
2563 else if (opt == FLG_INIT)
2564 {
2565# ifndef NOLCL
28bf4b0b 2566 llassert (inputStream_isUndefined (initFile));
616915dd 2567
28bf4b0b 2568 initFile = inputStream_create
146e25eb 2569 (cstring_copy (extra),
28bf4b0b 2570 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
2571 FALSE);
616915dd 2572# endif
2573 }
2574 else if (flagcode_hasString (opt))
2575 {
146e25eb 2576 DPRINTF (("Here: %s", extra));
2577
2578 /*
2579 ** If it has "'s, we need to remove them.
2580 */
2581
ee229125 2582 if (cstring_firstChar (extra) == '\"')
616915dd 2583 {
ee229125 2584 if (cstring_lastChar (extra) == '\"')
616915dd 2585 {
146e25eb 2586 cstring unquoted = cstring_copyLength
2587 (cstring_toCharsSafe (cstring_suffix (extra, 1)),
2588 cstring_length (extra) - 2);
2589
2590 DPRINTF (("string flag: %s -> %s", extra, unquoted));
2591 setStringFlag (opt, unquoted);
2592 cstring_free (extra);
616915dd 2593 }
2594 else
2595 {
ccf0a4a8 2596 voptgenerror
2597 (FLG_BADFLAG,
616915dd 2598 message ("Unmatched \" in option string: %s",
ccf0a4a8 2599 extra),
2600 g_currentloc);
146e25eb 2601 setStringFlag (opt, extra);
616915dd 2602 }
2603 }
146e25eb 2604 else
2605 {
2606 DPRINTF (("No quotes: %s", extra));
2607 setStringFlag (opt, extra);
2608 }
2609
2610 extra = cstring_undefined;
616915dd 2611 }
2612 else
2613 {
616915dd 2614 BADEXIT;
2615 }
2616 }
146e25eb 2617
2618 cstring_free (extra);
616915dd 2619 }
2620 else
2621 {
2622 BADEXIT;
2623 }
2624 }
2625 }
2626
2627 *s = c;
2628 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2629 while ((c == ' ') || (c == '\t'))
2630 {
2631 c = *(++s);
2632 incColumn ();
2633 }
2634 }
2635 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2636 s = os;
2637 }
2638
2639 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2640 sfree (os);
dfd82dce 2641 check (fileTable_closeFile (context_fileTable (), rcfile));
616915dd 2642}
2643
28bf4b0b 2644static fileIdList preprocessFiles (fileIdList fl, bool xhfiles)
616915dd 2645 /*@modifies fileSystem@*/
2646{
2647 bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
2648 int skip = (fileIdList_size (fl) / 5);
2649 int filesprocessed = 0;
2650 fileIdList dfiles = fileIdList_create ();
2651
2652 fileloc_free (g_currentloc);
2653 g_currentloc = fileloc_createBuiltin ();
2654
2655 fileIdList_elements (fl, fid)
2656 {
28bf4b0b 2657 cstring ppfname = fileName (fid);
616915dd 2658
53a89507 2659 if (!(osd_fileIsReadable (ppfname)))
616915dd 2660 {
146e25eb 2661 lldiagmsg (message ("Cannot open file: %q", osd_outputPath (ppfname)));
53a89507 2662 ppfname = cstring_undefined;
28bf4b0b 2663 }
2664
2665 if (cstring_isDefined (ppfname))
2666 {
2667 fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
53a89507 2668
2669 if (xhfiles)
2670 {
2671 llassert (fileTable_isXHFile (context_fileTable (), dfile));
2672 }
2673
28bf4b0b 2674 llassert (cstring_isNonEmpty (ppfname));
616915dd 2675
2676 if (msg)
2677 {
2678 if ((filesprocessed % skip) == 0)
2679 {
2680 if (filesprocessed == 0) {
2681 fprintf (stderr, " ");
2682 }
2683 else {
2684 fprintf (stderr, ".");
2685 }
2686
2687 (void) fflush (stderr);
2688 }
2689 filesprocessed++;
2690 }
2691
28bf4b0b 2692 if (cppProcess (ppfname, fileName (dfile)) != 0)
616915dd 2693 {
2694 llfatalerror (message ("Preprocessing error for file: %s",
2695 rootFileName (fid)));
2696 }
2697
2698 fileIdList_add (dfiles, dfile);
2699 }
2700 } end_fileIdList_elements;
2701
2702 return dfiles;
2703}
28bf4b0b 2704
2705/* This should be in an lclUtils.c file... */
2706# ifndef NOLCL
2707char *specFullName (char *specfile, /*@out@*/ char **inpath)
2708{
2709 /* extract the path and the specname associated with the given file */
2710 char *specname = (char *) dmalloc (sizeof (*specname)
2711 * (strlen (specfile) + 9));
2712 char *ospecname = specname;
2713 char *path = (char *) dmalloc (sizeof (*path) * (strlen (specfile)));
2714 size_t size;
2715 long int i, j;
2716
2717 /* initialized path to empty string or may have accidental garbage */
2718 *path = '\0';
2719
2720 /*@-mayaliasunique@*/
2721 strcpy (specname, specfile);
2722 /*@=mayaliasunique@*/
2723
2724 /* trim off pathnames in specfile */
2725 size = strlen (specname);
2726
2727 for (i = size_toInt (size) - 1; i >= 0; i--)
2728 {
2729 if (specname[i] == CONNECTCHAR)
2730 {
2731 /* strcpy (specname, (char *)specname+i+1); */
2732 for (j = 0; j <= i; j++) /* include '/' */
2733 {
2734 path[j] = specname[j];
2735 }
2736
2737 path[i + 1] = '\0';
2738 specname += i + 1;
2739 break;
2740 }
2741 }
2742
2743 /*
2744 ** also remove .lcl file extension, assume it's the last extension
2745 ** of the file name
2746 */
2747
2748 size = strlen (specname);
2749
2750 for (i = size_toInt (size) - 1; i >= 0; i--)
2751 {
2752 if (specname[i] == '.')
2753 {
2754 specname[i] = '\0';
2755 break;
2756 }
2757 }
2758
2759 *inpath = path;
2760
2761 /*
2762 ** If specname no longer points to the original char,
2763 ** we need to allocate a new pointer and copy the string.
2764 */
2765
2766 if (specname != ospecname) {
2767 char *rspecname = (char *) dmalloc (sizeof (*rspecname) * (strlen (specname) + 1));
2768 strcpy (rspecname, specname); /* evs 2000-05-16: Bug: was ospecname! */
2769 sfree (ospecname);
2770 return rspecname;
2771 }
2772
2773 return specname;
2774}
2775# endif
This page took 0.46313 seconds and 5 git commands to generate.