]>
Commit | Line | Data |
---|---|---|
616915dd | 1 | /* |
11db3170 | 2 | ** Splint - annotation-assisted static program checker |
77d37419 | 3 | ** Copyright (C) 1994-2002 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 | ** | |
155af98d | 20 | ** For information on splint: info@splint.org |
21 | ** To report a bug: splint-bug@splint.org | |
11db3170 | 22 | ** For more information: http://www.splint.org |
616915dd | 23 | */ |
24 | /* | |
25 | ** llmain.c | |
26 | ** | |
11db3170 | 27 | ** Main module for Splint annotation-assisted program checker |
616915dd | 28 | */ |
29 | ||
30 | # include <signal.h> | |
12f2ffe9 | 31 | # include <time.h> |
616915dd | 32 | /* |
33 | ** Ensure that WIN32 and _WIN32 are both defined or both undefined. | |
34 | */ | |
35 | ||
36 | # ifdef WIN32 | |
37 | # ifndef _WIN32 | |
38 | # error "Inconsistent definitions." | |
39 | # endif | |
40 | # else | |
41 | # ifdef _WIN32 | |
42 | # error "Inconsistent definitions." | |
43 | # endif | |
44 | # endif | |
45 | ||
46 | # ifdef WIN32 | |
47 | # include <windows.h> | |
48 | # include <process.h> | |
49 | # endif | |
50 | ||
1b8ae690 | 51 | # include "splintMacros.nf" |
616915dd | 52 | # include "llbasic.h" |
53 | # include "osd.h" | |
140c27a8 | 54 | # include "help.h" |
616915dd | 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 | ||
4dd72714 | 73 | # include "Headers/version.h" /* Visual C++ finds the wrong version.h */ |
616915dd | 74 | # include "lcllib.h" |
75 | # include "cgrammar.h" | |
76 | # include "llmain.h" | |
77 | # include "portab.h" | |
12f2ffe9 | 78 | |
616915dd | 79 | |
80 | extern /*@external@*/ int yydebug; | |
616915dd | 81 | static void cleanupFiles (void); |
ce7034f0 | 82 | /* |
83 | ** evans 2002-07-03: renamed from interrupt to avoid conflict with WATCOM compiler keyword | |
84 | ** (Suggested by Adam Clarke) | |
85 | */ | |
86 | ||
87 | static void llinterrupt (int p_i); | |
990ec868 | 88 | |
616915dd | 89 | static void describeVars (void); |
90 | static bool specialFlagsHelp (char *p_next); | |
91 | static bool hasShownHerald = FALSE; | |
28bf4b0b | 92 | static char *specFullName (char *p_specfile, /*@out@*/ char **p_inpath) |
93 | /*@modifies *p_inpath@*/ ; | |
616915dd | 94 | |
95 | static bool anylcl = FALSE; | |
96 | static clock_t inittime; | |
97 | ||
28bf4b0b | 98 | static fileIdList preprocessFiles (fileIdList, bool) |
616915dd | 99 | /*@modifies fileSystem@*/ ; |
100 | ||
0e5499ac | 101 | static void warnSysFiles(fileIdList p_files) /*@modifies fileSystem@*/; |
e55c0c6d | 102 | |
616915dd | 103 | # ifndef NOLCL |
104 | ||
105 | static | |
106 | void lslCleanup (void) | |
107 | /*@globals killed g_symtab@*/ | |
108 | /*@modifies internalState, g_symtab@*/ | |
109 | { | |
110 | /* | |
111 | ** Cleanup all the LCL/LSL. | |
112 | */ | |
113 | ||
114 | static bool didCleanup = FALSE; | |
115 | ||
116 | llassert (!didCleanup); | |
117 | llassert (anylcl); | |
118 | ||
119 | didCleanup = TRUE; | |
120 | ||
121 | lsymbol_destroyMod (); | |
122 | LCLSynTableCleanup (); | |
123 | LCLTokenTableCleanup (); | |
124 | LCLScanLineCleanup (); | |
125 | LCLScanCleanup (); | |
126 | ||
127 | /* clean up LSL parsing */ | |
128 | ||
129 | lsynTableCleanup (); | |
130 | ltokenTableCleanup (); | |
131 | lscanLineCleanup (); | |
132 | LSLScanCleanup (); | |
133 | ||
134 | symtable_free (g_symtab); | |
135 | sort_destroyMod (); | |
136 | } | |
137 | ||
616915dd | 138 | static void |
139 | lslProcess (fileIdList lclfiles) | |
140 | /*@globals undef g_currentSpec, undef g_currentSpecName, g_currentloc, | |
141 | undef killed g_symtab; @*/ | |
142 | /*@modifies g_currentSpec, g_currentSpecName, g_currentloc, internalState, fileSystem; @*/ | |
143 | { | |
144 | char *path = NULL; | |
145 | bool parser_status = FALSE; | |
146 | bool overallStatus = FALSE; | |
147 | ||
140c27a8 | 148 | lslinit_process (); |
149 | inittime = clock (); | |
150 | ||
616915dd | 151 | context_resetSpecLines (); |
152 | ||
153 | fileIdList_elements (lclfiles, fid) | |
154 | { | |
28bf4b0b | 155 | cstring actualName = cstring_undefined; |
4dd72714 | 156 | cstring fname = fileTable_fileName (fid); |
616915dd | 157 | |
28bf4b0b | 158 | if (osd_getPath (cstring_fromChars (g_localSpecPath), |
159 | fname, &actualName) == OSD_FILENOTFOUND) | |
616915dd | 160 | { |
161 | if (mstring_equal (g_localSpecPath, ".")) | |
162 | { | |
53a89507 | 163 | lldiagmsg (message ("Spec file not found: %q", osd_outputPath (fname))); |
616915dd | 164 | } |
165 | else | |
166 | { | |
53a89507 | 167 | lldiagmsg (message ("Spec file not found: %q (on %s)", |
168 | osd_outputPath (fname), | |
616915dd | 169 | cstring_fromChars (g_localSpecPath))); |
170 | } | |
171 | } | |
172 | else | |
173 | { | |
28bf4b0b | 174 | inputStream specFile; |
175 | /*@access cstring@*/ | |
176 | char *namePtr = actualName; | |
177 | ||
178 | while (*namePtr == '.' && *(namePtr + 1) == CONNECTCHAR) | |
616915dd | 179 | { |
28bf4b0b | 180 | namePtr += 2; |
616915dd | 181 | } |
28bf4b0b | 182 | /*@noaccess cstring@*/ |
183 | ||
184 | g_currentSpec = cstring_fromCharsNew (namePtr); | |
185 | ||
186 | specFile = inputStream_create (cstring_copy (g_currentSpec), | |
187 | LCL_EXTENSION, TRUE); | |
616915dd | 188 | |
28bf4b0b | 189 | llassert (inputStream_isDefined (specFile)); |
616915dd | 190 | |
616915dd | 191 | g_currentSpecName = specFullName |
192 | (cstring_toCharsSafe (g_currentSpec), | |
193 | &path); | |
194 | ||
195 | setSpecFileId (fid); | |
196 | ||
80489f0a | 197 | displayScan (message ("reading spec %s", g_currentSpec)); |
616915dd | 198 | |
f7bbce9e | 199 | /* Open the source file */ |
616915dd | 200 | |
28bf4b0b | 201 | if (!inputStream_open (specFile)) |
616915dd | 202 | { |
53a89507 | 203 | lldiagmsg (message ("Cannot open file: %q", |
204 | osd_outputPath (inputStream_fileName (specFile)))); | |
28bf4b0b | 205 | inputStream_free (specFile); |
616915dd | 206 | } |
207 | else | |
208 | { | |
209 | scopeInfo dummy_scope = (scopeInfo) dmalloc (sizeof (*dummy_scope)); | |
210 | dummy_scope->kind = SPE_INVALID; | |
211 | ||
212 | lhInit (specFile); | |
213 | LCLScanReset (specFile); | |
214 | ||
215 | /* | |
216 | ** Minor hacks to allow more than one LCL file to | |
217 | ** be scanned, while keeping initializations | |
218 | */ | |
219 | ||
220 | symtable_enterScope (g_symtab, dummy_scope); | |
221 | resetImports (cstring_fromChars (g_currentSpecName)); | |
222 | context_enterLCLfile (); | |
223 | (void) lclHadNewError (); | |
224 | ||
225 | parser_status = (ylparse () != 0); | |
226 | context_exitLCLfile (); | |
227 | lhCleanup (); | |
228 | overallStatus = parser_status || lclHadNewError (); | |
229 | ||
230 | if (context_getFlag (FLG_DOLCS)) | |
231 | { | |
232 | if (overallStatus) | |
233 | { | |
28bf4b0b | 234 | outputLCSFile (path, "%FAILED Output from ", |
616915dd | 235 | g_currentSpecName); |
236 | } | |
237 | else | |
238 | { | |
28bf4b0b | 239 | outputLCSFile (path, "%PASSED Output from ", |
616915dd | 240 | g_currentSpecName); |
241 | } | |
242 | } | |
243 | ||
28bf4b0b | 244 | (void) inputStream_close (specFile); |
245 | inputStream_free (specFile); | |
616915dd | 246 | |
247 | symtable_exitScope (g_symtab); | |
28bf4b0b | 248 | } |
616915dd | 249 | } |
28bf4b0b | 250 | cstring_free (actualName); |
616915dd | 251 | } end_fileIdList_elements; |
28bf4b0b | 252 | |
616915dd | 253 | /* Can cleanup lsl stuff right away */ |
28bf4b0b | 254 | |
255 | lslCleanup (); | |
256 | ||
257 | g_currentSpec = cstring_undefined; | |
258 | g_currentSpecName = NULL; | |
616915dd | 259 | } |
260 | # endif | |
261 | ||
262 | static void handlePassThroughFlag (char *arg) | |
263 | { | |
264 | char *curarg = arg; | |
265 | char *quotechar = strchr (curarg, '\"'); | |
266 | int offset = 0; | |
267 | bool open = FALSE; | |
b37cf05e | 268 | char *freearg = NULL; |
616915dd | 269 | |
270 | while (quotechar != NULL) | |
271 | { | |
272 | if (*(quotechar - 1) == '\\') | |
273 | { | |
274 | char *tp = quotechar - 2; | |
275 | bool escape = TRUE; | |
276 | ||
277 | while (*tp == '\\') | |
278 | { | |
279 | escape = !escape; | |
280 | tp--; | |
281 | } | |
282 | ||
283 | if (escape) | |
284 | { | |
285 | curarg = quotechar + 1; | |
286 | quotechar = strchr (curarg, '\"'); | |
287 | continue; | |
288 | } | |
289 | } | |
290 | ||
b37cf05e | 291 | llassert (quotechar != NULL); |
616915dd | 292 | *quotechar = '\0'; |
293 | offset = (quotechar - arg) + 2; | |
294 | ||
295 | if (open) | |
296 | { | |
297 | arg = cstring_toCharsSafe | |
298 | (message ("%s\"\'%s", | |
299 | cstring_fromChars (arg), | |
300 | cstring_fromChars (quotechar + 1))); | |
b37cf05e | 301 | freearg = arg; |
616915dd | 302 | open = FALSE; |
303 | } | |
304 | else | |
305 | { | |
306 | arg = cstring_toCharsSafe | |
307 | (message ("%s\'\"%s", | |
308 | cstring_fromChars (arg), | |
309 | cstring_fromChars (quotechar + 1))); | |
b37cf05e | 310 | freearg = arg; |
616915dd | 311 | open = TRUE; |
312 | } | |
313 | ||
314 | curarg = arg + offset; | |
315 | quotechar = strchr (curarg, '\"'); | |
316 | } | |
317 | ||
318 | if (open) | |
319 | { | |
320 | showHerald (); | |
ccf0a4a8 | 321 | voptgenerror (FLG_BADFLAG, |
322 | message ("Unclosed quote in flag: %s", | |
323 | cstring_fromChars (arg)), | |
324 | g_currentloc); | |
616915dd | 325 | } |
326 | else | |
327 | { | |
328 | if (arg[0] == 'D') { | |
329 | cstring def; | |
330 | ||
331 | /* | |
332 | ** If the value is surrounded by single quotes ('), remove | |
333 | ** them. This is an artifact of UNIX command line? | |
334 | */ | |
335 | ||
28bf4b0b | 336 | def = osd_fixDefine (cstring_fromChars (arg + 1)); |
616915dd | 337 | DPRINTF (("Do define: %s", def)); |
338 | cppDoDefine (def); | |
339 | DPRINTF (("After define")); | |
340 | cstring_free (def); | |
341 | } else if (arg[0] == 'U') { | |
342 | cppDoUndefine (cstring_fromChars (arg + 1)); | |
343 | } else { | |
344 | BADBRANCH; | |
345 | } | |
346 | } | |
b37cf05e | 347 | |
348 | sfree (freearg); | |
616915dd | 349 | } |
350 | ||
351 | void showHerald (void) | |
352 | { | |
80489f0a | 353 | if (hasShownHerald || context_getFlag (FLG_QUIET)) |
354 | { | |
355 | return; | |
356 | } | |
616915dd | 357 | else |
358 | { | |
80489f0a | 359 | fprintf (g_messagestream, "%s\n\n", SPLINT_VERSION); |
616915dd | 360 | hasShownHerald = TRUE; |
361 | llflush (); | |
362 | } | |
363 | } | |
364 | ||
616915dd | 365 | /* |
1b8ae690 | 366 | ** Disable MSVC++ warning about return value. Methinks humbly splint control |
616915dd | 367 | ** comments are a mite more legible. |
368 | */ | |
369 | ||
370 | # ifdef WIN32 | |
371 | # pragma warning (disable:4035) | |
372 | # endif | |
373 | ||
374 | int main (int argc, char *argv[]) | |
375 | # ifdef NOLCL | |
376 | /*@globals killed undef g_currentloc, | |
377 | killed undef yyin, | |
80489f0a | 378 | undef g_warningstream, g_messagestream, g_errorstream; |
616915dd | 379 | @*/ |
380 | /*@modifies g_currentloc, fileSystem, | |
381 | yyin; | |
382 | @*/ | |
383 | # else | |
384 | /*@globals killed undef g_currentloc, | |
616915dd | 385 | killed g_localSpecPath, |
386 | killed undef g_currentSpec, | |
387 | killed undef g_currentSpecName, | |
388 | killed undef yyin, | |
80489f0a | 389 | undef g_warningstream, g_messagestream, g_errorstream; |
616915dd | 390 | @*/ |
140c27a8 | 391 | /*@modifies g_currentloc, g_localSpecPath, g_currentSpec, g_currentSpecName, |
392 | fileSystem, yyin; | |
616915dd | 393 | @*/ |
394 | # endif | |
395 | { | |
396 | bool first_time = TRUE; | |
616915dd | 397 | bool expsuccess; |
28bf4b0b | 398 | inputStream sourceFile = inputStream_undefined; |
616915dd | 399 | |
400 | fileIdList dercfiles; | |
616915dd | 401 | cstringSList passThroughArgs = cstringSList_undefined; |
28bf4b0b | 402 | fileIdList cfiles, xfiles, lclfiles, mtfiles; |
616915dd | 403 | clock_t before, lcltime, libtime, pptime, cptime, rstime; |
404 | int i = 0; | |
405 | ||
22367f91 | 406 | # ifdef __EMX__ |
407 | _wildcard (&argc, &argv); | |
408 | # endif | |
409 | ||
80489f0a | 410 | g_warningstream = stdout; |
411 | g_messagestream = stderr; | |
412 | g_errorstream = stderr; | |
616915dd | 413 | |
ce7034f0 | 414 | (void) signal (SIGINT, llinterrupt); |
415 | (void) signal (SIGSEGV, llinterrupt); | |
616915dd | 416 | |
616915dd | 417 | flags_initMod (); |
28bf4b0b | 418 | clabstract_initMod (); |
616915dd | 419 | typeIdSet_initMod (); |
420 | cppReader_initMod (); | |
53a89507 | 421 | osd_initMod (); |
422 | ||
616915dd | 423 | setCodePoint (); |
28bf4b0b | 424 | |
616915dd | 425 | g_currentloc = fileloc_createBuiltin (); |
80489f0a | 426 | |
616915dd | 427 | before = clock (); |
428 | context_initMod (); | |
28bf4b0b | 429 | |
616915dd | 430 | context_setInCommandLine (); |
431 | ||
432 | if (argc <= 1) | |
433 | { | |
140c27a8 | 434 | help_showAvailableHelp (); |
aa9c1601 | 435 | llexit (LLSUCCESS); |
436 | } | |
437 | ||
438 | /* -help must be the first flag to get help */ | |
140c27a8 | 439 | if (flagcode_isHelpFlag (flags_identifyFlag (cstring_fromChars (argv[1])))) |
aa9c1601 | 440 | { |
140c27a8 | 441 | /* |
442 | ** Skip first flag and help flag | |
443 | */ | |
444 | ||
445 | help_processFlags (argc - 2, argv + 2); | |
aa9c1601 | 446 | llexit (LLSUCCESS); |
616915dd | 447 | } |
448 | ||
449 | setCodePoint (); | |
450 | yydebug = 0; | |
451 | ||
452 | /* | |
453 | ** Add include directories from environment. | |
454 | */ | |
455 | ||
456 | { | |
7272a1c1 | 457 | cstring incval = cstring_copy (osd_getEnvironmentVariable (INCLUDEPATH_VAR)); |
b37cf05e | 458 | cstring oincval = incval; |
616915dd | 459 | |
28bf4b0b | 460 | if (cstring_isDefined (incval)) |
616915dd | 461 | { |
462 | /* | |
463 | ** Each directory on the include path is a system include directory. | |
464 | */ | |
465 | ||
466 | DPRINTF (("include: %s", incval)); | |
28bf4b0b | 467 | context_setString (FLG_SYSTEMDIRS, cstring_copy (incval)); |
616915dd | 468 | |
28bf4b0b | 469 | while (cstring_isDefined (incval)) |
616915dd | 470 | { |
28bf4b0b | 471 | /*@access cstring@*/ |
7272a1c1 | 472 | char *nextsep = strchr (incval, PATH_SEPARATOR); |
616915dd | 473 | |
474 | if (nextsep != NULL) | |
475 | { | |
476 | cstring dir; | |
477 | *nextsep = '\0'; | |
28bf4b0b | 478 | dir = cstring_copy (incval); |
616915dd | 479 | |
480 | if (cstring_length (dir) == 0 | |
481 | || !isalpha ((int) cstring_firstChar (dir))) | |
482 | { | |
483 | /* | |
484 | ** win32 environment values can have special values, | |
485 | ** ignore them | |
486 | */ | |
487 | } | |
488 | else | |
489 | { | |
616915dd | 490 | cppAddIncludeDir (dir); |
491 | } | |
492 | ||
7272a1c1 | 493 | *nextsep = PATH_SEPARATOR; |
28bf4b0b | 494 | incval = cstring_fromChars (nextsep + 1); |
616915dd | 495 | cstring_free (dir); |
496 | } | |
497 | else | |
498 | { | |
499 | break; | |
500 | } | |
28bf4b0b | 501 | |
502 | /*@noaccess cstring@*/ | |
616915dd | 503 | } |
504 | } | |
68de3f33 | 505 | else /* 2001-09-09: herbert */ |
506 | { | |
507 | /* Put C_INCLUDE_PATH directories in sysdirs */ | |
508 | cstring cincval = osd_getEnvironmentVariable (cstring_makeLiteralTemp ("C_INCLUDE_PATH")); | |
aa9c1601 | 509 | |
68de3f33 | 510 | if (cstring_isDefined (cincval)) |
511 | { | |
512 | context_setString (FLG_SYSTEMDIRS, cstring_copy (cincval)); | |
513 | } | |
514 | } | |
515 | /* /herbert */ | |
28bf4b0b | 516 | |
b37cf05e | 517 | cstring_free (oincval); |
616915dd | 518 | } |
519 | ||
520 | /* | |
521 | ** check RCFILE for default flags | |
522 | */ | |
523 | ||
140c27a8 | 524 | /* |
525 | ** Process command line message formatting flags before reading rc file | |
526 | */ | |
527 | ||
616915dd | 528 | { |
28bf4b0b | 529 | cstring home = osd_getHomeDir (); |
60868d40 | 530 | cstring fname = cstring_undefined; |
616915dd | 531 | bool defaultf = TRUE; |
532 | bool nof = FALSE; | |
533 | ||
534 | for (i = 1; i < argc; i++) | |
535 | { | |
536 | char *thisarg; | |
537 | thisarg = argv[i]; | |
538 | ||
539 | if (*thisarg == '-' || *thisarg == '+') | |
540 | { | |
f2b6724f | 541 | bool set = (*thisarg == '+'); |
542 | flagcode opt; | |
543 | ||
616915dd | 544 | thisarg++; |
a956d444 | 545 | |
546 | /* | |
547 | ** Don't report warnings this time | |
548 | */ | |
549 | ||
550 | opt = flags_identifyFlagQuiet (cstring_fromChars (thisarg)); | |
616915dd | 551 | |
f2b6724f | 552 | if (opt == FLG_NOF) |
616915dd | 553 | { |
554 | nof = TRUE; | |
555 | } | |
80489f0a | 556 | else if (flagcode_isMessageControlFlag (opt)) |
f2b6724f | 557 | { |
558 | /* | |
559 | ** Need to set it immediately, so rc file scan is displayed | |
560 | */ | |
561 | ||
562 | context_userSetFlag (opt, set); | |
80489f0a | 563 | |
564 | if (flagcode_hasArgument (opt)) | |
565 | { | |
566 | llassert (flagcode_hasString (opt)); | |
567 | ||
568 | if (++i < argc) | |
569 | { | |
570 | fname = cstring_fromChars (argv[i]); | |
571 | setStringFlag (opt, fname); | |
572 | } | |
573 | else | |
574 | { | |
140c27a8 | 575 | voptgenerror |
576 | (FLG_BADFLAG, | |
577 | message | |
80489f0a | 578 | ("Flag %s must be followed by a string", |
140c27a8 | 579 | flagcode_unparse (opt)), |
580 | g_currentloc); | |
80489f0a | 581 | } |
582 | } | |
f2b6724f | 583 | } |
584 | else if (opt == FLG_OPTF) | |
616915dd | 585 | { |
586 | if (++i < argc) | |
587 | { | |
588 | defaultf = FALSE; | |
60868d40 | 589 | fname = cstring_fromChars (argv[i]); |
140c27a8 | 590 | (void) rcfiles_read (fname, &passThroughArgs, TRUE); |
616915dd | 591 | } |
592 | else | |
593 | llfatalerror | |
594 | (cstring_makeLiteral ("Flag f to select options file " | |
595 | "requires an argument")); | |
596 | } | |
597 | else | |
598 | { | |
599 | ; /* wait to process later */ | |
600 | } | |
601 | } | |
602 | } | |
f2b6724f | 603 | |
616915dd | 604 | setCodePoint (); |
605 | ||
606 | if (!nof && defaultf) | |
607 | { | |
60868d40 | 608 | /* |
f2b6724f | 609 | ** No explicit rc file, first try reading ~/.splintrc |
60868d40 | 610 | */ |
616915dd | 611 | |
f2b6724f | 612 | if (cstring_isUndefined (fname)) |
60868d40 | 613 | { |
f2b6724f | 614 | if (!cstring_isEmpty (home)) |
60868d40 | 615 | { |
f2b6724f | 616 | bool readhomerc, readaltrc; |
617 | cstring homename, altname; | |
618 | ||
619 | homename = message ("%s%h%s", home, CONNECTCHAR, | |
620 | cstring_fromChars (RCFILE)); | |
140c27a8 | 621 | readhomerc = rcfiles_read (homename, &passThroughArgs, FALSE); |
60868d40 | 622 | |
f2b6724f | 623 | /* |
1b8ae690 | 624 | ** Try ~/.splintrc also for historical accuracy |
f2b6724f | 625 | */ |
626 | ||
627 | altname = message ("%s%h%s", home, CONNECTCHAR, | |
628 | cstring_fromChars (ALTRCFILE)); | |
140c27a8 | 629 | readaltrc = rcfiles_read (altname, &passThroughArgs, FALSE); |
f2b6724f | 630 | |
631 | if (readhomerc && readaltrc) | |
632 | { | |
633 | ||
634 | voptgenerror | |
635 | (FLG_WARNRC, | |
636 | message ("Found both %s and %s files. Using both files, " | |
637 | "but recommend using only %s to avoid confusion.", | |
638 | homename, altname, homename), | |
639 | g_currentloc); | |
640 | } | |
146e25eb | 641 | |
642 | cstring_free (homename); | |
643 | cstring_free (altname); | |
60868d40 | 644 | } |
645 | } | |
646 | ||
f2b6724f | 647 | /* |
648 | ** Next, read .splintrc in the current working directory | |
649 | */ | |
650 | ||
651 | { | |
652 | cstring rcname = message ("%s%s",osd_getCurrentDirectory (), cstring_fromChars (RCFILE)); | |
653 | cstring altname = message ("%s%s",osd_getCurrentDirectory (), cstring_fromChars (ALTRCFILE)); | |
654 | bool readrc, readaltrc; | |
655 | ||
140c27a8 | 656 | readrc = rcfiles_read (rcname, &passThroughArgs, FALSE); |
657 | readaltrc = rcfiles_read (altname, &passThroughArgs, FALSE); | |
f2b6724f | 658 | |
659 | if (readrc && readaltrc) | |
660 | { | |
661 | voptgenerror (FLG_WARNRC, | |
662 | message ("Found both %s and %s files. Using both files, " | |
663 | "but recommend using only %s to avoid confusion.", | |
664 | rcname, altname, rcname), | |
665 | g_currentloc); | |
666 | ||
667 | } | |
616915dd | 668 | |
f2b6724f | 669 | cstring_free (rcname); |
670 | cstring_free (altname); | |
671 | } | |
616915dd | 672 | } |
673 | } | |
674 | ||
675 | setCodePoint (); | |
140c27a8 | 676 | llassert (fileloc_isBuiltin (g_currentloc)); |
677 | ||
678 | cfiles = fileIdList_create (); | |
679 | xfiles = fileIdList_create (); | |
680 | lclfiles = fileIdList_create (); | |
681 | mtfiles = fileIdList_create (); | |
28bf4b0b | 682 | |
aa9c1601 | 683 | /* argv[0] is the program name, don't pass it to flags_processFlags */ |
140c27a8 | 684 | flags_processFlags (TRUE, xfiles, cfiles, |
685 | lclfiles, mtfiles, | |
686 | &passThroughArgs, | |
687 | argc - 1, argv + 1); | |
616915dd | 688 | |
f2b6724f | 689 | showHerald (); |
690 | ||
616915dd | 691 | # ifdef DOANNOTS |
692 | initAnnots (); | |
693 | # endif | |
694 | ||
695 | inittime = clock (); | |
696 | ||
697 | context_resetErrors (); | |
698 | context_clearInCommandLine (); | |
699 | ||
700 | anylcl = !fileIdList_isEmpty (lclfiles); | |
701 | ||
702 | if (context_doMerge ()) | |
703 | { | |
704 | cstring m = context_getMerge (); | |
705 | ||
80489f0a | 706 | displayScanOpen (message ("< loading %s ", m)); |
616915dd | 707 | loadState (m); |
80489f0a | 708 | displayScanClose (); |
616915dd | 709 | |
710 | if (!usymtab_existsType (context_getBoolName ())) | |
711 | { | |
712 | usymtab_initBool (); | |
713 | } | |
714 | } | |
715 | else | |
716 | { | |
717 | if (!context_getFlag (FLG_NOLIB) && loadStandardState ()) | |
718 | { | |
719 | ; | |
720 | } | |
721 | else | |
722 | { | |
723 | ctype_initTable (); | |
724 | } | |
725 | ||
726 | /* setup bool type and constants */ | |
727 | usymtab_initBool (); | |
728 | } | |
729 | ||
730 | fileloc_free (g_currentloc); | |
731 | g_currentloc = fileloc_createBuiltin (); | |
732 | ||
28bf4b0b | 733 | /* |
734 | ** Read metastate files (must happen before loading libraries) | |
735 | */ | |
736 | ||
737 | fileIdList_elements (mtfiles, mtfile) | |
738 | { | |
739 | context_setFileId (mtfile); | |
80489f0a | 740 | displayScan (message ("processing %s", fileTable_rootFileName (mtfile))); |
4dd72714 | 741 | mtreader_readFile (cstring_copy (fileTable_fileName (mtfile))); |
28bf4b0b | 742 | } end_fileIdList_elements; |
743 | ||
616915dd | 744 | libtime = clock (); |
28bf4b0b | 745 | |
616915dd | 746 | if (anylcl) |
747 | { | |
748 | # ifdef NOLCL | |
11db3170 | 749 | llfatalerror (cstring_makeLiteral ("This version of Splint does not handle LCL files.")); |
616915dd | 750 | # else |
751 | lslProcess (lclfiles); | |
752 | # endif | |
753 | } | |
754 | ||
28bf4b0b | 755 | usymtab_initGlobalMarker (); |
756 | ||
616915dd | 757 | /* |
758 | ** pre-processing | |
759 | ** | |
760 | ** call the pre-preprocessor and /lib/cpp to generate appropriate | |
761 | ** files | |
762 | ** | |
763 | */ | |
764 | ||
765 | context_setInCommandLine (); | |
140c27a8 | 766 | |
616915dd | 767 | DPRINTF (("Pass through: %s", cstringSList_unparse (passThroughArgs))); |
768 | ||
140c27a8 | 769 | cstringSList_elements (passThroughArgs, thisarg) |
770 | { | |
771 | handlePassThroughFlag (cstring_toCharsSafe (thisarg)); | |
772 | } | |
773 | end_cstringSList_elements; | |
616915dd | 774 | |
775 | cstringSList_free (passThroughArgs); | |
776 | ||
777 | cleanupMessages (); | |
778 | ||
28bf4b0b | 779 | DPRINTF (("Initializing cpp reader!")); |
780 | cppReader_initialize (); | |
616915dd | 781 | cppReader_saveDefinitions (); |
782 | ||
783 | context_clearInCommandLine (); | |
784 | ||
785 | if (!context_getFlag (FLG_NOPP)) | |
786 | { | |
28bf4b0b | 787 | fileIdList tfiles; |
788 | ||
616915dd | 789 | llflush (); |
790 | ||
80489f0a | 791 | displayScanOpen (cstring_makeLiteral ("preprocessing")); |
616915dd | 792 | |
793 | lcltime = clock (); | |
794 | ||
795 | context_setPreprocessing (); | |
28bf4b0b | 796 | dercfiles = preprocessFiles (xfiles, TRUE); |
797 | tfiles = preprocessFiles (cfiles, FALSE); | |
e55c0c6d | 798 | warnSysFiles(cfiles); |
28bf4b0b | 799 | dercfiles = fileIdList_append (dercfiles, tfiles); |
800 | fileIdList_free (tfiles); | |
801 | ||
616915dd | 802 | context_clearPreprocessing (); |
803 | ||
804 | fileIdList_free (cfiles); | |
805 | ||
80489f0a | 806 | displayScanClose (); |
616915dd | 807 | pptime = clock (); |
808 | } | |
809 | else | |
810 | { | |
811 | lcltime = clock (); | |
28bf4b0b | 812 | dercfiles = fileIdList_append (cfiles, xfiles); |
616915dd | 813 | pptime = clock (); |
814 | } | |
28bf4b0b | 815 | |
616915dd | 816 | /* |
817 | ** now, check all the corresponding C files | |
818 | ** | |
819 | ** (for now these are just <file>.c, but after pre-processing | |
820 | ** will be <tmpprefix>.<file>.c) | |
821 | */ | |
822 | ||
823 | { | |
824 | # ifdef WIN32 | |
825 | int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/ | |
826 | ||
827 | if (nfiles != 0) | |
828 | { | |
829 | llbug (message ("Files unclosed: %d", nfiles)); | |
830 | } | |
831 | # endif | |
832 | } | |
833 | ||
28bf4b0b | 834 | DPRINTF (("Initializing...")); |
835 | ||
616915dd | 836 | exprNode_initMod (); |
837 | ||
28bf4b0b | 838 | DPRINTF (("Okay...")); |
839 | ||
616915dd | 840 | fileIdList_elements (dercfiles, fid) |
841 | { | |
4dd72714 | 842 | sourceFile = inputStream_create (cstring_copy (fileTable_fileName (fid)), C_EXTENSION, TRUE); |
616915dd | 843 | context_setFileId (fid); |
844 | ||
845 | /* Open source file */ | |
846 | ||
28bf4b0b | 847 | if (inputStream_isUndefined (sourceFile) || (!inputStream_open (sourceFile))) |
616915dd | 848 | { |
849 | /* previously, this was ignored ?! */ | |
4dd72714 | 850 | llbug (message ("Could not open temp file: %s", fileTable_fileName (fid))); |
616915dd | 851 | } |
852 | else | |
853 | { | |
28bf4b0b | 854 | yyin = inputStream_getFile (sourceFile); /*< shared <- only */ |
616915dd | 855 | |
856 | llassert (yyin != NULL); | |
857 | ||
80489f0a | 858 | displayScan (message ("checking %q", osd_outputPath (fileTable_rootFileName (fid)))); |
616915dd | 859 | |
860 | /* | |
861 | ** Every time, except the first time, through the loop, | |
862 | ** need to call yyrestart to clean up the parse buffer. | |
863 | */ | |
864 | ||
865 | if (!first_time) | |
866 | { | |
867 | (void) yyrestart (yyin); | |
868 | } | |
869 | else | |
870 | { | |
871 | first_time = FALSE; | |
872 | } | |
873 | ||
28bf4b0b | 874 | DPRINTF (("Entering...")); |
616915dd | 875 | context_enterFile (); |
876 | (void) yyparse (); | |
28bf4b0b | 877 | context_exitCFile (); |
616915dd | 878 | |
28bf4b0b | 879 | (void) inputStream_close (sourceFile); |
880 | } | |
616915dd | 881 | } end_fileIdList_elements; |
882 | ||
883 | cptime = clock (); | |
884 | ||
885 | /* process any leftover macros */ | |
886 | ||
887 | context_processAllMacros (); | |
888 | ||
889 | /* check everything that was specified was defined */ | |
890 | ||
891 | /* don't check if no c files were processed ? | |
892 | ** is this correct behaviour? | |
893 | */ | |
894 | ||
80489f0a | 895 | displayScan (cstring_makeLiteral ("global checks")); |
616915dd | 896 | |
897 | cleanupMessages (); | |
898 | ||
899 | if (context_getLinesProcessed () > 0) | |
900 | { | |
901 | usymtab_allDefined (); | |
902 | } | |
903 | ||
904 | if (context_maybeSet (FLG_TOPUNUSED)) | |
905 | { | |
906 | uentry ue = usymtab_lookupSafe (cstring_makeLiteralTemp ("main")); | |
907 | ||
908 | if (uentry_isValid (ue)) | |
909 | { | |
910 | uentry_setUsed (ue, fileloc_observeBuiltin ()); | |
911 | } | |
912 | ||
913 | usymtab_allUsed (); | |
914 | } | |
915 | ||
916 | if (context_maybeSet (FLG_EXPORTLOCAL)) | |
917 | { | |
918 | usymtab_exportLocal (); | |
919 | } | |
920 | ||
921 | ||
922 | if (context_maybeSet (FLG_EXPORTHEADER)) | |
923 | { | |
924 | usymtab_exportHeader (); | |
925 | } | |
926 | ||
927 | if (context_getFlag (FLG_SHOWUSES)) | |
928 | { | |
929 | usymtab_displayAllUses (); | |
930 | } | |
931 | ||
932 | context_checkSuppressCounts (); | |
933 | ||
934 | if (context_doDump ()) | |
935 | { | |
936 | cstring dump = context_getDump (); | |
937 | ||
938 | dumpState (dump); | |
939 | } | |
940 | ||
941 | # ifdef DOANNOTS | |
942 | printAnnots (); | |
943 | # endif | |
944 | ||
945 | cleanupFiles (); | |
946 | ||
947 | if (context_getFlag (FLG_SHOWSUMMARY)) | |
948 | { | |
949 | summarizeErrors (); | |
950 | } | |
951 | ||
952 | ||
953 | { | |
954 | bool isQuiet = context_getFlag (FLG_QUIET); | |
955 | cstring specErrors = cstring_undefined; | |
956 | # ifndef NOLCL | |
957 | int nspecErrors = lclNumberErrors (); | |
958 | # endif | |
959 | ||
960 | expsuccess = TRUE; | |
961 | ||
962 | if (context_neednl ()) | |
80489f0a | 963 | fprintf (g_warningstream, "\n"); |
616915dd | 964 | |
965 | # ifndef NOLCL | |
966 | if (nspecErrors > 0) | |
967 | { | |
968 | if (nspecErrors == context_getLCLExpect ()) | |
969 | { | |
970 | specErrors = | |
11db3170 | 971 | message ("%d spec warning%&, as expected\n ", |
616915dd | 972 | nspecErrors); |
973 | } | |
974 | else | |
975 | { | |
976 | if (context_getLCLExpect () > 0) | |
977 | { | |
978 | specErrors = | |
11db3170 | 979 | message ("%d spec warning%&, expected %d\n ", |
616915dd | 980 | nspecErrors, |
981 | (int) context_getLCLExpect ()); | |
982 | } | |
983 | else | |
984 | { | |
2e127cb8 | 985 | specErrors = message ("%d spec warning%&\n ", |
616915dd | 986 | nspecErrors); |
987 | expsuccess = FALSE; | |
988 | } | |
989 | } | |
990 | } | |
991 | else | |
992 | { | |
993 | if (context_getLCLExpect () > 0) | |
994 | { | |
11db3170 | 995 | specErrors = message ("No spec warnings, expected %d\n ", |
616915dd | 996 | (int) context_getLCLExpect ()); |
997 | expsuccess = FALSE; | |
998 | } | |
999 | } | |
1000 | # endif | |
1001 | ||
1002 | if (context_anyErrors ()) | |
1003 | { | |
1004 | if (context_numErrors () == context_getExpect ()) | |
1005 | { | |
1006 | if (!isQuiet) { | |
11db3170 | 1007 | llmsg (message ("Finished checking --- " |
1008 | "%s%d code warning%&, as expected", | |
616915dd | 1009 | specErrors, context_numErrors ())); |
1010 | } | |
1011 | } | |
1012 | else | |
1013 | { | |
1014 | if (context_getExpect () > 0) | |
1015 | { | |
1016 | if (!isQuiet) { | |
1017 | llmsg (message | |
11db3170 | 1018 | ("Finished checking --- " |
1019 | "%s%d code warning%&, expected %d", | |
616915dd | 1020 | specErrors, context_numErrors (), |
1021 | (int) context_getExpect ())); | |
1022 | } | |
1023 | ||
1024 | expsuccess = FALSE; | |
1025 | } | |
1026 | else | |
1027 | { | |
1028 | ||
28bf4b0b | 1029 | if (!isQuiet) |
1030 | { | |
11db3170 | 1031 | llmsg (message ("Finished checking --- " |
2e127cb8 | 1032 | "%s%d code warning%&", |
28bf4b0b | 1033 | specErrors, context_numErrors ())); |
1034 | } | |
616915dd | 1035 | |
1036 | expsuccess = FALSE; | |
1037 | } | |
1038 | } | |
1039 | } | |
1040 | else | |
1041 | { | |
1042 | if (context_getExpect () > 0) | |
1043 | { | |
1044 | if (!isQuiet) { | |
1045 | llmsg (message | |
11db3170 | 1046 | ("Finished checking --- " |
1047 | "%sno code warnings, expected %d", | |
616915dd | 1048 | specErrors, |
1049 | (int) context_getExpect ())); | |
1050 | } | |
1051 | ||
1052 | expsuccess = FALSE; | |
1053 | } | |
1054 | else | |
1055 | { | |
1056 | if (context_getLinesProcessed () > 0) | |
1057 | { | |
11db3170 | 1058 | if (cstring_isEmpty (specErrors)) |
1059 | { | |
1060 | if (!isQuiet) | |
1061 | { | |
1062 | llmsg (message ("Finished checking --- no warnings")); | |
1063 | } | |
1064 | } | |
1065 | else | |
146e25eb | 1066 | { |
11db3170 | 1067 | if (!isQuiet) |
1068 | { | |
1069 | llmsg (message ("Finished checking --- %sno code warnings", | |
1070 | specErrors)); | |
1071 | } | |
146e25eb | 1072 | } |
616915dd | 1073 | } |
1074 | else | |
1075 | { | |
1076 | if (!isQuiet) { | |
11db3170 | 1077 | llmsg (message ("Finished checking --- %sno code processed", |
616915dd | 1078 | specErrors)); |
1079 | } | |
1080 | } | |
1081 | } | |
1082 | } | |
1083 | ||
1084 | cstring_free (specErrors); | |
1085 | } | |
1086 | ||
1087 | if (context_getFlag (FLG_STATS)) | |
1088 | { | |
1089 | clock_t ttime = clock () - before; | |
1090 | int specLines = context_getSpecLinesProcessed (); | |
140c27a8 | 1091 | cstring specmsg = cstring_undefined; |
1092 | ||
616915dd | 1093 | rstime = clock (); |
1094 | ||
1095 | if (specLines > 0) | |
1096 | { | |
140c27a8 | 1097 | specmsg = message ("%d spec, ", specLines); |
616915dd | 1098 | } |
1099 | ||
1100 | # ifndef CLOCKS_PER_SEC | |
140c27a8 | 1101 | lldiagmsg (message ("%s%d source lines in %d time steps (steps/sec unknown)\n", |
1102 | specmsg, | |
1103 | context_getLinesProcessed (), | |
1104 | (int) ttime)); | |
616915dd | 1105 | # else |
140c27a8 | 1106 | lldiagmsg (message ("%s%d source lines in %f s.\n", |
1107 | specmsg, | |
1108 | context_getLinesProcessed (), | |
1109 | (double) ttime / CLOCKS_PER_SEC)); | |
616915dd | 1110 | # endif |
1111 | } | |
1112 | else | |
1113 | { | |
1114 | rstime = clock (); | |
1115 | } | |
1116 | ||
1117 | if (context_getFlag (FLG_TIMEDIST)) | |
1118 | { | |
1119 | clock_t ttime = clock () - before; | |
1120 | ||
1121 | if (ttime > 0) | |
1122 | { | |
1123 | char *msg = (char *) dmalloc (256 * sizeof (*msg)); | |
1124 | ||
1125 | if (anylcl) | |
1126 | { | |
1127 | sprintf (msg, | |
1128 | "Time distribution (percent): initialize %.2f / lcl %.2f / " | |
1129 | "pre-process %.2f / c check %.2f / finalize %.2f \n", | |
1130 | (100.0 * (double) (libtime - before) / ttime), | |
1131 | (100.0 * (double) (lcltime - libtime) / ttime), | |
1132 | (100.0 * (double) (pptime - lcltime) / ttime), | |
1133 | (100.0 * (double) (cptime - pptime) / ttime), | |
1134 | (100.0 * (double) (rstime - cptime) / ttime)); | |
1135 | } | |
1136 | else | |
1137 | { | |
1138 | sprintf (msg, | |
1139 | "Time distribution (percent): initialize %.2f / " | |
1140 | "pre-process %.2f / c check %.2f / finalize %.2f \n", | |
1141 | (100.0 * (double) (libtime - before) / ttime), | |
1142 | (100.0 * (double) (pptime - libtime) / ttime), | |
1143 | (100.0 * (double) (cptime - pptime) / ttime), | |
1144 | (100.0 * (double) (rstime - cptime) / ttime)); | |
1145 | } | |
1146 | ||
1147 | llgenindentmsgnoloc (cstring_fromCharsO (msg)); | |
1148 | } | |
1149 | } | |
1150 | ||
1151 | llexit (expsuccess ? LLSUCCESS : LLFAILURE); | |
8250fa4a | 1152 | BADBRANCHRET (LLFAILURE); |
616915dd | 1153 | } |
1154 | ||
28bf4b0b | 1155 | # ifdef WIN32 |
616915dd | 1156 | /* |
1157 | ** Reenable return value warnings. | |
1158 | */ | |
28bf4b0b | 1159 | # pragma warning (default:4035) |
1160 | # endif | |
616915dd | 1161 | |
616915dd | 1162 | void |
ce7034f0 | 1163 | llinterrupt (int i) |
616915dd | 1164 | { |
1165 | switch (i) | |
1166 | { | |
1167 | case SIGINT: | |
80489f0a | 1168 | fprintf (g_errorstream, "*** Interrupt\n"); |
616915dd | 1169 | llexit (LLINTERRUPT); |
1170 | case SIGSEGV: | |
1171 | { | |
1172 | cstring loc; | |
1173 | ||
1174 | /* Cheat when there are parse errors */ | |
1175 | checkParseError (); | |
1176 | ||
80489f0a | 1177 | fprintf (g_errorstream, "*** Segmentation Violation\n"); |
616915dd | 1178 | |
1179 | /* Don't catch it if fileloc_unparse causes a signal */ | |
1180 | (void) signal (SIGSEGV, NULL); | |
1181 | ||
1182 | loc = fileloc_unparse (g_currentloc); | |
1183 | ||
80489f0a | 1184 | fprintf (g_errorstream, "*** Location (not trusted): %s\n", |
616915dd | 1185 | cstring_toCharsSafe (loc)); |
1186 | cstring_free (loc); | |
1187 | printCodePoint (); | |
80489f0a | 1188 | fprintf (g_errorstream, "*** Please report bug to %s\n", SPLINT_MAINTAINER); |
616915dd | 1189 | exit (LLGIVEUP); |
1190 | } | |
1191 | default: | |
80489f0a | 1192 | fprintf (g_errorstream, "*** Signal: %d\n", i); |
616915dd | 1193 | /*@-mustfree@*/ |
80489f0a | 1194 | fprintf (g_errorstream, "*** Location (not trusted): %s\n", |
616915dd | 1195 | cstring_toCharsSafe (fileloc_unparse (g_currentloc))); |
1196 | /*@=mustfree@*/ | |
1197 | printCodePoint (); | |
80489f0a | 1198 | fprintf (g_errorstream, "*** Please report bug to %s ***\n", SPLINT_MAINTAINER); |
616915dd | 1199 | exit (LLGIVEUP); |
1200 | } | |
1201 | } | |
1202 | ||
1203 | void | |
1204 | cleanupFiles (void) | |
1205 | { | |
1206 | static bool doneCleanup = FALSE; | |
1207 | ||
1208 | /* make sure this is only called once! */ | |
1209 | ||
1210 | if (doneCleanup) return; | |
1211 | ||
1212 | setCodePoint (); | |
1213 | ||
dfd82dce | 1214 | /* |
1215 | ** Close all open files | |
1216 | ** (There should only be open files, if we exited after a fatal error.) | |
1217 | */ | |
1218 | ||
1219 | fileTable_closeAll (context_fileTable ()); | |
1220 | ||
616915dd | 1221 | if (context_getFlag (FLG_KEEP)) |
1222 | { | |
80489f0a | 1223 | check (fputs ("Temporary files kept:\n", g_messagestream) != EOF); |
616915dd | 1224 | fileTable_printTemps (context_fileTable ()); |
1225 | } | |
1226 | else | |
1227 | { | |
1228 | # ifdef WIN32 | |
1229 | int nfiles = /*@-unrecog@*/ _fcloseall (); /*@=unrecog@*/ | |
1230 | ||
1231 | if (nfiles != 0) | |
1232 | { | |
1233 | llbug (message ("Files unclosed: %d", nfiles)); | |
1234 | } | |
1235 | # endif | |
1236 | fileTable_cleanup (context_fileTable ()); | |
1237 | } | |
1238 | ||
1239 | doneCleanup = TRUE; | |
1240 | } | |
1241 | ||
1242 | /* | |
11db3170 | 1243 | ** cleans up temp files (if necessary) and exits |
616915dd | 1244 | */ |
1245 | ||
27c9e640 | 1246 | /*@noreturn@*/ void |
616915dd | 1247 | llexit (int status) |
1248 | { | |
1249 | DPRINTF (("llexit: %d", status)); | |
1250 | ||
1251 | # ifdef WIN32 | |
1252 | if (status == LLFAILURE) | |
1253 | { | |
1254 | _fcloseall (); | |
1255 | } | |
1256 | # endif | |
1257 | ||
1258 | cleanupFiles (); | |
1259 | ||
1260 | if (status != LLFAILURE) | |
1261 | { | |
1262 | context_destroyMod (); | |
1263 | exprNode_destroyMod (); | |
1264 | ||
1265 | sRef_destroyMod (); | |
1266 | uentry_destroyMod (); | |
1267 | typeIdSet_destroyMod (); | |
1268 | ||
1269 | # ifdef USEDMALLOC | |
1270 | dmalloc_shutdown (); | |
1271 | # endif | |
1272 | } | |
1273 | ||
1274 | exit ((status == LLSUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE); | |
1275 | } | |
1276 | ||
28bf4b0b | 1277 | static fileIdList preprocessFiles (fileIdList fl, bool xhfiles) |
616915dd | 1278 | /*@modifies fileSystem@*/ |
1279 | { | |
1280 | bool msg = (context_getFlag (FLG_SHOWSCAN) && fileIdList_size (fl) > 10); | |
1281 | int skip = (fileIdList_size (fl) / 5); | |
1282 | int filesprocessed = 0; | |
1283 | fileIdList dfiles = fileIdList_create (); | |
1284 | ||
1285 | fileloc_free (g_currentloc); | |
1286 | g_currentloc = fileloc_createBuiltin (); | |
1287 | ||
1288 | fileIdList_elements (fl, fid) | |
1289 | { | |
4dd72714 | 1290 | cstring ppfname = fileTable_fileName (fid); |
616915dd | 1291 | |
53a89507 | 1292 | if (!(osd_fileIsReadable (ppfname))) |
616915dd | 1293 | { |
146e25eb | 1294 | lldiagmsg (message ("Cannot open file: %q", osd_outputPath (ppfname))); |
53a89507 | 1295 | ppfname = cstring_undefined; |
28bf4b0b | 1296 | } |
1297 | ||
1298 | if (cstring_isDefined (ppfname)) | |
1299 | { | |
1300 | fileId dfile = fileTable_addCTempFile (context_fileTable (), fid); | |
53a89507 | 1301 | |
1302 | if (xhfiles) | |
1303 | { | |
1304 | llassert (fileTable_isXHFile (context_fileTable (), dfile)); | |
1305 | } | |
1306 | ||
28bf4b0b | 1307 | llassert (cstring_isNonEmpty (ppfname)); |
616915dd | 1308 | |
1309 | if (msg) | |
1310 | { | |
1311 | if ((filesprocessed % skip) == 0) | |
1312 | { | |
1313 | if (filesprocessed == 0) { | |
ce7034f0 | 1314 | displayScanContinue (cstring_makeLiteral (" ")); |
616915dd | 1315 | } |
1316 | else { | |
ce7034f0 | 1317 | displayScanContinue (cstring_makeLiteral (".")); |
616915dd | 1318 | } |
616915dd | 1319 | } |
1320 | filesprocessed++; | |
1321 | } | |
1322 | ||
4dd72714 | 1323 | DPRINTF (("outfile: %s", fileTable_fileName (dfile))); |
1324 | ||
1325 | if (cppProcess (ppfname, fileTable_fileName (dfile)) != 0) | |
616915dd | 1326 | { |
1327 | llfatalerror (message ("Preprocessing error for file: %s", | |
4dd72714 | 1328 | fileTable_rootFileName (fid))); |
616915dd | 1329 | } |
1330 | ||
1331 | fileIdList_add (dfiles, dfile); | |
1332 | } | |
1333 | } end_fileIdList_elements; | |
1334 | ||
1335 | return dfiles; | |
1336 | } | |
28bf4b0b | 1337 | |
1338 | /* This should be in an lclUtils.c file... */ | |
1339 | # ifndef NOLCL | |
1340 | char *specFullName (char *specfile, /*@out@*/ char **inpath) | |
1341 | { | |
1342 | /* extract the path and the specname associated with the given file */ | |
1343 | char *specname = (char *) dmalloc (sizeof (*specname) | |
1344 | * (strlen (specfile) + 9)); | |
1345 | char *ospecname = specname; | |
1346 | char *path = (char *) dmalloc (sizeof (*path) * (strlen (specfile))); | |
1347 | size_t size; | |
1348 | long int i, j; | |
1349 | ||
1350 | /* initialized path to empty string or may have accidental garbage */ | |
1351 | *path = '\0'; | |
1352 | ||
1353 | /*@-mayaliasunique@*/ | |
1354 | strcpy (specname, specfile); | |
1355 | /*@=mayaliasunique@*/ | |
1356 | ||
1357 | /* trim off pathnames in specfile */ | |
1358 | size = strlen (specname); | |
1359 | ||
1360 | for (i = size_toInt (size) - 1; i >= 0; i--) | |
1361 | { | |
1362 | if (specname[i] == CONNECTCHAR) | |
1363 | { | |
1364 | /* strcpy (specname, (char *)specname+i+1); */ | |
1365 | for (j = 0; j <= i; j++) /* include '/' */ | |
1366 | { | |
1367 | path[j] = specname[j]; | |
1368 | } | |
1369 | ||
1370 | path[i + 1] = '\0'; | |
1371 | specname += i + 1; | |
1372 | break; | |
1373 | } | |
1374 | } | |
1375 | ||
1376 | /* | |
1377 | ** also remove .lcl file extension, assume it's the last extension | |
1378 | ** of the file name | |
1379 | */ | |
1380 | ||
1381 | size = strlen (specname); | |
1382 | ||
1383 | for (i = size_toInt (size) - 1; i >= 0; i--) | |
1384 | { | |
1385 | if (specname[i] == '.') | |
1386 | { | |
1387 | specname[i] = '\0'; | |
1388 | break; | |
1389 | } | |
1390 | } | |
1391 | ||
1392 | *inpath = path; | |
1393 | ||
1394 | /* | |
1395 | ** If specname no longer points to the original char, | |
1396 | ** we need to allocate a new pointer and copy the string. | |
1397 | */ | |
1398 | ||
1399 | if (specname != ospecname) { | |
1400 | char *rspecname = (char *) dmalloc (sizeof (*rspecname) * (strlen (specname) + 1)); | |
1401 | strcpy (rspecname, specname); /* evs 2000-05-16: Bug: was ospecname! */ | |
1402 | sfree (ospecname); | |
1403 | return rspecname; | |
1404 | } | |
1405 | ||
1406 | return specname; | |
1407 | } | |
1408 | # endif | |
e55c0c6d | 1409 | |
1410 | void warnSysFiles(fileIdList files) | |
1411 | { | |
1412 | fileIdList_elements (files, file) | |
1413 | { | |
1414 | ||
1415 | if (fileTable_isSystemFile (context_fileTable (), file) ) | |
1416 | { | |
d0fa7de4 | 1417 | if (!context_getFlag( FLG_SYSTEMDIRERRORS ) ) |
1418 | { | |
1419 | voptgenerror (FLG_WARNSYSFILES, message ("Warning %s is a considered a system file. No errors in this file will be reported.", fileTable_rootFileName (file) ), g_currentloc); | |
1420 | } | |
e55c0c6d | 1421 | } |
1422 | } | |
1423 | end_fileIdList_elements; | |
1424 | } |