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