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