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