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