VirtualBox

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

Last change on this file since 1250 was 1187, checked in by bird, 17 years ago

Added version and help.

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