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