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