]> andersk Git - splint.git/blame - src/llmain.c
Added splint.spec file contributed by Heiko Abraham
[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;
616915dd 653 bool expsuccess;
28bf4b0b 654 inputStream sourceFile = inputStream_undefined;
616915dd 655
656 fileIdList dercfiles;
657 cstringSList fl = cstringSList_undefined;
658 cstringSList passThroughArgs = cstringSList_undefined;
28bf4b0b 659 fileIdList cfiles, xfiles, lclfiles, mtfiles;
616915dd 660 clock_t before, lcltime, libtime, pptime, cptime, rstime;
661 int i = 0;
662
22367f91 663# ifdef __EMX__
664 _wildcard (&argc, &argv);
665# endif
666
80489f0a 667 g_warningstream = stdout;
668 g_messagestream = stderr;
669 g_errorstream = stderr;
616915dd 670
671 (void) signal (SIGINT, interrupt);
672 (void) signal (SIGSEGV, interrupt);
673
674 cfiles = fileIdList_create ();
28bf4b0b 675 xfiles = fileIdList_create ();
616915dd 676 lclfiles = fileIdList_create ();
28bf4b0b 677 mtfiles = fileIdList_create ();
616915dd 678
679 flags_initMod ();
28bf4b0b 680 clabstract_initMod ();
616915dd 681 typeIdSet_initMod ();
682 cppReader_initMod ();
53a89507 683 osd_initMod ();
684
616915dd 685 setCodePoint ();
28bf4b0b 686
616915dd 687 g_currentloc = fileloc_createBuiltin ();
80489f0a 688
616915dd 689 before = clock ();
690 context_initMod ();
28bf4b0b 691
616915dd 692 context_setInCommandLine ();
693
694 if (argc <= 1)
695 {
696 showHelp ();
aa9c1601 697 llexit (LLSUCCESS);
698 }
699
700 /* -help must be the first flag to get help */
701 if (flagcode_isHelpFlag (flags_identifyFlag (argv[1])))
702 {
703 flags_processHelp (argc - 1, argv + 1);
704 llexit (LLSUCCESS);
616915dd 705 }
706
707 setCodePoint ();
708 yydebug = 0;
709
710 /*
711 ** Add include directories from environment.
712 */
713
714 {
7272a1c1 715 cstring incval = cstring_copy (osd_getEnvironmentVariable (INCLUDEPATH_VAR));
b37cf05e 716 cstring oincval = incval;
616915dd 717
28bf4b0b 718 if (cstring_isDefined (incval))
616915dd 719 {
720 /*
721 ** Each directory on the include path is a system include directory.
722 */
723
724 DPRINTF (("include: %s", incval));
28bf4b0b 725 context_setString (FLG_SYSTEMDIRS, cstring_copy (incval));
616915dd 726
28bf4b0b 727 while (cstring_isDefined (incval))
616915dd 728 {
28bf4b0b 729 /*@access cstring@*/
7272a1c1 730 char *nextsep = strchr (incval, PATH_SEPARATOR);
616915dd 731
732 if (nextsep != NULL)
733 {
734 cstring dir;
735 *nextsep = '\0';
28bf4b0b 736 dir = cstring_copy (incval);
616915dd 737
738 if (cstring_length (dir) == 0
739 || !isalpha ((int) cstring_firstChar (dir)))
740 {
741 /*
742 ** win32 environment values can have special values,
743 ** ignore them
744 */
745 }
746 else
747 {
616915dd 748 cppAddIncludeDir (dir);
749 }
750
7272a1c1 751 *nextsep = PATH_SEPARATOR;
28bf4b0b 752 incval = cstring_fromChars (nextsep + 1);
616915dd 753 cstring_free (dir);
754 }
755 else
756 {
757 break;
758 }
28bf4b0b 759
760 /*@noaccess cstring@*/
616915dd 761 }
762 }
68de3f33 763 else /* 2001-09-09: herbert */
764 {
765 /* Put C_INCLUDE_PATH directories in sysdirs */
766 cstring cincval = osd_getEnvironmentVariable (cstring_makeLiteralTemp ("C_INCLUDE_PATH"));
aa9c1601 767
68de3f33 768 if (cstring_isDefined (cincval))
769 {
770 context_setString (FLG_SYSTEMDIRS, cstring_copy (cincval));
771 }
772 }
773 /* /herbert */
28bf4b0b 774
b37cf05e 775 cstring_free (oincval);
616915dd 776 }
777
778 /*
779 ** check RCFILE for default flags
780 */
781
782 {
28bf4b0b 783 cstring home = osd_getHomeDir ();
60868d40 784 cstring fname = cstring_undefined;
616915dd 785 bool defaultf = TRUE;
786 bool nof = FALSE;
787
788 for (i = 1; i < argc; i++)
789 {
790 char *thisarg;
791 thisarg = argv[i];
792
793 if (*thisarg == '-' || *thisarg == '+')
794 {
f2b6724f 795 bool set = (*thisarg == '+');
796 flagcode opt;
797
616915dd 798 thisarg++;
a956d444 799
800 /*
801 ** Don't report warnings this time
802 */
803
804 opt = flags_identifyFlagQuiet (cstring_fromChars (thisarg));
616915dd 805
f2b6724f 806 if (opt == FLG_NOF)
616915dd 807 {
808 nof = TRUE;
809 }
80489f0a 810 else if (flagcode_isMessageControlFlag (opt))
f2b6724f 811 {
812 /*
813 ** Need to set it immediately, so rc file scan is displayed
814 */
815
816 context_userSetFlag (opt, set);
80489f0a 817
818 if (flagcode_hasArgument (opt))
819 {
820 llassert (flagcode_hasString (opt));
821
822 if (++i < argc)
823 {
824 fname = cstring_fromChars (argv[i]);
825 setStringFlag (opt, fname);
826 }
827 else
828 {
829 llfatalerror
830 (message
831 ("Flag %s must be followed by a string",
832 flagcode_unparse (opt)));
833 }
834 }
f2b6724f 835 }
836 else if (opt == FLG_OPTF)
616915dd 837 {
838 if (++i < argc)
839 {
840 defaultf = FALSE;
60868d40 841 fname = cstring_fromChars (argv[i]);
146e25eb 842 (void) readOptionsFile (fname, &passThroughArgs, TRUE);
616915dd 843 }
844 else
845 llfatalerror
846 (cstring_makeLiteral ("Flag f to select options file "
847 "requires an argument"));
848 }
849 else
850 {
851 ; /* wait to process later */
852 }
853 }
854 }
f2b6724f 855
616915dd 856 setCodePoint ();
857
858 if (!nof && defaultf)
859 {
60868d40 860 /*
f2b6724f 861 ** No explicit rc file, first try reading ~/.splintrc
60868d40 862 */
616915dd 863
f2b6724f 864 if (cstring_isUndefined (fname))
60868d40 865 {
f2b6724f 866 if (!cstring_isEmpty (home))
60868d40 867 {
f2b6724f 868 bool readhomerc, readaltrc;
869 cstring homename, altname;
870
871 homename = message ("%s%h%s", home, CONNECTCHAR,
872 cstring_fromChars (RCFILE));
873 readhomerc = readOptionsFile (homename, &passThroughArgs, FALSE);
60868d40 874
f2b6724f 875 /*
1b8ae690 876 ** Try ~/.splintrc also for historical accuracy
f2b6724f 877 */
878
879 altname = message ("%s%h%s", home, CONNECTCHAR,
880 cstring_fromChars (ALTRCFILE));
881 readaltrc = readOptionsFile (altname, &passThroughArgs, FALSE);
882
883 if (readhomerc && readaltrc)
884 {
885
886 voptgenerror
887 (FLG_WARNRC,
888 message ("Found both %s and %s files. Using both files, "
889 "but recommend using only %s to avoid confusion.",
890 homename, altname, homename),
891 g_currentloc);
892 }
146e25eb 893
894 cstring_free (homename);
895 cstring_free (altname);
60868d40 896 }
897 }
898
f2b6724f 899 /*
900 ** Next, read .splintrc in the current working directory
901 */
902
903 {
904 cstring rcname = message ("%s%s",osd_getCurrentDirectory (), cstring_fromChars (RCFILE));
905 cstring altname = message ("%s%s",osd_getCurrentDirectory (), cstring_fromChars (ALTRCFILE));
906 bool readrc, readaltrc;
907
908 readrc = readOptionsFile (rcname, &passThroughArgs, FALSE);
909 readaltrc = readOptionsFile (altname, &passThroughArgs, FALSE);
910
911 if (readrc && readaltrc)
912 {
913 voptgenerror (FLG_WARNRC,
914 message ("Found both %s and %s files. Using both files, "
915 "but recommend using only %s to avoid confusion.",
916 rcname, altname, rcname),
917 g_currentloc);
918
919 }
616915dd 920
f2b6724f 921 cstring_free (rcname);
922 cstring_free (altname);
923 }
616915dd 924 }
925 }
926
927 setCodePoint ();
28bf4b0b 928
aa9c1601 929 /* argv[0] is the program name, don't pass it to flags_processFlags */
930 flags_processFlags (argc - 1, argv + 1);
616915dd 931
f2b6724f 932 showHerald ();
933
616915dd 934 /*
935 ** create lists of C and LCL files
936 */
937
938 cstringSList_elements (fl, current)
939 {
28bf4b0b 940 cstring ext = fileLib_getExtension (current);
941
942 if (cstring_isUndefined (ext))
616915dd 943 {
944 /* no extension --- both C and LCL with default extensions */
945
28bf4b0b 946 addFile (cfiles, message ("%s%s", current, C_EXTENSION));
947 addFile (lclfiles, message ("%s%s", current, LCL_EXTENSION));
948 }
949 else if (cstring_equal (ext, XH_EXTENSION))
950 {
53a89507 951 addXHFile (xfiles, current);
28bf4b0b 952 }
68de3f33 953 else if (cstring_equal (ext, PP_EXTENSION))
954 {
955 if (!context_getFlag (FLG_NOPP))
956 {
957 voptgenerror
958 (FLG_FILEEXTENSIONS,
959 message ("File extension %s used without +nopp flag (will be processed as C source code): %s",
960 ext, current),
961 g_currentloc);
962 }
963
964 addFile (cfiles, cstring_copy (current));
965 }
28bf4b0b 966 else if (cstring_equal (ext, LCL_EXTENSION))
967 {
968 addFile (lclfiles, cstring_copy (current));
616915dd 969 }
28bf4b0b 970 else if (fileLib_isCExtension (ext))
616915dd 971 {
28bf4b0b 972 addFile (cfiles, cstring_copy (current));
973 }
974 else if (cstring_equal (ext, MTS_EXTENSION))
975 {
53a89507 976 addLarchPathFile (mtfiles, current);
616915dd 977 }
978 else
979 {
28bf4b0b 980 voptgenerror
981 (FLG_FILEEXTENSIONS,
982 message ("Unrecognized file extension: %s (assuming %s is C source code)",
983 current, ext),
984 g_currentloc);
985
986 addFile (cfiles, cstring_copy (current));
616915dd 987 }
988 } end_cstringSList_elements;
989
616915dd 990 if (showhelp)
991 {
992 if (allhelp)
993 {
994 showHelp ();
995 }
80489f0a 996 fprintf (g_warningstream, "\n");
616915dd 997
998 fileIdList_free (cfiles);
28bf4b0b 999 fileIdList_free (xfiles);
616915dd 1000 fileIdList_free (lclfiles);
1001
1002 llexit (LLSUCCESS);
1003 }
1004
1005# ifdef DOANNOTS
1006 initAnnots ();
1007# endif
1008
1009 inittime = clock ();
1010
1011 context_resetErrors ();
1012 context_clearInCommandLine ();
1013
1014 anylcl = !fileIdList_isEmpty (lclfiles);
1015
1016 if (context_doMerge ())
1017 {
1018 cstring m = context_getMerge ();
1019
80489f0a 1020 displayScanOpen (message ("< loading %s ", m));
616915dd 1021 loadState (m);
80489f0a 1022 displayScanClose ();
616915dd 1023
1024 if (!usymtab_existsType (context_getBoolName ()))
1025 {
1026 usymtab_initBool ();
1027 }
1028 }
1029 else
1030 {
1031 if (!context_getFlag (FLG_NOLIB) && loadStandardState ())
1032 {
1033 ;
1034 }
1035 else
1036 {
1037 ctype_initTable ();
1038 }
1039
1040 /* setup bool type and constants */
1041 usymtab_initBool ();
1042 }
1043
1044 fileloc_free (g_currentloc);
1045 g_currentloc = fileloc_createBuiltin ();
1046
28bf4b0b 1047 /*
1048 ** Read metastate files (must happen before loading libraries)
1049 */
1050
1051 fileIdList_elements (mtfiles, mtfile)
1052 {
1053 context_setFileId (mtfile);
80489f0a 1054 displayScan (message ("processing %s", fileTable_rootFileName (mtfile)));
4dd72714 1055 mtreader_readFile (cstring_copy (fileTable_fileName (mtfile)));
28bf4b0b 1056 } end_fileIdList_elements;
1057
616915dd 1058 libtime = clock ();
28bf4b0b 1059
616915dd 1060 if (anylcl)
1061 {
1062# ifdef NOLCL
11db3170 1063 llfatalerror (cstring_makeLiteral ("This version of Splint does not handle LCL files."));
616915dd 1064# else
1065 lslProcess (lclfiles);
1066# endif
1067 }
1068
28bf4b0b 1069 usymtab_initGlobalMarker ();
1070
616915dd 1071 /*
1072 ** pre-processing
1073 **
1074 ** call the pre-preprocessor and /lib/cpp to generate appropriate
1075 ** files
1076 **
1077 */
1078
1079 context_setInCommandLine ();
1080
616915dd 1081 DPRINTF (("Pass through: %s", cstringSList_unparse (passThroughArgs)));
1082
1083 cstringSList_elements (passThroughArgs, thisarg) {
1084 handlePassThroughFlag (cstring_toCharsSafe (thisarg));
1085 } end_cstringSList_elements;
1086
1087 cstringSList_free (passThroughArgs);
1088
1089 cleanupMessages ();
1090
28bf4b0b 1091 DPRINTF (("Initializing cpp reader!"));
1092 cppReader_initialize ();
616915dd 1093 cppReader_saveDefinitions ();
1094
1095 context_clearInCommandLine ();
1096
1097 if (!context_getFlag (FLG_NOPP))
1098 {
28bf4b0b 1099 fileIdList tfiles;
1100
616915dd 1101 llflush ();
1102
80489f0a 1103 displayScanOpen (cstring_makeLiteral ("preprocessing"));
616915dd 1104
1105 lcltime = clock ();
1106
1107 context_setPreprocessing ();
28bf4b0b 1108 dercfiles = preprocessFiles (xfiles, TRUE);
1109 tfiles = preprocessFiles (cfiles, FALSE);
e55c0c6d 1110 warnSysFiles(cfiles);
28bf4b0b 1111 dercfiles = fileIdList_append (dercfiles, tfiles);
1112 fileIdList_free (tfiles);
1113
616915dd 1114 context_clearPreprocessing ();
1115
1116 fileIdList_free (cfiles);
1117
80489f0a 1118 displayScanClose ();
616915dd 1119 pptime = clock ();
1120 }
1121 else
1122 {
1123 lcltime = clock ();
28bf4b0b 1124 dercfiles = fileIdList_append (cfiles, xfiles);
616915dd 1125 pptime = clock ();
1126 }
28bf4b0b 1127
616915dd 1128 /*
1129 ** now, check all the corresponding C files
1130 **
1131 ** (for now these are just <file>.c, but after pre-processing
1132 ** will be <tmpprefix>.<file>.c)
1133 */
1134
1135 {
1136# ifdef WIN32
1137 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1138
1139 if (nfiles != 0)
1140 {
1141 llbug (message ("Files unclosed: %d", nfiles));
1142 }
1143# endif
1144 }
1145
28bf4b0b 1146 DPRINTF (("Initializing..."));
1147
616915dd 1148 exprNode_initMod ();
1149
28bf4b0b 1150 DPRINTF (("Okay..."));
1151
616915dd 1152 fileIdList_elements (dercfiles, fid)
1153 {
4dd72714 1154 sourceFile = inputStream_create (cstring_copy (fileTable_fileName (fid)), C_EXTENSION, TRUE);
616915dd 1155 context_setFileId (fid);
1156
1157 /* Open source file */
1158
28bf4b0b 1159 if (inputStream_isUndefined (sourceFile) || (!inputStream_open (sourceFile)))
616915dd 1160 {
1161 /* previously, this was ignored ?! */
4dd72714 1162 llbug (message ("Could not open temp file: %s", fileTable_fileName (fid)));
616915dd 1163 }
1164 else
1165 {
28bf4b0b 1166 yyin = inputStream_getFile (sourceFile); /*< shared <- only */
616915dd 1167
1168 llassert (yyin != NULL);
1169
80489f0a 1170 displayScan (message ("checking %q", osd_outputPath (fileTable_rootFileName (fid))));
616915dd 1171
1172 /*
1173 ** Every time, except the first time, through the loop,
1174 ** need to call yyrestart to clean up the parse buffer.
1175 */
1176
1177 if (!first_time)
1178 {
1179 (void) yyrestart (yyin);
1180 }
1181 else
1182 {
1183 first_time = FALSE;
1184 }
1185
28bf4b0b 1186 DPRINTF (("Entering..."));
616915dd 1187 context_enterFile ();
1188 (void) yyparse ();
28bf4b0b 1189 context_exitCFile ();
616915dd 1190
28bf4b0b 1191 (void) inputStream_close (sourceFile);
1192 }
616915dd 1193 } end_fileIdList_elements;
1194
1195 cptime = clock ();
1196
1197 /* process any leftover macros */
1198
1199 context_processAllMacros ();
1200
1201 /* check everything that was specified was defined */
1202
1203 /* don't check if no c files were processed ?
1204 ** is this correct behaviour?
1205 */
1206
80489f0a 1207 displayScan (cstring_makeLiteral ("global checks"));
616915dd 1208
1209 cleanupMessages ();
1210
1211 if (context_getLinesProcessed () > 0)
1212 {
1213 usymtab_allDefined ();
1214 }
1215
1216 if (context_maybeSet (FLG_TOPUNUSED))
1217 {
1218 uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main"));
1219
1220 if (uentry_isValid (ue))
1221 {
1222 uentry_setUsed (ue, fileloc_observeBuiltin ());
1223 }
1224
1225 usymtab_allUsed ();
1226 }
1227
1228 if (context_maybeSet (FLG_EXPORTLOCAL))
1229 {
1230 usymtab_exportLocal ();
1231 }
1232
1233
1234 if (context_maybeSet (FLG_EXPORTHEADER))
1235 {
1236 usymtab_exportHeader ();
1237 }
1238
1239 if (context_getFlag (FLG_SHOWUSES))
1240 {
1241 usymtab_displayAllUses ();
1242 }
1243
1244 context_checkSuppressCounts ();
1245
1246 if (context_doDump ())
1247 {
1248 cstring dump = context_getDump ();
1249
1250 dumpState (dump);
1251 }
1252
1253# ifdef DOANNOTS
1254 printAnnots ();
1255# endif
1256
1257 cleanupFiles ();
1258
1259 if (context_getFlag (FLG_SHOWSUMMARY))
1260 {
1261 summarizeErrors ();
1262 }
1263
1264
1265 {
1266 bool isQuiet = context_getFlag (FLG_QUIET);
1267 cstring specErrors = cstring_undefined;
1268# ifndef NOLCL
1269 int nspecErrors = lclNumberErrors ();
1270# endif
1271
1272 expsuccess = TRUE;
1273
1274 if (context_neednl ())
80489f0a 1275 fprintf (g_warningstream, "\n");
616915dd 1276
1277# ifndef NOLCL
1278 if (nspecErrors > 0)
1279 {
1280 if (nspecErrors == context_getLCLExpect ())
1281 {
1282 specErrors =
11db3170 1283 message ("%d spec warning%&, as expected\n ",
616915dd 1284 nspecErrors);
1285 }
1286 else
1287 {
1288 if (context_getLCLExpect () > 0)
1289 {
1290 specErrors =
11db3170 1291 message ("%d spec warning%&, expected %d\n ",
616915dd 1292 nspecErrors,
1293 (int) context_getLCLExpect ());
1294 }
1295 else
1296 {
2e127cb8 1297 specErrors = message ("%d spec warning%&\n ",
616915dd 1298 nspecErrors);
1299 expsuccess = FALSE;
1300 }
1301 }
1302 }
1303 else
1304 {
1305 if (context_getLCLExpect () > 0)
1306 {
11db3170 1307 specErrors = message ("No spec warnings, expected %d\n ",
616915dd 1308 (int) context_getLCLExpect ());
1309 expsuccess = FALSE;
1310 }
1311 }
1312# endif
1313
1314 if (context_anyErrors ())
1315 {
1316 if (context_numErrors () == context_getExpect ())
1317 {
1318 if (!isQuiet) {
11db3170 1319 llmsg (message ("Finished checking --- "
1320 "%s%d code warning%&, as expected",
616915dd 1321 specErrors, context_numErrors ()));
1322 }
1323 }
1324 else
1325 {
1326 if (context_getExpect () > 0)
1327 {
1328 if (!isQuiet) {
1329 llmsg (message
11db3170 1330 ("Finished checking --- "
1331 "%s%d code warning%&, expected %d",
616915dd 1332 specErrors, context_numErrors (),
1333 (int) context_getExpect ()));
1334 }
1335
1336 expsuccess = FALSE;
1337 }
1338 else
1339 {
1340
28bf4b0b 1341 if (!isQuiet)
1342 {
11db3170 1343 llmsg (message ("Finished checking --- "
2e127cb8 1344 "%s%d code warning%&",
28bf4b0b 1345 specErrors, context_numErrors ()));
1346 }
616915dd 1347
1348 expsuccess = FALSE;
1349 }
1350 }
1351 }
1352 else
1353 {
1354 if (context_getExpect () > 0)
1355 {
1356 if (!isQuiet) {
1357 llmsg (message
11db3170 1358 ("Finished checking --- "
1359 "%sno code warnings, expected %d",
616915dd 1360 specErrors,
1361 (int) context_getExpect ()));
1362 }
1363
1364 expsuccess = FALSE;
1365 }
1366 else
1367 {
1368 if (context_getLinesProcessed () > 0)
1369 {
11db3170 1370 if (cstring_isEmpty (specErrors))
1371 {
1372 if (!isQuiet)
1373 {
1374 llmsg (message ("Finished checking --- no warnings"));
1375 }
1376 }
1377 else
146e25eb 1378 {
11db3170 1379 if (!isQuiet)
1380 {
1381 llmsg (message ("Finished checking --- %sno code warnings",
1382 specErrors));
1383 }
146e25eb 1384 }
616915dd 1385 }
1386 else
1387 {
1388 if (!isQuiet) {
11db3170 1389 llmsg (message ("Finished checking --- %sno code processed",
616915dd 1390 specErrors));
1391 }
1392 }
1393 }
1394 }
1395
1396 cstring_free (specErrors);
1397 }
1398
1399 if (context_getFlag (FLG_STATS))
1400 {
1401 clock_t ttime = clock () - before;
1402 int specLines = context_getSpecLinesProcessed ();
1403
1404 rstime = clock ();
1405
1406 if (specLines > 0)
1407 {
80489f0a 1408 fprintf (g_warningstream, "%d spec, ", specLines);
616915dd 1409 }
1410
1411# ifndef CLOCKS_PER_SEC
80489f0a 1412 fprintf (g_warningstream, "%d source lines in %ld time steps (steps/sec unknown)\n",
616915dd 1413 context_getLinesProcessed (),
1414 (long) ttime);
1415# else
80489f0a 1416 fprintf (g_warningstream, "%d source lines in %.2f s.\n",
616915dd 1417 context_getLinesProcessed (),
1418 (double) ttime / CLOCKS_PER_SEC);
1419# endif
1420 }
1421 else
1422 {
1423 rstime = clock ();
1424 }
1425
1426 if (context_getFlag (FLG_TIMEDIST))
1427 {
1428 clock_t ttime = clock () - before;
1429
1430 if (ttime > 0)
1431 {
1432 char *msg = (char *) dmalloc (256 * sizeof (*msg));
1433
1434 if (anylcl)
1435 {
1436 sprintf (msg,
1437 "Time distribution (percent): initialize %.2f / lcl %.2f / "
1438 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1439 (100.0 * (double) (libtime - before) / ttime),
1440 (100.0 * (double) (lcltime - libtime) / ttime),
1441 (100.0 * (double) (pptime - lcltime) / ttime),
1442 (100.0 * (double) (cptime - pptime) / ttime),
1443 (100.0 * (double) (rstime - cptime) / ttime));
1444 }
1445 else
1446 {
1447 sprintf (msg,
1448 "Time distribution (percent): initialize %.2f / "
1449 "pre-process %.2f / c check %.2f / finalize %.2f \n",
1450 (100.0 * (double) (libtime - before) / ttime),
1451 (100.0 * (double) (pptime - libtime) / ttime),
1452 (100.0 * (double) (cptime - pptime) / ttime),
1453 (100.0 * (double) (rstime - cptime) / ttime));
1454 }
1455
1456 llgenindentmsgnoloc (cstring_fromCharsO (msg));
1457 }
1458 }
1459
1460 llexit (expsuccess ? LLSUCCESS : LLFAILURE);
8250fa4a 1461 BADBRANCHRET (LLFAILURE);
616915dd 1462}
1463
28bf4b0b 1464# ifdef WIN32
616915dd 1465/*
1466** Reenable return value warnings.
1467*/
28bf4b0b 1468# pragma warning (default:4035)
1469# endif
616915dd 1470
1471void
1472showHelp (void)
1473{
1474 showHerald ();
1475
28bf4b0b 1476 llmsg (message ("Source files are .c, .h and %s files. If there is no suffix,",
1477 LCL_EXTENSION));
11db3170 1478 llmsg (message (" Splint will look for <file>.c and <file>%s.", LCL_EXTENSION));
616915dd 1479 llmsglit ("");
11db3170 1480 llmsglit ("Use splint -help <topic or flag name> for more information");
616915dd 1481 llmsglit ("");
1482 llmsglit ("Topics:");
1483 llmsglit ("");
1484 llmsglit (" annotations (describes source-code annotations)");
1485 llmsglit (" comments (describes control comments)");
1486 llmsglit (" flags (describes flag categories)");
1487 llmsglit (" flags <category> (describes flags in category)");
1488 llmsglit (" flags all (short description of all flags)");
1489 llmsglit (" flags alpha (list all flags alphabetically)");
1490 llmsglit (" flags full (full description of all flags)");
1491 llmsglit (" mail (information on mailing lists)");
1492 llmsglit (" modes (show mode settings)");
1493 llmsglit (" parseerrors (help on handling parser errors)");
1494 llmsglit (" prefixcodes (character codes in namespace prefixes)");
1495 llmsglit (" references (sources for more information)");
1496 llmsglit (" vars (environment variables)");
1497 llmsglit (" version (information on compilation, maintainer)");
1498 llmsglit ("");
1499}
1500
1501static bool
1502specialFlagsHelp (char *next)
1503{
1504 if ((next != NULL) && (*next != '-') && (*next != '+'))
1505 {
1506 if (mstring_equal (next, "alpha"))
1507 {
1508 printAlphaFlags ();
1509 return TRUE;
1510 }
1511 else if (mstring_equal (next, "all"))
1512 {
1513 printAllFlags (TRUE, FALSE);
1514 return TRUE;
1515 }
1516 else if (mstring_equal (next, "categories")
1517 || mstring_equal (next, "cats"))
1518 {
1519 listAllCategories ();
1520 return TRUE;
1521 }
1522 else if (mstring_equal (next, "full"))
1523 {
1524 printAllFlags (FALSE, TRUE);
1525 return TRUE;
1526 }
4f43223c 1527 else if (mstring_equal (next, "manual"))
1528 {
45569d72 1529 printFlagManual (FALSE);
1530 return TRUE;
1531 }
1532 else if (mstring_equal (next, "webmanual"))
1533 {
1534 printFlagManual (TRUE);
4f43223c 1535 return TRUE;
1536 }
616915dd 1537 else
1538 {
1539 return FALSE;
1540 }
1541 }
1542 else
1543 {
1544 return FALSE;
1545 }
1546}
1547
1548void
1549printParseErrors (void)
1550{
1551 llmsglit ("Parse Errors");
1552 llmsglit ("------------");
1553 llmsglit ("");
1b8ae690 1554 llmsglit ("Splint will sometimes encounter a parse error for code that "
616915dd 1555 "can be parsed with a local compiler. There are a few likely "
1556 "causes for this and a number of techniques that can be used "
1557 "to work around the problem.");
1558 llmsglit ("");
1559 llmsglit ("Compiler extensions --- compilers sometimes extend the C "
1560 "language with compiler-specific keywords and syntax. While "
1561 "it is not advisible to use these, oftentimes one has no choice "
1562 "when the system header files use compiler extensions. ");
1563 llmsglit ("");
11db3170 1564 llmsglit ("Splint supports some of the GNU (gcc) compiler extensions, "
616915dd 1565 "if the +gnuextensions flag is set. You may be able to workaround "
1566 "other compiler extensions by using a pre-processor define. "
1567 "Alternately, you can surround the unparseable code with");
1568 llmsglit ("");
3e3ec469 1569 llmsglit (" # ifndef S_SPLINT_S");
616915dd 1570 llmsglit (" ...");
1571 llmsglit (" # endif");
1572 llmsglit ("");
28bf4b0b 1573 /* evans 2000-12-21 fixed typo reported by Jeroen Ruigrok/Asmodai */
616915dd 1574 llmsglit ("Missing type definitions --- an undefined type name will usually "
28bf4b0b 1575 "lead to a parse error. This often occurs when a standard header "
616915dd 1576 "file defines some type that is not part of the standard library. ");
11db3170 1577 llmsglit ("By default, Splint does not process the local files corresponding "
616915dd 1578 "to standard library headers, but uses a library specification "
1579 "instead so dependencies on local system headers can be detected. "
1580 "If another system header file that does not correspond to a "
1581 "standard library header uses one of these superfluous types, "
1582 "a parse error will result.");
1583 llmsglit ("");
1584 llmsglit ("If the parse error is inside a posix standard header file, the "
11db3170 1585 "first thing to try is +posixlib. This makes Splint use "
616915dd 1586 "the posix library specification instead of reading the posix "
1587 "header files.");
1588 llmsglit ("");
1589 llmsglit ("Otherwise, you may need to either manually define the problematic "
1b8ae690 1590 "type (e.g., add -Dmlink_t=int to your .splintrc file) or force "
1591 "splint to process the header file that defines it. This is done "
45569d72 1592 "by setting -skipisoheaders or -skipposixheaders before "
616915dd 1593 "the file that defines the type is #include'd.");
1b8ae690 1594 llmsglit ("(See splint -help "
45569d72 1595 "skipisoheaders and splint -help skipposixheaders for a list of "
616915dd 1596 "standard headers.) For example, if <sys/local.h> uses a type "
1597 "defined by posix header <sys/types.h> but not defined by the "
1598 "posix library, we might do: ");
1599 llmsglit ("");
1600 llmsglit (" /*@-skipposixheaders@*/");
1601 llmsglit (" # include <sys/types.h>");
1602 llmsglit (" /*@=skipposixheaders@*/");
1603 llmsglit (" # include <sys/local.h>");
1604 llmsglit ("");
11db3170 1605 llmsglit ("to force Splint to process <sys/types.h>.");
616915dd 1606 llmsglit ("");
11db3170 1607 llmsglit ("At last resort, +trytorecover can be used to make Splint attempt "
616915dd 1608 "to continue after a parse error. This is usually not successful "
1609 "and the author does not consider assertion failures when +trytorecover "
1610 "is used to be bugs.");
1611}
1612
1613void
1614printAnnotations (void)
1615{
1616 llmsglit ("Annotations");
1617 llmsglit ("-----------");
1618 llmsglit ("");
28bf4b0b 1619 llmsglit ("Annotations are semantic comments that document certain "
616915dd 1620 "assumptions about functions, variables, parameters, and types. ");
1621 llmsglit ("");
1622 llmsglit ("They may be used to indicate where the representation of a "
1623 "user-defined type is hidden, to limit where a global variable may "
1624 "be used or modified, to constrain what a function implementation "
1625 "may do to its parameters, and to express checked assumptions about "
1626 "variables, types, structure fields, function parameters, and "
1627 "function results.");
1628 llmsglit ("");
1629 llmsglit ("Annotations are introduced by \"/*@\". The role of the @ may be "
1630 "played by any printable character, selected using -commentchar <char>.");
1631 llmsglit ("");
1632 llmsglit ("Consult the User's Guide for descriptions of checking associated with each annotation.");
1633 llmsglit ("");
1634 llmsglit ("Globals: (in function declarations)");
1635 llmsglit (" /*@globals <globitem>,+ @*/");
1636 llmsglit (" globitem is an identifier, internalState or fileSystem");
1637 llmsglit ("");
1638 llmsglit ("Modifies: (in function declarations)");
1639 llmsglit (" /*@modifies <moditem>,+ @*/");
1640 llmsglit (" moditem is an lvalue");
1641 llmsglit (" /*@modifies nothing @*/");
1642 llmsglit (" /*@*/ (Abbreviation for no globals and modifies nothing.)");
1643 llmsglit ("");
1644 llmsglit ("Iterators:");
1645 llmsglit (" /*@iter <identifier> (<parameter-type-list>) @*/ - declare an iterator");
1646 llmsglit ("");
1647 llmsglit ("Constants:");
1648 llmsglit (" /*@constant <declaration> @*/ - declares a constant");
1649 llmsglit ("");
1650 llmsglit ("Alternate Types:");
1651 llmsglit (" /*@alt <basic-type>,+ @*/");
1652 llmsglit (" (e.g., int /*@alt char@*/ is a type matching either int or char)");
1653 llmsglit ("");
1654 llmsglit ("Declarator Annotations");
1655 llmsglit ("");
1656 llmsglit ("Type Definitions:");
1657 llmsglit (" /*@abstract@*/ - representation is hidden from clients");
1658 llmsglit (" /*@concrete@*/ - representation is visible to clients");
1659 llmsglit (" /*@immutable@*/ - instances of the type cannot change value");
1660 llmsglit (" /*@mutable@*/ - instances of the type can change value");
1661 llmsglit (" /*@refcounted@*/ - reference counted type");
1662 llmsglit ("");
1663 llmsglit ("Global Variables:");
1664 llmsglit (" /*@unchecked@*/ - weakest checking for global use");
1665 llmsglit (" /*@checkmod@*/ - check modification by not use of global");
1666 llmsglit (" /*@checked@*/ - check use and modification of global");
1667 llmsglit (" /*@checkedstrict@*/ - check use of global strictly");
1668 llmsglit ("");
1669 llmsglit ("Memory Management:");
1670 llmsglit (" /*@dependent@*/ - a reference to externally-owned storage");
1671 llmsglit (" /*@keep@*/ - a parameter that is kept by the called function");
1672 llmsglit (" /*@killref@*/ - a refcounted parameter, killed by the call");
1673 llmsglit (" /*@only@*/ - an unshared reference");
1674 llmsglit (" /*@owned@*/ - owner of storage that may be shared by /*@dependent@*/ references");
1675 llmsglit (" /*@shared@*/ - shared reference that is never deallocated");
1676 llmsglit (" /*@temp@*/ - temporary parameter");
1677 llmsglit ("");
1678 llmsglit ("Aliasing:");
1679 llmsglit (" /*@unique@*/ - may not be aliased by any other visible reference");
1680 llmsglit (" /*@returned@*/ - may be aliased by the return value");
1681 llmsglit ("");
1682 llmsglit ("Exposure:");
1683 llmsglit (" /*@observer@*/ - reference that cannot be modified");
1684 llmsglit (" /*@exposed@*/ - exposed reference to storage in another object");
1685 llmsglit ("");
1686 llmsglit ("Definition State:");
1687 llmsglit (" /*@out@*/ - storage reachable from reference need not be defined");
1688 llmsglit (" /*@in@*/ - all storage reachable from reference must be defined");
1689 llmsglit (" /*@partial@*/ - partially defined, may have undefined fields");
1690 llmsglit (" /*@reldef@*/ - relax definition checking");
1691 llmsglit ("");
1692 llmsglit ("Global State: (for globals lists, no /*@, since list is already in /*@\'s)");
1693 llmsglit (" undef - variable is undefined before the call");
1694 llmsglit (" killed - variable is undefined after the call");
1695 llmsglit ("");
1696 llmsglit ("Null State:");
1697 llmsglit (" /*@null@*/ - possibly null pointer");
0e41eb0e 1698 llmsglit (" /*@notnull@*/ - definitely non-null pointer");
616915dd 1699 llmsglit (" /*@relnull@*/ - relax null checking");
1700 llmsglit ("");
1701 llmsglit ("Null Predicates:");
0e41eb0e 1702 llmsglit (" /*@nullwhentrue@*/ - if result is TRUE, first parameter is NULL");
1703 llmsglit (" /*@falsewhennull@*/ - if result is TRUE, first parameter is not NULL");
616915dd 1704 llmsglit ("");
1705 llmsglit ("Execution:");
27c9e640 1706 llmsglit (" /*@noreturn@*/ - function never returns");
1707 llmsglit (" /*@maynotreturn@*/ - function may or may not return");
1708 llmsglit (" /*@noreturnwhentrue@*/ - function does not return if first parameter is TRUE");
1709 llmsglit (" /*@noreturnwhenfalse@*/ - function does not return if first parameter if FALSE");
1710 llmsglit (" /*@alwaysreturns@*/ - function always returns");
616915dd 1711 llmsglit ("");
1712 llmsglit ("Side-Effects:");
1713 llmsglit (" /*@sef@*/ - corresponding actual parameter has no side effects");
1714 llmsglit ("");
1715 llmsglit ("Declaration:");
1716 llmsglit (" /*@unused@*/ - need not be used (no unused errors reported)");
1717 llmsglit (" /*@external@*/ - defined externally (no undefined error reported)");
1718 llmsglit ("");
1719 llmsglit ("Case:");
1720 llmsglit (" /*@fallthrough@*/ - fall-through case");
1721 llmsglit ("");
1722 llmsglit ("Break:");
1723 llmsglit (" /*@innerbreak@*/ - break is breaking an inner loop or switch");
1724 llmsglit (" /*@loopbreak@*/ - break is breaking a loop");
1725 llmsglit (" /*@switchbreak@*/ - break is breaking a switch");
1726 llmsglit (" /*@innercontinue@*/ - continue is continuing an inner loop");
1727 llmsglit ("");
1728 llmsglit ("Unreachable Code:");
1729 llmsglit (" /*@notreached@*/ - statement may be unreachable.");
1730 llmsglit ("");
1731 llmsglit ("Special Functions:");
1732 llmsglit (" /*@printflike@*/ - check variable arguments like printf");
1733 llmsglit (" /*@scanflike@*/ - check variable arguments like scanf");
1734}
1735
1736void
1737printComments (void)
1738{
1739 llmsglit ("Control Comments");
1740 llmsglit ("----------------");
1741 llmsglit ("");
1742 llmsglit ("Setting Flags");
1743 llmsglit ("");
1744 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.");
1745 llmsglit ("");
1746 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,");
1747 llmsglit (" /*@+boolint -modifies =showfunc@*/");
1748 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).");
1749 llmsglit ("");
1750 llmsglit ("Error Suppression");
1751 llmsglit ("");
1752 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.");
1753 llmsglit ("");
1754 llmsglit ("/*@ignore@*/ ... /*@end@*/");
1755 llgenindentmsgnoloc
1756 (cstring_makeLiteral
1757 ("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."));
1758 llmsglit ("/*@i@*/");
1759 llgenindentmsgnoloc
1760 (cstring_makeLiteral
1761 ("No errors will be reported from an /*@i@*/ comment to the end of the line."));
1762 llmsglit ("/*@i<n>@*/");
1763 llgenindentmsgnoloc
1764 (cstring_makeLiteral
11db3170 1765 ("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 1766 llmsglit ("/*@t@*/, /*@t<n>@*/");
1767 llgenindentmsgnoloc
1768 (cstring_makeLiteral
1769 ("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."));
1770 llmsglit ("");
1771 llmsglit ("Type Access");
1772 llmsglit ("");
1773 llmsglit ("/*@access <type>@*/");
1774 llmsglit (" Allows the following code to access the representation of <type>");
1775 llmsglit ("/*@noaccess <type>@*/");
1776 llmsglit (" Hides the representation of <type>");
1777 llmsglit ("");
1778 llmsglit ("Macro Expansion");
1779 llmsglit ("");
1780 llmsglit ("/*@notfunction@*/");
1781 llgenindentmsgnoloc
1782 (cstring_makeLiteral
1783 ("Indicates that the next macro definition is not intended to be a "
1784 "function, and should be expanded in line instead of checked as a "
1785 "macro function definition."));
1786}
1787
1788
1789void
1790printFlags (void)
1791{
1792 llmsglit ("Flag Categories");
1793 llmsglit ("---------------");
1794 listAllCategories ();
1b8ae690 1795 llmsglit ("\nTo see the flags in a flag category, do\n splint -help flags <category>");
1796 llmsglit ("To see a list of all flags in alphabetical order, do\n splint -help flags alpha");
1797 llmsglit ("To see a full description of all flags, do\n splint -help flags full");
616915dd 1798}
1799
1800void
1801printMaintainer (void)
1802{
1b8ae690 1803 llmsg (message ("Maintainer: %s", cstring_makeLiteralTemp (SPLINT_MAINTAINER)));
616915dd 1804 llmsglit (LCL_COMPILE);
1805}
1806
1807void
1808printMail (void)
1809{
1810 llmsglit ("Mailing Lists");
1811 llmsglit ("-------------");
1812 llmsglit ("");
11db3170 1813 llmsglit ("There are two mailing lists associated with Splint: ");
616915dd 1814 llmsglit ("");
1815 llmsglit (" lclint-announce@virginia.edu");
1816 llmsglit ("");
1817 llmsglit (" Reserved for announcements of new releases and bug fixes.");
1818 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
1819 llmsglit (" subscribe lclint-announce");
1820 llmsglit ("");
1821 llmsglit (" lclint-interest@virginia.edu");
1822 llmsglit ("");
1b8ae690 1823 llmsglit (" Informal discussions on the use and development of Splint.");
616915dd 1824 llmsglit (" To subscribe, send a message to majordomo@virginia.edu with body: ");
1825 llmsglit (" subscribe lclint-interest");
1826}
1827
1828void
1829printReferences (void)
1830{
1831 llmsglit ("References");
1832 llmsglit ("----------");
1833 llmsglit ("");
11db3170 1834 llmsglit ("For more information, see the Splint web site: http://www.splint.org");
616915dd 1835}
1836
1837void
1838describePrefixCodes (void)
1839{
1840 llmsglit ("Prefix Codes");
1841 llmsglit ("------------");
1842 llmsglit ("");
1843 llmsglit ("These characters have special meaning in name prefixes:");
1844 llmsglit ("");
1845 llmsg (message (" %h Any uppercase letter [A-Z]", PFX_UPPERCASE));
1846 llmsg (message (" %h Any lowercase letter [a-z]", PFX_LOWERCASE));
1847 llmsg (message (" %h Any character (valid in a C identifier)", PFX_ANY));
1848 llmsg (message (" %h Any digit [0-9]", PFX_DIGIT));
1849 llmsg (message (" %h Any non-uppercase letter [a-z0-9_]", PFX_NOTUPPER));
1850 llmsg (message (" %h Any non-lowercase letter [A-Z0-9_]", PFX_NOTLOWER));
1851 llmsg (message (" %h Any letter [A-Za-z]", PFX_ANYLETTER));
1852 llmsg (message (" %h Any letter or digit [A-Za-z0-9]", PFX_ANYLETTERDIGIT));
1853 llmsglit (" * Zero or more repetitions of the previous character class until the end of the name");
1854}
1855
1856void
1857describeVars (void)
1858{
1859 cstring eval;
28bf4b0b 1860 cstring def;
616915dd 1861
1862 eval = context_getLarchPath ();
1863 def = osd_getEnvironmentVariable (LARCH_PATH);
1864
28bf4b0b 1865 if (cstring_isDefined (def) ||
616915dd 1866 !cstring_equal (eval, cstring_fromChars (DEFAULT_LARCHPATH)))
1867 {
1868 llmsg (message ("LARCH_PATH = %s", eval));
1869 }
1870 else
1871 {
1872 llmsg (message ("LARCH_PATH = <not set> (default = %s)",
1873 cstring_fromChars (DEFAULT_LARCHPATH)));
1874 }
1875
1876 llmsglit (" --- path used to find larch initialization files and LSL traits");
1877
1878 eval = context_getLCLImportDir ();
28bf4b0b 1879 def = osd_getEnvironmentVariable (cstring_makeLiteralTemp (LCLIMPORTDIR));
616915dd 1880
28bf4b0b 1881 if (cstring_isDefined (def) ||
616915dd 1882 !cstring_equal (eval, cstring_fromChars (DEFAULT_LCLIMPORTDIR)))
1883 {
1884 llmsg (message ("%q = %s", cstring_makeLiteral (LCLIMPORTDIR), eval));
1885 }
1886 else
1887 {
1888 llmsg (message ("%s = <not set, default: %s>", cstring_makeLiteralTemp (LCLIMPORTDIR),
1889 cstring_makeLiteralTemp (DEFAULT_LCLIMPORTDIR)));
1890 }
1891
1892 llmsglit (" --- directory containing lcl standard library files "
1893 "(import with < ... >)");;
1894
7272a1c1 1895 llmsg (message
1896 ("include path = %q (set by environment variable %s and -I flags)",
1897 cppReader_getIncludePath (), INCLUDEPATH_VAR));
616915dd 1898
7272a1c1 1899 llmsglit (" --- path used to find #include'd files");
1900
1901 llmsg (message
68de3f33 1902 ("systemdirs = %s (set by -systemdirs or environment variable %s)", /*@i413223@*/
7272a1c1 1903 context_getString (FLG_SYSTEMDIRS),
1904 INCLUDEPATH_VAR));
1905
1906 llmsglit (" --- if file is found on this path, it is treated as a system file for error reporting");
616915dd 1907}
1908
1909void
1910interrupt (int i)
1911{
1912 switch (i)
1913 {
1914 case SIGINT:
80489f0a 1915 fprintf (g_errorstream, "*** Interrupt\n");
616915dd 1916 llexit (LLINTERRUPT);
1917 case SIGSEGV:
1918 {
1919 cstring loc;
1920
1921 /* Cheat when there are parse errors */
1922 checkParseError ();
1923
80489f0a 1924 fprintf (g_errorstream, "*** Segmentation Violation\n");
616915dd 1925
1926 /* Don't catch it if fileloc_unparse causes a signal */
1927 (void) signal (SIGSEGV, NULL);
1928
1929 loc = fileloc_unparse (g_currentloc);
1930
80489f0a 1931 fprintf (g_errorstream, "*** Location (not trusted): %s\n",
616915dd 1932 cstring_toCharsSafe (loc));
1933 cstring_free (loc);
1934 printCodePoint ();
80489f0a 1935 fprintf (g_errorstream, "*** Please report bug to %s\n", SPLINT_MAINTAINER);
616915dd 1936 exit (LLGIVEUP);
1937 }
1938 default:
80489f0a 1939 fprintf (g_errorstream, "*** Signal: %d\n", i);
616915dd 1940 /*@-mustfree@*/
80489f0a 1941 fprintf (g_errorstream, "*** Location (not trusted): %s\n",
616915dd 1942 cstring_toCharsSafe (fileloc_unparse (g_currentloc)));
1943 /*@=mustfree@*/
1944 printCodePoint ();
80489f0a 1945 fprintf (g_errorstream, "*** Please report bug to %s ***\n", SPLINT_MAINTAINER);
616915dd 1946 exit (LLGIVEUP);
1947 }
1948}
1949
1950void
1951cleanupFiles (void)
1952{
1953 static bool doneCleanup = FALSE;
1954
1955 /* make sure this is only called once! */
1956
1957 if (doneCleanup) return;
1958
1959 setCodePoint ();
1960
dfd82dce 1961 /*
1962 ** Close all open files
1963 ** (There should only be open files, if we exited after a fatal error.)
1964 */
1965
1966 fileTable_closeAll (context_fileTable ());
1967
616915dd 1968 if (context_getFlag (FLG_KEEP))
1969 {
80489f0a 1970 check (fputs ("Temporary files kept:\n", g_messagestream) != EOF);
616915dd 1971 fileTable_printTemps (context_fileTable ());
1972 }
1973 else
1974 {
1975# ifdef WIN32
1976 int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/
1977
1978 if (nfiles != 0)
1979 {
1980 llbug (message ("Files unclosed: %d", nfiles));
1981 }
1982# endif
1983 fileTable_cleanup (context_fileTable ());
1984 }
1985
1986 doneCleanup = TRUE;
1987}
1988
1989/*
11db3170 1990** cleans up temp files (if necessary) and exits
616915dd 1991*/
1992
27c9e640 1993/*@noreturn@*/ void
616915dd 1994llexit (int status)
1995{
1996 DPRINTF (("llexit: %d", status));
1997
1998# ifdef WIN32
1999 if (status == LLFAILURE)
2000 {
2001 _fcloseall ();
2002 }
2003# endif
2004
2005 cleanupFiles ();
2006
2007 if (status != LLFAILURE)
2008 {
2009 context_destroyMod ();
2010 exprNode_destroyMod ();
2011
2012 sRef_destroyMod ();
2013 uentry_destroyMod ();
2014 typeIdSet_destroyMod ();
2015
2016# ifdef USEDMALLOC
2017 dmalloc_shutdown ();
2018# endif
2019 }
2020
2021 exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE);
2022}
2023
f2b6724f 2024bool readOptionsFile (cstring fname, cstringSList *passThroughArgs, bool report)
2025{
2026 bool res = FALSE;
2027
2028 if (fileTable_exists (context_fileTable (), fname))
2029 {
2030 if (report)
2031 {
2032 voptgenerror
2033 (FLG_WARNRC,
2034 message ("Multiple attempts to read options file: %s", fname),
2035 g_currentloc);
2036 }
2037 }
2038 else
2039 {
d5047b91 2040 FILE *innerf = fileTable_openReadFile (context_fileTable (), fname);
f2b6724f 2041
2042 if (innerf != NULL)
2043 {
2044 fileloc fc = g_currentloc;
2045 g_currentloc = fileloc_createRc (fname);
2046
80489f0a 2047 displayScan (message ("< reading options from %q >",
2048 fileloc_outputFilename (g_currentloc)));
f2b6724f 2049
2050 loadrc (innerf, passThroughArgs);
2051 fileloc_reallyFree (g_currentloc);
2052 g_currentloc = fc;
2053 res = TRUE;
2054 }
2055 else
2056 {
2057 if (report)
2058 {
2059 voptgenerror
2060 (FLG_WARNRC,
2061 message ("Cannot open options file: %s", fname),
2062 g_currentloc);
2063 }
2064 }
2065 }
2066
2067 return res;
2068}
2069
ee229125 2070/*
2071** This shouldn't be necessary, but Apple Darwin can't handle '"''s.
2072*/
2073
616915dd 2074void
15b3d2b2 2075loadrc (/*:open:*/ FILE *rcfile, cstringSList *passThroughArgs)
146e25eb 2076 /*@modifies rcfile@*/
b9904f57 2077 /*@ensures closed rcfile@*/
616915dd 2078{
2079 char *s = mstring_create (MAX_LINE_LENGTH);
2080 char *os = s;
f2b6724f 2081
616915dd 2082 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2083
2084 s = os;
2085
28bf4b0b 2086 while (reader_readLine (rcfile, s, MAX_LINE_LENGTH) != NULL)
616915dd 2087 {
2088 char c;
2089 bool set = FALSE;
2090 char *thisflag;
2091 flagcode opt;
2092
2093 DPRINTF (("Line: %s", s));
2094 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
616915dd 2095
28bf4b0b 2096 while (*s == ' ' || *s == '\t')
616915dd 2097 {
2098 s++;
2099 incColumn ();
2100 }
2101
2102 while (*s != '\0')
2103 {
2104 bool escaped = FALSE;
2105 bool quoted = FALSE;
2106 c = *s;
2107
2108 DPRINTF (("Process: %s", s));
2109 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2110 /* comment characters */
2111 if (c == '#' || c == ';' || c == '\n')
2112 {
2113 /*@innerbreak@*/
2114 break;
2115 }
2116
2117 if (c == '-' || c == '+')
2118 {
2119 set = (c == '+');
2120 }
2121 else
2122 {
2123 showHerald ();
ccf0a4a8 2124 voptgenerror (FLG_BADFLAG,
2125 message ("Bad flag syntax (+ or - expected, "
2126 "+ is assumed): %s",
2127 cstring_fromChars (s)),
2128 g_currentloc);
616915dd 2129 s--;
2130 set = TRUE;
2131 }
2132
2133 s++;
2134 incColumn ();
2135
2136 thisflag = s;
2137
2138 while ((c = *s) != '\0')
2139 { /* remember to handle spaces and quotes in -D and -U ... */
2140 if (escaped)
2141 {
2142 escaped = FALSE;
2143 }
2144 else if (quoted)
2145 {
2146 if (c == '\\')
2147 {
2148 escaped = TRUE;
2149 }
2150 else if (c == '\"')
2151 {
2152 quoted = FALSE;
2153 }
2154 else
2155 {
2156 ;
2157 }
2158 }
2159 else if (c == '\"')
2160 {
2161 quoted = TRUE;
2162 }
2163 else
2164 {
2165 if (c == ' ' || c == '\t' || c == '\n')
2166 {
2167 /*@innerbreak@*/ break;
2168 }
2169 }
2170
2171 s++;
2172 incColumn ();
2173 }
2174
2175 DPRINTF (("Nulling: %c", *s));
2176 *s = '\0';
2177
2178 if (mstring_isEmpty (thisflag))
2179 {
2180 llfatalerror (message ("Missing flag: %s",
2181 cstring_fromChars (os)));
2182 }
2183
2184 DPRINTF (("Flag: %s", thisflag));
2185
a956d444 2186 opt = flags_identifyFlag (cstring_fromChars (thisflag));
616915dd 2187
2188 if (flagcode_isSkip (opt))
2189 {
2190 ;
2191 }
2192 else if (flagcode_isInvalid (opt))
2193 {
28bf4b0b 2194 DPRINTF (("Invalid: %s", thisflag));
2195
aa9c1601 2196 if (flags_isModeName (cstring_fromChars (thisflag)))
616915dd 2197 {
2198 context_setMode (cstring_fromChars (thisflag));
2199 }
2200 else
2201 {
ccf0a4a8 2202 voptgenerror (FLG_BADFLAG,
2203 message ("Unrecognized option: %s",
2204 cstring_fromChars (thisflag)),
2205 g_currentloc);
616915dd 2206 }
2207 }
2208 else
2209 {
2210 context_userSetFlag (opt, set);
2211
2212 if (flagcode_hasArgument (opt))
2213 {
2214 if (opt == FLG_HELP)
2215 {
2216 showHerald ();
ccf0a4a8 2217 voptgenerror (FLG_BADFLAG,
2218 message ("Cannot use help in rc files"),
2219 g_currentloc);
616915dd 2220 }
2221 else if (flagcode_isPassThrough (opt)) /* -D or -U */
2222 {
2223 cstring arg = cstring_fromCharsNew (thisflag);
2224 cstring_markOwned (arg);
2225 *passThroughArgs = cstringSList_add (*passThroughArgs, arg);
2226 DPRINTF (("Pass through: %s",
2227 cstringSList_unparse (*passThroughArgs)));
2228 }
2229 else if (opt == FLG_INCLUDEPATH
2230 || opt == FLG_SPECPATH)
2231 {
aa9c1601 2232 cstring dir;
2233
2234 /*
2235 ** Either -I<dir> or -I <dir>
2236 */
2237
2238 if (cstring_length (thisflag) > 1)
2239 {
2240 dir = cstring_suffix (cstring_fromChars (thisflag), 1); /* skip over I/S */
2241 }
2242 else
2243 {
2244 BADBRANCH; /*@!!!!@*/
2245 }
616915dd 2246
2247 switch (opt)
2248 {
2249 case FLG_INCLUDEPATH:
2250 cppAddIncludeDir (dir);
2251 /*@switchbreak@*/ break;
2252 case FLG_SPECPATH:
2253 /*@-mustfree@*/
2254 g_localSpecPath = cstring_toCharsSafe
2255 (message ("%s:%s", cstring_fromChars (g_localSpecPath), dir));
2256 /*@=mustfree@*/
2257 /*@switchbreak@*/ break;
2258 BADDEFAULT;
2259 }
2260 }
2261 else if (flagcode_hasString (opt)
4f43223c 2262 || flagcode_hasNumber (opt)
2263 || flagcode_hasChar (opt)
616915dd 2264 || opt == FLG_INIT || opt == FLG_OPTF)
2265 {
2266 cstring extra = cstring_undefined;
2267 char *rest, *orest;
2268 char rchar;
2269
2270 *s = c;
2271 rest = mstring_copy (s);
2272 DPRINTF (("Here: rest = %s", rest));
2273 orest = rest;
2274 *s = '\0';
2275
2276 while ((rchar = *rest) != '\0'
2277 && (isspace ((int) rchar)))
2278 {
2279 rest++;
2280 s++;
2281 }
2282
2283 DPRINTF (("Yo: %s", rest));
2284
2285 while ((rchar = *rest) != '\0'
2286 && !isspace ((int) rchar))
2287 {
2288 extra = cstring_appendChar (extra, rchar);
2289 rest++;
2290 s++;
2291 }
2292
2293 DPRINTF (("Yo: %s", extra));
2294 sfree (orest);
2295
2296 if (cstring_isUndefined (extra))
2297 {
2298 showHerald ();
ccf0a4a8 2299 voptgenerror
616915dd 2300 (FLG_BADFLAG,
2301 message
2302 ("Flag %s must be followed by an argument",
ccf0a4a8 2303 flagcode_unparse (opt)),
2304 g_currentloc);
616915dd 2305 }
2306 else
2307 {
2308 s--;
2309
2310 DPRINTF (("Here we are: %s", extra));
2311
4f43223c 2312 if (flagcode_hasNumber (opt) || flagcode_hasChar (opt))
616915dd 2313 {
2314 DPRINTF (("Set value flag: %s", extra));
2315 setValueFlag (opt, extra);
616915dd 2316 }
2317 else if (opt == FLG_OPTF)
2318 {
f2b6724f 2319 (void) readOptionsFile (extra, passThroughArgs, TRUE);
616915dd 2320 }
2321 else if (opt == FLG_INIT)
2322 {
2323# ifndef NOLCL
28bf4b0b 2324 llassert (inputStream_isUndefined (initFile));
616915dd 2325
28bf4b0b 2326 initFile = inputStream_create
146e25eb 2327 (cstring_copy (extra),
28bf4b0b 2328 cstring_makeLiteralTemp (LCLINIT_SUFFIX),
2329 FALSE);
616915dd 2330# endif
2331 }
2332 else if (flagcode_hasString (opt))
2333 {
146e25eb 2334 DPRINTF (("Here: %s", extra));
2335
2336 /*
2337 ** If it has "'s, we need to remove them.
2338 */
2339
ee229125 2340 if (cstring_firstChar (extra) == '\"')
616915dd 2341 {
ee229125 2342 if (cstring_lastChar (extra) == '\"')
616915dd 2343 {
146e25eb 2344 cstring unquoted = cstring_copyLength
2345 (cstring_toCharsSafe (cstring_suffix (extra, 1)),
2346 cstring_length (extra) - 2);
2347
2348 DPRINTF (("string flag: %s -> %s", extra, unquoted));
2349 setStringFlag (opt, unquoted);
2350 cstring_free (extra);
616915dd 2351 }
2352 else
2353 {
ccf0a4a8 2354 voptgenerror
2355 (FLG_BADFLAG,
616915dd 2356 message ("Unmatched \" in option string: %s",
ccf0a4a8 2357 extra),
2358 g_currentloc);
146e25eb 2359 setStringFlag (opt, extra);
616915dd 2360 }
2361 }
146e25eb 2362 else
2363 {
2364 DPRINTF (("No quotes: %s", extra));
2365 setStringFlag (opt, extra);
2366 }
2367
2368 extra = cstring_undefined;
616915dd 2369 }
2370 else
2371 {
616915dd 2372 BADEXIT;
2373 }
2374 }
146e25eb 2375
2376 cstring_free (extra);
616915dd 2377 }
2378 else
2379 {
2380 BADEXIT;
2381 }
2382 }
2383 }
2384
2385 *s = c;
2386 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2387 while ((c == ' ') || (c == '\t'))
2388 {
2389 c = *(++s);
2390 incColumn ();
2391 }
2392 }
2393 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2394 s = os;
2395 }
2396
2397 DPRINTF (("Pass through: %s", cstringSList_unparse (*passThroughArgs)));
2398 sfree (os);
dfd82dce 2399 check (fileTable_closeFile (context_fileTable (), rcfile));
616915dd 2400}
2401
28bf4b0b 2402static fileIdList preprocessFiles (fileIdList fl, bool xhfiles)
616915dd 2403 /*@modifies fileSystem@*/
2404{
2405 bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10);
2406 int skip = (fileIdList_size (fl) / 5);
2407 int filesprocessed = 0;
2408 fileIdList dfiles = fileIdList_create ();
2409
2410 fileloc_free (g_currentloc);
2411 g_currentloc = fileloc_createBuiltin ();
2412
2413 fileIdList_elements (fl, fid)
2414 {
4dd72714 2415 cstring ppfname = fileTable_fileName (fid);
616915dd 2416
53a89507 2417 if (!(osd_fileIsReadable (ppfname)))
616915dd 2418 {
146e25eb 2419 lldiagmsg (message ("Cannot open file: %q", osd_outputPath (ppfname)));
53a89507 2420 ppfname = cstring_undefined;
28bf4b0b 2421 }
2422
2423 if (cstring_isDefined (ppfname))
2424 {
2425 fileId dfile = fileTable_addCTempFile (context_fileTable (), fid);
53a89507 2426
2427 if (xhfiles)
2428 {
2429 llassert (fileTable_isXHFile (context_fileTable (), dfile));
2430 }
2431
28bf4b0b 2432 llassert (cstring_isNonEmpty (ppfname));
616915dd 2433
2434 if (msg)
2435 {
2436 if ((filesprocessed % skip) == 0)
2437 {
2438 if (filesprocessed == 0) {
80489f0a 2439 fprintf (g_messagestream, " ");
616915dd 2440 }
2441 else {
80489f0a 2442 fprintf (g_messagestream, ".");
616915dd 2443 }
2444
80489f0a 2445 (void) fflush (g_messagestream);
616915dd 2446 }
2447 filesprocessed++;
2448 }
2449
4dd72714 2450 DPRINTF (("outfile: %s", fileTable_fileName (dfile)));
2451
2452 if (cppProcess (ppfname, fileTable_fileName (dfile)) != 0)
616915dd 2453 {
2454 llfatalerror (message ("Preprocessing error for file: %s",
4dd72714 2455 fileTable_rootFileName (fid)));
616915dd 2456 }
2457
2458 fileIdList_add (dfiles, dfile);
2459 }
2460 } end_fileIdList_elements;
2461
2462 return dfiles;
2463}
28bf4b0b 2464
2465/* This should be in an lclUtils.c file... */
2466# ifndef NOLCL
2467char *specFullName (char *specfile, /*@out@*/ char **inpath)
2468{
2469 /* extract the path and the specname associated with the given file */
2470 char *specname = (char *) dmalloc (sizeof (*specname)
2471 * (strlen (specfile) + 9));
2472 char *ospecname = specname;
2473 char *path = (char *) dmalloc (sizeof (*path) * (strlen (specfile)));
2474 size_t size;
2475 long int i, j;
2476
2477 /* initialized path to empty string or may have accidental garbage */
2478 *path = '\0';
2479
2480 /*@-mayaliasunique@*/
2481 strcpy (specname, specfile);
2482 /*@=mayaliasunique@*/
2483
2484 /* trim off pathnames in specfile */
2485 size = strlen (specname);
2486
2487 for (i = size_toInt (size) - 1; i >= 0; i--)
2488 {
2489 if (specname[i] == CONNECTCHAR)
2490 {
2491 /* strcpy (specname, (char *)specname+i+1); */
2492 for (j = 0; j <= i; j++) /* include '/' */
2493 {
2494 path[j] = specname[j];
2495 }
2496
2497 path[i + 1] = '\0';
2498 specname += i + 1;
2499 break;
2500 }
2501 }
2502
2503 /*
2504 ** also remove .lcl file extension, assume it's the last extension
2505 ** of the file name
2506 */
2507
2508 size = strlen (specname);
2509
2510 for (i = size_toInt (size) - 1; i >= 0; i--)
2511 {
2512 if (specname[i] == '.')
2513 {
2514 specname[i] = '\0';
2515 break;
2516 }
2517 }
2518
2519 *inpath = path;
2520
2521 /*
2522 ** If specname no longer points to the original char,
2523 ** we need to allocate a new pointer and copy the string.
2524 */
2525
2526 if (specname != ospecname) {
2527 char *rspecname = (char *) dmalloc (sizeof (*rspecname) * (strlen (specname) + 1));
2528 strcpy (rspecname, specname); /* evs 2000-05-16: Bug: was ospecname! */
2529 sfree (ospecname);
2530 return rspecname;
2531 }
2532
2533 return specname;
2534}
2535# endif
e55c0c6d 2536
2537void warnSysFiles(fileIdList files)
2538{
2539 fileIdList_elements (files, file)
2540 {
2541
2542 if (fileTable_isSystemFile (context_fileTable (), file) )
2543 {
d0fa7de4 2544 if (!context_getFlag( FLG_SYSTEMDIRERRORS ) )
2545 {
2546 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);
2547 }
e55c0c6d 2548 }
2549 }
2550 end_fileIdList_elements;
2551}
This page took 6.497344 seconds and 5 git commands to generate.