VirtualBox

source: kBuild/trunk/src/kDepPre/kDepPre.c@ 2968

Last change on this file since 2968 was 2955, checked in by bird, 8 years ago

kDepObj: Added -e<ignored .ext> option for avoid circular dependencies when compiling the precompiled header file (pch).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.0 KB
Line 
1/* $Id: kDepPre.c 2955 2016-09-21 19:05:53Z bird $ */
2/** @file
3 * kDepPre - Dependency Generator using Precompiler output.
4 */
5
6/*
7 * Copyright (c) 2005-2010 knut st. osmundsen <[email protected]>
8 *
9 * This file is part of kBuild.
10 *
11 * kBuild is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * kBuild is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with kBuild. If not, see <http://www.gnu.org/licenses/>
23 *
24 */
25
26/*******************************************************************************
27* Header Files *
28*******************************************************************************/
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <ctype.h>
33#ifdef _MSC_VER
34# include <io.h>
35#else
36# include <unistd.h>
37#endif
38#include "kDep.h"
39
40#ifdef HAVE_FGETC_UNLOCKED
41# define FGETC(s) getc_unlocked(s)
42#else
43# define FGETC(s) fgetc(s)
44#endif
45
46#ifdef NEED_ISBLANK
47# define isblank(ch) ( (unsigned char)(ch) == ' ' || (unsigned char)(ch) == '\t' )
48#endif
49
50
51
52
53/**
54 * Parses the output from a preprocessor of a C-style language.
55 *
56 * @returns 0 on success.
57 * @returns 1 or other approriate exit code on failure.
58 * @param pInput Input stream. (probably not seekable)
59 */
60static int ParseCPrecompiler(FILE *pInput)
61{
62 enum
63 {
64 C_DISCOVER = 0,
65 C_SKIP_LINE,
66 C_PARSE_FILENAME,
67 C_EOF
68 } enmMode = C_DISCOVER;
69 PDEP pDep = NULL;
70 int ch = 0;
71 char szBuf[8192];
72
73 for (;;)
74 {
75 switch (enmMode)
76 {
77 /*
78 * Start of line, need to look for '#[[:space]]*line <num> "file"' and '# <num> "file"'.
79 */
80 case C_DISCOVER:
81 /* first find '#' */
82 while ((ch = FGETC(pInput)) != EOF)
83 if (!isblank(ch))
84 break;
85 if (ch == '#')
86 {
87 /* skip spaces */
88 while ((ch = FGETC(pInput)) != EOF)
89 if (!isblank(ch))
90 break;
91
92 /* check for "line" */
93 if (ch == 'l')
94 {
95 if ( (ch = FGETC(pInput)) == 'i'
96 && (ch = FGETC(pInput)) == 'n'
97 && (ch = FGETC(pInput)) == 'e')
98 {
99 ch = FGETC(pInput);
100 if (isblank(ch))
101 {
102 /* skip spaces */
103 while ((ch = FGETC(pInput)) != EOF)
104 if (!isblank(ch))
105 break;
106 }
107 else
108 ch = 'x';
109 }
110 else
111 ch = 'x';
112 }
113
114 /* line number */
115 if (ch >= '0' && ch <= '9')
116 {
117 /* skip the number following spaces */
118 while ((ch = FGETC(pInput)) != EOF)
119 if (!isxdigit(ch))
120 break;
121 if (isblank(ch))
122 {
123 while ((ch = FGETC(pInput)) != EOF)
124 if (!isblank(ch))
125 break;
126 /* quoted filename */
127 if (ch == '"')
128 {
129 enmMode = C_PARSE_FILENAME;
130 break;
131 }
132 }
133 }
134 }
135 enmMode = C_SKIP_LINE;
136 break;
137
138 /*
139 * Skip past the end of the current line.
140 */
141 case C_SKIP_LINE:
142 do
143 {
144 if ( ch == '\r'
145 || ch == '\n')
146 break;
147 } while ((ch = FGETC(pInput)) != EOF);
148 enmMode = C_DISCOVER;
149 break;
150
151 /*
152 * Parse the filename.
153 */
154 case C_PARSE_FILENAME:
155 {
156 /* retreive and unescape the filename. */
157 char *psz = &szBuf[0];
158 while ( (ch = FGETC(pInput)) != EOF
159 && psz < &szBuf[sizeof(szBuf) - 1])
160 {
161 if (ch == '\\')
162 {
163 ch = FGETC(pInput);
164 switch (ch)
165 {
166 case '\\': ch = '/'; break;
167 case 't': ch = '\t'; break;
168 case 'r': ch = '\r'; break;
169 case 'n': ch = '\n'; break;
170 case 'b': ch = '\b'; break;
171 default:
172 fprintf(stderr, "warning: unknown escape char '%c'\n", ch);
173 continue;
174
175 }
176 *psz++ = ch == '\\' ? '/' : ch;
177 }
178 else if (ch != '"')
179 *psz++ = ch;
180 else
181 {
182 size_t cchFilename = psz - &szBuf[0];
183 *psz = '\0';
184 /* compare with current dep, add & switch on mismatch. */
185 if ( !pDep
186 || pDep->cchFilename != cchFilename
187 || memcmp(pDep->szFilename, szBuf, cchFilename))
188 pDep = depAdd(szBuf, cchFilename);
189 break;
190 }
191 }
192 enmMode = C_SKIP_LINE;
193 break;
194 }
195
196 /*
197 * Handle EOF.
198 */
199 case C_EOF:
200 if (feof(pInput))
201 return 0;
202 enmMode = C_DISCOVER;
203 break;
204 }
205 if (ch == EOF)
206 enmMode = C_EOF;
207 }
208
209 return 0;
210}
211
212
213static int usage(FILE *pOut, const char *argv0)
214{
215 fprintf(pOut,
216 "usage: %s [-l=c] -o <output> -t <target> [-f] [-s] < - | <filename> | -e <cmdline> >\n"
217 " or: %s --help\n"
218 " or: %s --version\n",
219 argv0, argv0, argv0);
220 return 1;
221}
222
223
224int main(int argc, char *argv[])
225{
226 int i;
227
228 /* Arguments. */
229 int iExec = 0;
230 FILE *pOutput = NULL;
231 const char *pszOutput = NULL;
232 FILE *pInput = NULL;
233 const char *pszTarget = NULL;
234 int fStubs = 0;
235 int fFixCase = 0;
236 /* Argument parsing. */
237 int fInput = 0; /* set when we've found input argument. */
238
239 /*
240 * Parse arguments.
241 */
242 if (argc <= 1)
243 return usage(stderr, argv[0]);
244 for (i = 1; i < argc; i++)
245 {
246 if (argv[i][0] == '-')
247 {
248 const char *psz = &argv[i][1];
249 if (*psz == '-')
250 {
251 if (!strcmp(psz, "-help"))
252 psz = "h";
253 else if (!strcmp(psz, "-version"))
254 psz = "V";
255 }
256
257 switch (*psz)
258 {
259 /*
260 * Output file.
261 */
262 case 'o':
263 {
264 pszOutput = &argv[i][2];
265 if (pOutput)
266 {
267 fprintf(stderr, "%s: syntax error: only one output file!\n", argv[0]);
268 return 1;
269 }
270 if (!*pszOutput)
271 {
272 if (++i >= argc)
273 {
274 fprintf(stderr, "%s: syntax error: The '-o' argument is missing the filename.\n", argv[0]);
275 return 1;
276 }
277 pszOutput = argv[i];
278 }
279 if (pszOutput[0] == '-' && !pszOutput[1])
280 pOutput = stdout;
281 else
282 pOutput = fopen(pszOutput, "w");
283 if (!pOutput)
284 {
285 fprintf(stderr, "%s: error: Failed to create output file '%s'.\n", argv[0], pszOutput);
286 return 1;
287 }
288 break;
289 }
290
291 /*
292 * Language spec.
293 */
294 case 'l':
295 {
296 const char *psz = &argv[i][2];
297 if (*psz == '=')
298 psz++;
299 if (!strcmp(psz, "c"))
300 ;
301 else
302 {
303 fprintf(stderr, "%s: error: The '%s' language is not supported.\n", argv[0], psz);
304 return 1;
305 }
306 break;
307 }
308
309 /*
310 * Target name.
311 */
312 case 't':
313 {
314 if (pszTarget)
315 {
316 fprintf(stderr, "%s: syntax error: only one target!\n", argv[0]);
317 return 1;
318 }
319 pszTarget = &argv[i][2];
320 if (!*pszTarget)
321 {
322 if (++i >= argc)
323 {
324 fprintf(stderr, "%s: syntax error: The '-t' argument is missing the target name.\n", argv[0]);
325 return 1;
326 }
327 pszTarget = argv[i];
328 }
329 break;
330 }
331
332 /*
333 * Exec.
334 */
335 case 'e':
336 {
337 if (++i >= argc)
338 {
339 fprintf(stderr, "%s: syntax error: The '-e' argument is missing the command.\n", argv[0]);
340 return 1;
341 }
342 iExec = i;
343 i = argc - 1;
344 break;
345 }
346
347 /*
348 * Pipe input.
349 */
350 case '\0':
351 {
352 pInput = stdin;
353 fInput = 1;
354 break;
355 }
356
357 /*
358 * Fix case.
359 */
360 case 'f':
361 {
362 fFixCase = 1;
363 break;
364 }
365
366 /*
367 * Generate stubs.
368 */
369 case 's':
370 {
371 fStubs = 1;
372 break;
373 }
374
375 /*
376 * The obligatory help and version.
377 */
378 case 'h':
379 usage(stdout, argv[0]);
380 return 0;
381
382 case 'V':
383 printf("kDepPre - kBuild version %d.%d.%d\n"
384 "Copyright (C) 2005-2008 knut st. osmundsen\n",
385 KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH);
386 return 0;
387
388 /*
389 * Invalid argument.
390 */
391 default:
392 fprintf(stderr, "%s: syntax error: Invalid argument '%s'.\n", argv[0], argv[i]);
393 return usage(stderr, argv[0]);
394 }
395 }
396 else
397 {
398 pInput = fopen(argv[i], "r");
399 if (!pInput)
400 {
401 fprintf(stderr, "%s: error: Failed to open input file '%s'.\n", argv[0], argv[i]);
402 return 1;
403 }
404 fInput = 1;
405 }
406
407 /*
408 * End of the line?
409 */
410 if (fInput)
411 {
412 if (++i < argc)
413 {
414 fprintf(stderr, "%s: syntax error: No arguments shall follow the input spec.\n", argv[0]);
415 return 1;
416 }
417 break;
418 }
419 }
420
421 /*
422 * Got all we require?
423 */
424 if (!pInput && iExec <= 0)
425 {
426 fprintf(stderr, "%s: syntax error: No input!\n", argv[0]);
427 return 1;
428 }
429 if (!pOutput)
430 {
431 fprintf(stderr, "%s: syntax error: No output!\n", argv[0]);
432 return 1;
433 }
434 if (!pszTarget)
435 {
436 fprintf(stderr, "%s: syntax error: No target!\n", argv[0]);
437 return 1;
438 }
439
440 /*
441 * Spawn process?
442 */
443 if (iExec > 0)
444 {
445 fprintf(stderr, "%s: -e is not yet implemented!\n", argv[0]);
446 return 1;
447 }
448
449 /*
450 * Do the parsing.
451 */
452 i = ParseCPrecompiler(pInput);
453
454 /*
455 * Reap child.
456 */
457 if (iExec > 0)
458 {
459 /* later */
460 }
461
462 /*
463 * Write the dependecy file.
464 */
465 if (!i)
466 {
467 depOptimize(fFixCase, 0 /* fQuiet */, NULL /*pszIgnoredExt*/);
468 fprintf(pOutput, "%s:", pszTarget);
469 depPrint(pOutput);
470 if (fStubs)
471 depPrintStubs(pOutput);
472 }
473
474 /*
475 * Close the output, delete output on failure.
476 */
477 if (!i && ferror(pOutput))
478 {
479 i = 1;
480 fprintf(stderr, "%s: error: Error writing to '%s'.\n", argv[0], pszOutput);
481 }
482 fclose(pOutput);
483 if (i)
484 {
485 if (unlink(pszOutput))
486 fprintf(stderr, "%s: warning: failed to remove output file '%s' on failure.\n", argv[0], pszOutput);
487 }
488
489 return i;
490}
491
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette