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