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