VirtualBox

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

Last change on this file since 1734 was 1734, checked in by bird, 16 years ago

kDepPre: Shut up pedantic gcc warnings.

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