VirtualBox

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

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

Fixed casing paths on win32.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 19.3 KB
 
1/* $Id: kDepPre.c 304 2005-08-11 20:17:17Z 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#ifdef __WIN32__
33#include <windows.h>
34#endif
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* Structures and Typedefs *
51*******************************************************************************/
52/** A dependency. */
53typedef struct DEP
54{
55 /** Next dependency in the list. */
56 struct DEP *pNext;
57 /** The filename hash. */
58 unsigned uHash;
59 /** The length of the filename. */
60 size_t cchFilename;
61 /** The filename. */
62 char szFilename[4];
63} DEP, *PDEP;
64
65
66/*******************************************************************************
67* Global Variables *
68*******************************************************************************/
69/** List of dependencies. */
70static PDEP g_pDeps = NULL;
71
72
73#ifdef __WIN32__
74/**
75 * Corrects the case of a path.
76 * Expects a fullpath!
77 *
78 * @param pszPath Pointer to the path, both input and output.
79 * The buffer must be able to hold one more byte than the string length.
80 */
81void w32_fixcase(char *pszPath)
82{
83#define my_assert(expr) \
84 do { \
85 if (!(expr)) { \
86 printf("my_assert: %s, file %s, line %d\npszPath=%s\npsz=%s\n", \
87 #expr, __FILE__, __LINE__, pszPath, psz); \
88 __asm { __asm int 3 } \
89 exit(1); \
90 } \
91 } while (0)
92
93 char *psz = pszPath;
94 if (*psz == '/' || *psz == '\\')
95 {
96 if (psz[1] == '/' || psz[1] == '\\')
97 {
98 /* UNC */
99 my_assert(psz[1] == '/' || psz[1] == '\\');
100 my_assert(psz[2] != '/' && psz[2] != '\\');
101
102 /* skip server name */
103 psz += 2;
104 while (*psz != '\\' && *psz != '/')
105 {
106 if (!*psz)
107 return;
108 *psz++ = toupper(*psz);
109 }
110
111 /* skip the share name */
112 psz++;
113 my_assert(*psz != '/' && *psz != '\\');
114 while (*psz != '\\' && *psz != '/')
115 {
116 if (!*psz)
117 return;
118 *psz++ = toupper(*psz);
119 }
120 my_assert(*psz == '/' || *psz == '\\');
121 psz++;
122 }
123 else
124 {
125 /* Unix spec */
126 psz++;
127 }
128 }
129 else
130 {
131 /* Drive letter */
132 my_assert(psz[1] == ':');
133 *psz = toupper(*psz);
134 my_assert(psz[0] >= 'A' && psz[0] <= 'Z');
135 my_assert(psz[2] == '/' || psz[2] == '\\');
136 psz += 3;
137 }
138
139 /*
140 * Pointing to the first char after the unc or drive specifier.
141 */
142 while (*psz)
143 {
144 WIN32_FIND_DATA FindFileData;
145 HANDLE hDir;
146 char chSaved0;
147 char chSaved1;
148 char *pszEnd;
149
150
151 /* find the end of the component. */
152 pszEnd = psz;
153 while (*pszEnd && *pszEnd != '/' && *pszEnd != '\\')
154 pszEnd++;
155
156 /* replace the end with "?\0" */
157 chSaved0 = pszEnd[0];
158 chSaved1 = pszEnd[1];
159 pszEnd[0] = '?';
160 pszEnd[1] = '\0';
161
162 /* find the right filename. */
163 hDir = FindFirstFile(pszPath, &FindFileData);
164 pszEnd[1] = chSaved1;
165 if (!hDir)
166 {
167 pszEnd[0] = chSaved0;
168 return;
169 }
170 pszEnd[0] = '\0';
171 while (stricmp(FindFileData.cFileName, psz))
172 {
173 if (!FindNextFile(hDir, &FindFileData))
174 {
175 pszEnd[0] = chSaved0;
176 return;
177 }
178 }
179 strcpy(psz, FindFileData.cFileName);
180 pszEnd[0] = chSaved0;
181
182 /* advance to the next component */
183 if (!chSaved0)
184 return;
185 psz = pszEnd + 1;
186 my_assert(*psz != '/' && *psz != '\\');
187 }
188#undef my_assert
189}
190
191#endif
192
193
194/**
195 * Prints the dependency chain.
196 *
197 * @returns Pointer to the allocated dependency.
198 * @param pOutput Output stream.
199 */
200static void depPrint(FILE *pOutput)
201{
202 PDEP pDep = g_pDeps;
203 for (pDep = g_pDeps; pDep; pDep = pDep->pNext)
204 {
205 /*
206 * Skip some fictive names like <built-in> and <command line>.
207 */
208 if ( pDep->szFilename[0] == '<'
209 && pDep->szFilename[pDep->cchFilename - 1] == '>')
210 continue;
211#ifdef __WIN32__
212 {
213 char szFilename[_MAX_PATH + 1];
214 if (_fullpath(szFilename, pDep->szFilename, sizeof(szFilename)))
215 w32_fixcase(szFilename);
216 fprintf(pOutput, " \\\n\t%s", pDep->szFilename);
217 }
218#else
219 fprintf(pOutput, " \\\n\t%s", pDep->szFilename);
220#endif
221 }
222 fprintf(pOutput, "\n\n");
223}
224
225
226/* sdbm:
227 This algorithm was created for sdbm (a public-domain reimplementation of
228 ndbm) database library. it was found to do well in scrambling bits,
229 causing better distribution of the keys and fewer splits. it also happens
230 to be a good general hashing function with good distribution. the actual
231 function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below
232 is the faster version used in gawk. [there is even a faster, duff-device
233 version] the magic constant 65599 was picked out of thin air while
234 experimenting with different constants, and turns out to be a prime.
235 this is one of the algorithms used in berkeley db (see sleepycat) and
236 elsewhere. */
237static unsigned sdbm(const char *str)
238{
239 unsigned hash = 0;
240 int c;
241
242 while ((c = *(unsigned const char *)str++))
243 hash = c + (hash << 6) + (hash << 16) - hash;
244
245 return hash;
246}
247
248
249/**
250 * Adds a dependency.
251 *
252 * @returns Pointer to the allocated dependency.
253 * @param pszFilename The filename.
254 * @param cchFilename The length of the filename.
255 */
256static PDEP depAdd(const char *pszFilename, size_t cchFilename)
257{
258 unsigned uHash = sdbm(pszFilename);
259 PDEP pDep;
260 PDEP pDepPrev;
261
262 /*
263 * Check if we've already got this one.
264 */
265 pDepPrev = NULL;
266 for (pDep = g_pDeps; pDep; pDepPrev = pDep, pDep = pDep->pNext)
267 if ( pDep->uHash == uHash
268 && pDep->cchFilename == cchFilename
269 && !memcmp(pDep->szFilename, pszFilename, cchFilename))
270 return pDep;
271
272 /*
273 * Add it.
274 */
275 pDep = malloc(sizeof(*pDep) + cchFilename);
276 if (!pDep)
277 {
278 fprintf(stderr, "\nOut of memory! (requested %#x bytes)\n\n", sizeof(*pDep) + cchFilename);
279 exit(1);
280 }
281
282 pDep->cchFilename = cchFilename;
283 memcpy(pDep->szFilename, pszFilename, cchFilename + 1);
284 pDep->uHash = uHash;
285
286 if (pDepPrev)
287 {
288 pDep->pNext = pDepPrev->pNext;
289 pDepPrev->pNext = pDep;
290 }
291 else
292 {
293 pDep->pNext = g_pDeps;
294 g_pDeps = pDep;
295 }
296 return pDep;
297}
298
299
300/**
301 * Parses the output from a preprocessor of a C-style language.
302 *
303 * @returns 0 on success.
304 * @returns 1 or other approriate exit code on failure.
305 * @param pInput Input stream. (probably not seekable)
306 */
307static int ParseCPrecompiler(FILE *pInput)
308{
309 enum
310 {
311 C_DISCOVER = 0,
312 C_SKIP_LINE,
313 C_PARSE_FILENAME,
314 C_EOF
315 } enmMode = C_DISCOVER;
316 PDEP pDep = NULL;
317 int ch;
318 char szBuf[8192];
319
320 for (;;)
321 {
322 switch (enmMode)
323 {
324 /*
325 * Start of line, need to look for '#[[:space]]*line <num> "file"' and '# <num> "file"'.
326 */
327 case C_DISCOVER:
328 /* first find '#' */
329 while ((ch = FGETC(pInput)) != EOF)
330 if (!isblank(ch))
331 break;
332 if (ch == '#')
333 {
334 /* skip spaces */
335 while ((ch = FGETC(pInput)) != EOF)
336 if (!isblank(ch))
337 break;
338
339 /* check for "line" */
340 if (ch == 'l')
341 {
342 if ( (ch = FGETC(pInput)) == 'i'
343 && (ch = FGETC(pInput)) == 'n'
344 && (ch = FGETC(pInput)) == 'e')
345 {
346 ch = FGETC(pInput);
347 if (isblank(ch))
348 {
349 /* skip spaces */
350 while ((ch = FGETC(pInput)) != EOF)
351 if (!isblank(ch))
352 break;
353 }
354 else
355 ch = 'x';
356 }
357 else
358 ch = 'x';
359 }
360
361 /* line number */
362 if (ch >= '0' && ch <= '9')
363 {
364 /* skip the number following spaces */
365 while ((ch = FGETC(pInput)) != EOF)
366 if (!isxdigit(ch))
367 break;
368 if (isblank(ch))
369 {
370 while ((ch = FGETC(pInput)) != EOF)
371 if (!isblank(ch))
372 break;
373 /* quoted filename */
374 if (ch == '"')
375 {
376 enmMode = C_PARSE_FILENAME;
377 break;
378 }
379 }
380 }
381 }
382 enmMode = C_SKIP_LINE;
383 break;
384
385 /*
386 * Skip past the end of the current line.
387 */
388 case C_SKIP_LINE:
389# if 0
390 for (;;)
391 {
392 if (!fgets(szBuf, sizeof(szBuf), pInput))
393 {
394 enmMode = C_EOF;
395 break;
396 }
397 ch = szBuf[strlen(szBuf) - 1];
398 if ( ch == '\r'
399 || ch == '\n')
400 break;
401 }
402# else
403 while ((ch = FGETC(pInput)) != EOF)
404 if ( ch == '\r'
405 || ch == '\n')
406 break;
407# endif
408 enmMode = C_DISCOVER;
409 break;
410
411 /*
412 * Parse the filename.
413 */
414 case C_PARSE_FILENAME:
415 {
416 /* retreive and unescape the filename. */
417 char *psz = &szBuf[0];
418 while ( (ch = FGETC(pInput)) != EOF
419 && psz < &szBuf[sizeof(szBuf) - 1])
420 {
421 if (ch == '\\')
422 {
423 ch = FGETC(pInput);
424 switch (ch)
425 {
426 case '\\': ch = '/'; break;
427 case 't': ch = '\t'; break;
428 case 'r': ch = '\r'; break;
429 case 'n': ch = '\n'; break;
430 case 'b': ch = '\b'; break;
431 default:
432 fprintf(stderr, "warning: unknown escape char '%c'\n", ch);
433 continue;
434
435 }
436 *psz++ = ch == '\\' ? '/' : ch;
437 }
438 else if (ch != '"')
439 *psz++ = ch;
440 else
441 {
442 size_t cchFilename = psz - &szBuf[0];
443 *psz = '\0';
444 /* compare with current dep, add & switch on mismatch. */
445 if ( !pDep
446 || pDep->cchFilename != cchFilename
447 || memcmp(pDep->szFilename, szBuf, cchFilename))
448 pDep = depAdd(szBuf, cchFilename);
449 break;
450 }
451 }
452 enmMode = C_SKIP_LINE;
453 break;
454 }
455
456 /*
457 * Handle EOF.
458 */
459 case C_EOF:
460 if (feof(pInput))
461 return 0;
462 enmMode = C_DISCOVER;
463 break;
464 }
465 if (ch == EOF)
466 enmMode = C_EOF;
467 }
468
469 return 0;
470}
471
472
473static void usage(const char *argv0)
474{
475 printf("syntax: %s [-l=c] -o <output> -t <target> < - | <filename> | -e <cmdline> >\n", argv0);
476}
477
478int main(int argc, char *argv[])
479{
480 int i;
481
482 /* Arguments. */
483 int iExec = 0;
484 FILE *pOutput = NULL;
485 const char *pszOutput = NULL;
486 FILE *pInput = NULL;
487 const char *pszTarget = NULL;
488 /* Argument parsing. */
489 int fInput = 0; /* set when we've found input argument. */
490
491 /*
492 * Parse arguments.
493 */
494 if (argc <= 1)
495 {
496 usage(argv[0]);
497 return 1;
498 }
499 for (i = 1; i < argc; i++)
500 {
501 if (argv[i][0] == '-')
502 {
503 switch (argv[i][1])
504 {
505 /*
506 * Output file.
507 */
508 case 'o':
509 {
510 pszOutput = &argv[i][2];
511 if (pOutput)
512 {
513 fprintf(stderr, "%s: syntax error: only one output file!\n", argv[0]);
514 return 1;
515 }
516 if (!*pszOutput)
517 {
518 if (++i >= argc)
519 {
520 fprintf(stderr, "%s: syntax error: The '-o' argument is missing the filename.\n", argv[0]);
521 return 1;
522 }
523 pszOutput = argv[i];
524 }
525 pOutput = fopen(pszOutput, "w");
526 if (!pOutput)
527 {
528 fprintf(stderr, "%s: error: Failed to create output file '%s'.\n", argv[0], pszOutput);
529 return 1;
530 }
531 break;
532 }
533
534 /*
535 * Language spec.
536 */
537 case 'l':
538 {
539 const char *psz = &argv[i][2];
540 if (*psz == '=')
541 psz++;
542 if (!strcmp(psz, "c"))
543 ;
544 else
545 {
546 fprintf(stderr, "%s: error: The '%s' language is not supported.\n", argv[0], psz);
547 return 1;
548 }
549 break;
550 }
551
552 /*
553 * Target name.
554 */
555 case 't':
556 {
557 if (pszTarget)
558 {
559 fprintf(stderr, "%s: syntax error: only one target!\n", argv[0]);
560 return 1;
561 }
562 pszTarget = &argv[i][2];
563 if (!*pszTarget)
564 {
565 if (++i >= argc)
566 {
567 fprintf(stderr, "%s: syntax error: The '-t' argument is missing the target name.\n", argv[0]);
568 return 1;
569 }
570 pszTarget = argv[i];
571 }
572 break;
573 }
574
575 /*
576 * Exec.
577 */
578 case 'e':
579 {
580 if (++i >= argc)
581 {
582 fprintf(stderr, "%s: syntax error: The '-e' argument is missing the command.\n", argv[0]);
583 return 1;
584 }
585 iExec = i;
586 i = argc - 1;
587 break;
588 }
589
590
591 /*
592 * Pipe input.
593 */
594 case '\0':
595 {
596 pInput = stdin;
597 fInput = 1;
598 break;
599 }
600
601 /*
602 * Invalid argument.
603 */
604 default:
605 fprintf(stderr, "%s: syntax error: Invalid argument '%s'.\n", argv[0], argv[i]);
606 usage(argv[0]);
607 return 1;
608 }
609 }
610 else
611 {
612 pInput = fopen(argv[i], "r");
613 if (!pOutput)
614 {
615 fprintf(stderr, "%s: error: Failed to open input file '%s'.\n", argv[0], argv[i]);
616 return 1;
617 }
618 fInput = 1;
619 }
620
621 /*
622 * End of the line?
623 */
624 if (fInput)
625 {
626 if (++i < argc)
627 {
628 fprintf(stderr, "%s: syntax error: No arguments shall follow the input spec.\n", argv[0]);
629 return 1;
630 }
631 break;
632 }
633 }
634
635 /*
636 * Got all we require?
637 */
638 if (!pInput && iExec <= 0)
639 {
640 fprintf(stderr, "%s: syntax error: No input!\n", argv[0]);
641 return 1;
642 }
643 if (!pOutput)
644 {
645 fprintf(stderr, "%s: syntax error: No input!\n", argv[0]);
646 return 1;
647 }
648 if (!pszTarget)
649 {
650 fprintf(stderr, "%s: syntax error: No target!\n", argv[0]);
651 return 1;
652 }
653
654 /*
655 * Spawn process?
656 */
657 if (iExec > 0)
658 {
659 fprintf(stderr, "%s: -e is not yet implemented!\n", argv[0]);
660 return 1;
661 }
662
663 /*
664 * Do the parsing.
665 */
666 i = ParseCPrecompiler(pInput);
667
668 /*
669 * Reap child.
670 */
671 if (iExec > 0)
672 {
673 // later
674 }
675
676 /*
677 * Write the dependecy file.
678 */
679 if (!i)
680 {
681 fprintf(pOutput, "%s:", pszTarget);
682 depPrint(pOutput);
683 }
684
685 /*
686 * Close the output, delete output on failure.
687 */
688 if (!i && ferror(pOutput))
689 {
690 i = 1;
691 fprintf(stderr, "%s: error: Error writing to '%s'.\n", argv[0], pszOutput);
692 }
693 fclose(pOutput);
694 if (i)
695 {
696 if (unlink(pszOutput))
697 fprintf(stderr, "%s: warning: failed to remove output file '%s' on failure.\n", argv[0], pszOutput);
698 }
699
700 return i;
701}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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