VirtualBox

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

最後變更 在這個檔案從259是 259,由 bird 提交於 20 年 前

Win32.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 16.1 KB
 
1/* $Id: kDepPre.c 259 2005-04-21 16:54:02Z bird $ */
2/** @file
3 *
4 * kDepPre - Dependency Generator using Precompiler output.
5 *
6 * Copyright (c) 2005 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#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <ctype.h>
32
33#ifdef HAVE_FGETC_UNLOCKED
34# define FGETC(s) getc_unlocked(s)
35#else
36# define FGETC(s) fgetc(s)
37#endif
38
39#ifdef NEED_ISBLANK
40# define isblank(ch) ( (unsigned char)(ch) == ' ' || (unsigned char)(ch) == '\t' )
41#endif
42
43
44
45
46/*******************************************************************************
47* Structures and Typedefs *
48*******************************************************************************/
49/** A dependency. */
50typedef struct DEP
51{
52 /** Next dependency in the list. */
53 struct DEP *pNext;
54 /** The filename hash. */
55 unsigned uHash;
56 /** The length of the filename. */
57 size_t cchFilename;
58 /** The filename. */
59 char szFilename[4];
60} DEP, *PDEP;
61
62
63/*******************************************************************************
64* Global Variables *
65*******************************************************************************/
66/** List of dependencies. */
67static PDEP g_pDeps = NULL;
68
69
70/**
71 * Prints the dependency chain.
72 *
73 * @returns Pointer to the allocated dependency.
74 * @param pOutput Output stream.
75 */
76static void depPrint(FILE *pOutput)
77{
78 PDEP pDep = g_pDeps;
79 for (pDep = g_pDeps; pDep; pDep = pDep->pNext)
80 {
81 /*
82 * Skip some fictive names like <built-in> and <command line>.
83 */
84 if ( pDep->szFilename[0] == '<'
85 && pDep->szFilename[pDep->cchFilename - 1] == '>')
86 continue;
87
88 fprintf(pOutput, " \\\n\t%s", pDep->szFilename);
89 }
90 fprintf(pOutput, "\n\n");
91}
92
93
94/* sdbm:
95 This algorithm was created for sdbm (a public-domain reimplementation of
96 ndbm) database library. it was found to do well in scrambling bits,
97 causing better distribution of the keys and fewer splits. it also happens
98 to be a good general hashing function with good distribution. the actual
99 function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below
100 is the faster version used in gawk. [there is even a faster, duff-device
101 version] the magic constant 65599 was picked out of thin air while
102 experimenting with different constants, and turns out to be a prime.
103 this is one of the algorithms used in berkeley db (see sleepycat) and
104 elsewhere. */
105static unsigned sdbm(const char *str)
106{
107 const char *pszStart;
108 unsigned hash = 0;
109 int c;
110
111 while ((c = *(unsigned const char *)str++))
112 hash = c + (hash << 6) + (hash << 16) - hash;
113
114 return hash;
115}
116
117
118/**
119 * Adds a dependency.
120 *
121 * @returns Pointer to the allocated dependency.
122 * @param pszFilename The filename.
123 * @param cchFilename The length of the filename.
124 */
125static PDEP depAdd(const char *pszFilename, size_t cchFilename)
126{
127 unsigned uHash = sdbm(pszFilename);
128 PDEP pDep;
129 PDEP pDepPrev;
130
131 /*
132 * Check if we've already got this one.
133 */
134 pDepPrev = NULL;
135 for (pDep = g_pDeps; pDep; pDepPrev = pDep, pDep = pDep->pNext)
136 if ( pDep->uHash == uHash
137 && pDep->cchFilename == cchFilename
138 && !memcmp(pDep->szFilename, pszFilename, cchFilename))
139 return pDep;
140
141 /*
142 * Add it.
143 */
144 pDep = malloc(sizeof(*pDep) + cchFilename);
145 if (!pDep)
146 {
147 fprintf(stderr, "\nOut of memory! (requested %#x bytes)\n\n", sizeof(*pDep) + cchFilename);
148 exit(1);
149 }
150
151 pDep->cchFilename = cchFilename;
152 memcpy(pDep->szFilename, pszFilename, cchFilename + 1);
153 pDep->uHash = uHash;
154
155 if (pDepPrev)
156 {
157 pDep->pNext = pDepPrev->pNext;
158 pDepPrev->pNext = pDep;
159 }
160 else
161 {
162 pDep->pNext = g_pDeps;
163 g_pDeps = pDep;
164 }
165 return pDep;
166}
167
168
169/**
170 * Parses the output from a preprocessor of a C-style language.
171 *
172 * @returns 0 on success.
173 * @returns 1 or other approriate exit code on failure.
174 * @param pInput Input stream. (probably not seekable)
175 */
176static int ParseCPrecompiler(FILE *pInput)
177{
178 enum
179 {
180 C_DISCOVER = 0,
181 C_SKIP_LINE,
182 C_PARSE_FILENAME,
183 C_EOF
184 } enmMode = C_DISCOVER;
185 PDEP pDep = NULL;
186 int ch;
187 char szBuf[8192];
188
189 for (;;)
190 {
191 switch (enmMode)
192 {
193 /*
194 * Start of line, need to look for '#[[:space]]*line <num> "file"' and '# <num> "file"'.
195 */
196 case C_DISCOVER:
197 /* first find '#' */
198 while ((ch = FGETC(pInput)) != EOF)
199 if (!isblank(ch))
200 break;
201 if (ch == '#')
202 {
203 /* skip spaces */
204 while ((ch = FGETC(pInput)) != EOF)
205 if (!isblank(ch))
206 break;
207
208 /* check for "line" */
209 if (ch == 'l')
210 {
211 if ( (ch = FGETC(pInput)) == 'i'
212 && (ch = FGETC(pInput)) == 'n'
213 && (ch = FGETC(pInput)) == 'e')
214 {
215 ch = FGETC(pInput);
216 if (isblank(ch))
217 {
218 /* skip spaces */
219 while ((ch = FGETC(pInput)) != EOF)
220 if (!isblank(ch))
221 break;
222 }
223 else
224 ch = 'x';
225 }
226 else
227 ch = 'x';
228 }
229
230 /* line number */
231 if (ch >= '0' && ch <= '9')
232 {
233 /* skip the number following spaces */
234 while ((ch = FGETC(pInput)) != EOF)
235 if (!isxdigit(ch))
236 break;
237 if (isblank(ch))
238 {
239 while ((ch = FGETC(pInput)) != EOF)
240 if (!isblank(ch))
241 break;
242 /* quoted filename */
243 if (ch == '"')
244 {
245 enmMode = C_PARSE_FILENAME;
246 break;
247 }
248 }
249 }
250 }
251 enmMode = C_SKIP_LINE;
252 break;
253
254 /*
255 * Skip past the end of the current line.
256 */
257 case C_SKIP_LINE:
258# if 0
259 for (;;)
260 {
261 if (!fgets(szBuf, sizeof(szBuf), pInput))
262 {
263 enmMode = C_EOF;
264 break;
265 }
266 ch = szBuf[strlen(szBuf) - 1];
267 if ( ch == '\r'
268 || ch == '\n')
269 break;
270 }
271# else
272 while ((ch = FGETC(pInput)) != EOF)
273 if ( ch == '\r'
274 || ch == '\n')
275 break;
276# endif
277 enmMode = C_DISCOVER;
278 break;
279
280 /*
281 * Parse the filename.
282 */
283 case C_PARSE_FILENAME:
284 {
285 /* retreive and unescape the filename. */
286 char *psz = &szBuf[0];
287 while ( (ch = FGETC(pInput)) != EOF
288 && psz < &szBuf[sizeof(szBuf) - 1])
289 {
290 if (ch == '\\')
291 {
292 ch = FGETC(pInput);
293 switch (ch)
294 {
295 case '\\': ch = '/'; break;
296 case 't': ch = '\t'; break;
297 case 'r': ch = '\r'; break;
298 case 'n': ch = '\n'; break;
299 case 'b': ch = '\b'; break;
300 default:
301 fprintf(stderr, "warning: unknown escape char '%c'\n", ch);
302 continue;
303
304 }
305 *psz++ = ch == '\\' ? '/' : ch;
306 }
307 else if (ch != '"')
308 *psz++ = ch;
309 else
310 {
311 size_t cchFilename = psz - &szBuf[0];
312 *psz = '\0';
313 /* compare with current dep, add & switch on mismatch. */
314 if ( !pDep
315 || pDep->cchFilename != cchFilename
316 || memcmp(pDep->szFilename, szBuf, cchFilename))
317 pDep = depAdd(szBuf, cchFilename);
318 break;
319 }
320 }
321 enmMode = C_SKIP_LINE;
322 break;
323 }
324
325 /*
326 * Handle EOF.
327 */
328 case C_EOF:
329 if (feof(pInput))
330 return 0;
331 enmMode = C_DISCOVER;
332 break;
333 }
334 if (ch == EOF)
335 enmMode = C_EOF;
336 }
337
338 return 0;
339}
340
341
342static void usage(const char *argv0)
343{
344 printf("syntax: %s [-l=c] -o <output> -t <target> <-e <cmdline> | - | <filename>\n", argv0);
345}
346
347int main(int argc, char *argv[])
348{
349 int i;
350
351 /* Arguments. */
352 int iExec = 0;
353 FILE *pOutput = NULL;
354 const char *pszOutput = NULL;
355 FILE *pInput = NULL;
356 const char *pszTarget = NULL;
357 /* Argument parsing. */
358 int fInput = 0; /* set when we've found input argument. */
359
360 /*
361 * Parse arguments.
362 */
363 if (argc <= 1)
364 {
365 usage(argv[0]);
366 return 1;
367 }
368 for (i = 1; i < argc; i++)
369 {
370 if (argv[i][0] == '-')
371 {
372 switch (argv[i][1])
373 {
374 /*
375 * Output file.
376 */
377 case 'o':
378 {
379 pszOutput = &argv[i][2];
380 if (pOutput)
381 {
382 fprintf(stderr, "%s: syntax error: only one output file!\n", argv[0]);
383 return 1;
384 }
385 if (!*pszOutput)
386 {
387 if (++i >= argc)
388 {
389 fprintf(stderr, "%s: syntax error: The '-o' argument is missing the filename.\n", argv[0]);
390 return 1;
391 }
392 pszOutput = argv[i];
393 }
394 pOutput = fopen(pszOutput, "w");
395 if (!pOutput)
396 {
397 fprintf(stderr, "%s: error: Failed to create output file '%s'.\n", argv[0], pszOutput);
398 return 1;
399 }
400 break;
401 }
402
403 /*
404 * Language spec.
405 */
406 case 'l':
407 {
408 const char *psz = &argv[i][2];
409 if (*psz == '=')
410 psz++;
411 if (!strcmp(psz, "c"))
412 ;
413 else
414 {
415 fprintf(stderr, "%s: error: The '%s' language is not supported.\n", argv[0], psz);
416 return 1;
417 }
418 break;
419 }
420
421 /*
422 * Target name.
423 */
424 case 't':
425 {
426 if (pszTarget)
427 {
428 fprintf(stderr, "%s: syntax error: only one target!\n", argv[0]);
429 return 1;
430 }
431 pszTarget = &argv[i][2];
432 if (!*pszTarget)
433 {
434 if (++i >= argc)
435 {
436 fprintf(stderr, "%s: syntax error: The '-t' argument is missing the target name.\n", argv[0]);
437 return 1;
438 }
439 pszTarget = argv[i];
440 }
441 break;
442 }
443
444 /*
445 * Exec.
446 */
447 case 'e':
448 {
449 if (++i >= argc)
450 {
451 fprintf(stderr, "%s: syntax error: The '-e' argument is missing the command.\n", argv[0]);
452 return 1;
453 }
454 iExec = i;
455 i = argc - 1;
456 break;
457 }
458
459
460 /*
461 * Pipe input.
462 */
463 case '\0':
464 {
465 pInput = stdin;
466 fInput = 1;
467 break;
468 }
469
470 /*
471 * Invalid argument.
472 */
473 default:
474 fprintf(stderr, "%s: syntax error: Invalid argument '%s'.\n", argv[0], argv[i]);
475 usage(argv[0]);
476 return 1;
477 }
478 }
479 else
480 {
481 pInput = fopen(argv[i], "r");
482 if (!pOutput)
483 {
484 fprintf(stderr, "%s: error: Failed to open input file '%s'.\n", argv[0], argv[i]);
485 return 1;
486 }
487 fInput = 1;
488 }
489
490 /*
491 * End of the line?
492 */
493 if (fInput)
494 {
495 if (++i < argc)
496 {
497 fprintf(stderr, "%s: syntax error: No arguments shall follow the input spec.\n", argv[0]);
498 return 1;
499 }
500 break;
501 }
502 }
503
504 /*
505 * Got all we require?
506 */
507 if (!pInput && iExec <= 0)
508 {
509 fprintf(stderr, "%s: syntax error: No input!\n", argv[0]);
510 return 1;
511 }
512 if (!pOutput)
513 {
514 fprintf(stderr, "%s: syntax error: No input!\n", argv[0]);
515 return 1;
516 }
517 if (!pszTarget)
518 {
519 fprintf(stderr, "%s: syntax error: No target!\n", argv[0]);
520 return 1;
521 }
522
523 /*
524 * Spawn process?
525 */
526 if (iExec > 0)
527 {
528 fprintf(stderr, "%s: -e is not yet implemented!\n", argv[0]);
529 return 1;
530 }
531
532 /*
533 * Do the parsing.
534 */
535 i = ParseCPrecompiler(pInput);
536
537 /*
538 * Reap child.
539 */
540 if (iExec > 0)
541 {
542 // later
543 }
544
545 /*
546 * Write the dependecy file.
547 */
548 if (!i)
549 {
550 fprintf(pOutput, "%s:", pszTarget);
551 depPrint(pOutput);
552 }
553
554 /*
555 * Close the output, delete output on failure.
556 */
557 if (!i && ferror(pOutput))
558 {
559 i = 1;
560 fprintf(stderr, "%s: error: Error writing to '%s'.\n", argv[0], pszOutput);
561 }
562 fclose(pOutput);
563 if (i)
564 {
565 if (unlink(pszOutput))
566 fprintf(stderr, "%s: warning: failed to remove output file '%s' on failure.\n", argv[0], pszOutput);
567 }
568
569 return i;
570}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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