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