VirtualBox

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

Last change on this file since 384 was 384, checked in by bird, 19 years ago

Added extremely rough support for VC++ IDB files.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.7 KB
Line 
1/* $Id: kDepPre.c 384 2006-01-12 04:01:09Z 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 <errno.h>
32#include <ctype.h>
33#include <limits.h>
34#include <sys/stat.h>
35#ifdef __WIN32__
36# include <windows.h>
37#endif
38#if !defined(__WIN32__) && !defined(__OS2__)
39# include <dirent.h>
40#endif
41#ifndef __WIN32__
42# include <unistd.h>
43#endif
44
45#ifdef HAVE_FGETC_UNLOCKED
46# define FGETC(s) getc_unlocked(s)
47#else
48# define FGETC(s) fgetc(s)
49#endif
50
51#ifdef NEED_ISBLANK
52# define isblank(ch) ( (unsigned char)(ch) == ' ' || (unsigned char)(ch) == '\t' )
53#endif
54
55
56
57
58/*******************************************************************************
59* Structures and Typedefs *
60*******************************************************************************/
61/** A dependency. */
62typedef struct DEP
63{
64 /** Next dependency in the list. */
65 struct DEP *pNext;
66 /** The filename hash. */
67 unsigned uHash;
68 /** The length of the filename. */
69 size_t cchFilename;
70 /** The filename. */
71 char szFilename[4];
72} DEP, *PDEP;
73
74
75/*******************************************************************************
76* Global Variables *
77*******************************************************************************/
78/** List of dependencies. */
79static PDEP g_pDeps = NULL;
80
81
82/*******************************************************************************
83* Internal Functions *
84*******************************************************************************/
85static PDEP depAdd(const char *pszFilename, size_t cchFilename);
86static void depOptimize(int fFixCase);
87static void depPrint(FILE *pOutput);
88static void depPrintStubs(FILE *pOutput);
89
90
91#ifdef __WIN32__
92/**
93 * Corrects the case of a path.
94 * Expects a fullpath!
95 *
96 * @param pszPath Pointer to the path, both input and output.
97 * The buffer must be able to hold one more byte than the string length.
98 */
99void fixcase(char *pszPath)
100{
101#define my_assert(expr) \
102 do { \
103 if (!(expr)) { \
104 printf("my_assert: %s, file %s, line %d\npszPath=%s\npsz=%s\n", \
105 #expr, __FILE__, __LINE__, pszPath, psz); \
106 __asm { __asm int 3 } \
107 exit(1); \
108 } \
109 } while (0)
110
111 char *psz = pszPath;
112 if (*psz == '/' || *psz == '\\')
113 {
114 if (psz[1] == '/' || psz[1] == '\\')
115 {
116 /* UNC */
117 my_assert(psz[1] == '/' || psz[1] == '\\');
118 my_assert(psz[2] != '/' && psz[2] != '\\');
119
120 /* skip server name */
121 psz += 2;
122 while (*psz != '\\' && *psz != '/')
123 {
124 if (!*psz)
125 return;
126 *psz++ = toupper(*psz);
127 }
128
129 /* skip the share name */
130 psz++;
131 my_assert(*psz != '/' && *psz != '\\');
132 while (*psz != '\\' && *psz != '/')
133 {
134 if (!*psz)
135 return;
136 *psz++ = toupper(*psz);
137 }
138 my_assert(*psz == '/' || *psz == '\\');
139 psz++;
140 }
141 else
142 {
143 /* Unix spec */
144 psz++;
145 }
146 }
147 else
148 {
149 /* Drive letter */
150 my_assert(psz[1] == ':');
151 *psz = toupper(*psz);
152 my_assert(psz[0] >= 'A' && psz[0] <= 'Z');
153 my_assert(psz[2] == '/' || psz[2] == '\\');
154 psz += 3;
155 }
156
157 /*
158 * Pointing to the first char after the unc or drive specifier.
159 */
160 while (*psz)
161 {
162 WIN32_FIND_DATA FindFileData;
163 HANDLE hDir;
164 char chSaved0;
165 char chSaved1;
166 char *pszEnd;
167
168
169 /* find the end of the component. */
170 pszEnd = psz;
171 while (*pszEnd && *pszEnd != '/' && *pszEnd != '\\')
172 pszEnd++;
173
174 /* replace the end with "?\0" */
175 chSaved0 = pszEnd[0];
176 chSaved1 = pszEnd[1];
177 pszEnd[0] = '?';
178 pszEnd[1] = '\0';
179
180 /* find the right filename. */
181 hDir = FindFirstFile(pszPath, &FindFileData);
182 pszEnd[1] = chSaved1;
183 if (!hDir)
184 {
185 pszEnd[0] = chSaved0;
186 return;
187 }
188 pszEnd[0] = '\0';
189 while (stricmp(FindFileData.cFileName, psz))
190 {
191 if (!FindNextFile(hDir, &FindFileData))
192 {
193 pszEnd[0] = chSaved0;
194 return;
195 }
196 }
197 strcpy(psz, FindFileData.cFileName);
198 pszEnd[0] = chSaved0;
199
200 /* advance to the next component */
201 if (!chSaved0)
202 return;
203 psz = pszEnd + 1;
204 my_assert(*psz != '/' && *psz != '\\');
205 }
206#undef my_assert
207}
208
209/**
210 * Corrects all slashes to unix slashes.
211 *
212 * @returns pszFilename.
213 * @param pszFilename The filename to correct.
214 */
215char *fixslash(char *pszFilename)
216{
217 char *psz = pszFilename;
218 while ((psz = strchr(psz, '\\')) != NULL)
219 *psz++ = '/';
220 return pszFilename;
221}
222
223#elif defined(__OS2__)
224
225/**
226 * Corrects the case of a path.
227 *
228 * @param pszPath Pointer to the path, both input and output.
229 * The buffer must be able to hold one more byte than the string length.
230 */
231void fixcase(char *pszFilename)
232{
233 return;
234}
235
236#else
237
238/**
239 * Corrects the case of a path.
240 *
241 * @param pszPath Pointer to the path, both input and output.
242 */
243void fixcase(char *pszFilename)
244{
245 char *psz;
246
247 /*
248 * Skip the root.
249 */
250 psz = pszFilename;
251 while (*psz == '/')
252 psz++;
253
254 /*
255 * Iterate all the components.
256 */
257 while (*psz)
258 {
259 char chSlash;
260 struct stat s;
261 char *pszStart = psz;
262
263 /*
264 * Find the next slash (or end of string) and terminate the string there.
265 */
266 while (*psz != '/' && *psz)
267 *psz++;
268 chSlash = *psz;
269 *psz = '\0';
270
271 /*
272 * Does this part exist?
273 * If not we'll enumerate the directory and search for an case-insensitive match.
274 */
275 if (stat(pszFilename, &s))
276 {
277 struct dirent *pEntry;
278 DIR *pDir;
279 if (pszStart == pszFilename)
280 pDir = opendir(*pszFilename ? pszFilename : ".");
281 else
282 {
283 pszStart[-1] = '\0';
284 pDir = opendir(pszFilename);
285 pszStart[-1] = '/';
286 }
287 if (!pDir)
288 {
289 *psz = chSlash;
290 break; /* giving up, if we fail to open the directory. */
291 }
292
293 while ((pEntry = readdir(pDir)) != NULL)
294 {
295 if (!strcasecmp(pEntry->d_name, pszStart))
296 {
297 strcpy(pszStart, pEntry->d_name);
298 break;
299 }
300 }
301 closedir(pDir);
302 if (!pEntry)
303 {
304 *psz = chSlash;
305 break; /* giving up if not found. */
306 }
307 }
308
309 /* restore the slash and press on. */
310 *psz = chSlash;
311 while (*psz == '/')
312 psz++;
313 }
314
315 return;
316}
317
318
319#endif
320
321
322/**
323 * 'Optimizes' and corrects the dependencies.
324 */
325static void depOptimize(int fFixCase)
326{
327 /*
328 * Walk the list correct the names and re-insert them.
329 */
330 PDEP pDepOrg = g_pDeps;
331 PDEP pDep = g_pDeps;
332 g_pDeps = NULL;
333 for (; pDep; pDep = pDep->pNext)
334 {
335#ifdef __WIN32__
336 char szFilename[_MAX_PATH + 1];
337#else
338 char szFilename[PATH_MAX + 1];
339#endif
340 char *pszFilename;
341 struct stat s;
342
343 /*
344 * Skip some fictive names like <built-in> and <command line>.
345 */
346 if ( pDep->szFilename[0] == '<'
347 && pDep->szFilename[pDep->cchFilename - 1] == '>')
348 continue;
349 pszFilename = pDep->szFilename;
350
351#if !defined(__OS2__) && !defined(__WIN32__)
352 /*
353 * Skip any drive letters from compilers running in wine.
354 */
355 if (pszFilename[1] == ':')
356 pszFilename += 2;
357#endif
358
359 /*
360 * The microsoft compilers are notoriously screwing up the casing.
361 * This will screw up kmk (/ GNU Make).
362 */
363 if (fFixCase)
364 {
365#ifdef __WIN32__
366 if (_fullpath(szFilename, pszFilename, sizeof(szFilename)))
367 fixslash(szFilename);
368 else
369#endif
370 strcpy(szFilename, pszFilename);
371 fixcase(szFilename);
372 pszFilename = szFilename;
373 }
374
375 /*
376 * Check that the file exists before we start depending on it.
377 */
378 if (stat(pszFilename, &s))
379 {
380 fprintf(stderr, "kDepPre: Skipping '%s' - %s!\n", szFilename, strerror(errno));
381 continue;
382 }
383
384 /*
385 * Insert the corrected dependency.
386 */
387 depAdd(pszFilename, strlen(pszFilename));
388 }
389
390#if 0 /* waste of time */
391 /*
392 * Free the old ones.
393 */
394 while (pDepOrg)
395 {
396 pDep = pDepOrg;
397 pDepOrg = pDepOrg->pNext;
398 free(pDep);
399 }
400#endif
401}
402
403
404/**
405 * Prints the dependency chain.
406 *
407 * @returns Pointer to the allocated dependency.
408 * @param pOutput Output stream.
409 */
410static void depPrint(FILE *pOutput)
411{
412 PDEP pDep;
413 for (pDep = g_pDeps; pDep; pDep = pDep->pNext)
414 fprintf(pOutput, " \\\n\t%s", pDep->szFilename);
415 fprintf(pOutput, "\n\n");
416}
417
418
419/**
420 * Prints empty dependency stubs for all dependencies.
421 */
422static void depPrintStubs(FILE *pOutput)
423{
424 PDEP pDep;
425 for (pDep = g_pDeps; pDep; pDep = pDep->pNext)
426 fprintf(pOutput, "%s:\n\n", pDep->szFilename);
427}
428
429
430/* sdbm:
431 This algorithm was created for sdbm (a public-domain reimplementation of
432 ndbm) database library. it was found to do well in scrambling bits,
433 causing better distribution of the keys and fewer splits. it also happens
434 to be a good general hashing function with good distribution. the actual
435 function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below
436 is the faster version used in gawk. [there is even a faster, duff-device
437 version] the magic constant 65599 was picked out of thin air while
438 experimenting with different constants, and turns out to be a prime.
439 this is one of the algorithms used in berkeley db (see sleepycat) and
440 elsewhere. */
441static unsigned sdbm(const char *str)
442{
443 unsigned hash = 0;
444 int c;
445
446 while ((c = *(unsigned const char *)str++))
447 hash = c + (hash << 6) + (hash << 16) - hash;
448
449 return hash;
450}
451
452
453/**
454 * Adds a dependency.
455 *
456 * @returns Pointer to the allocated dependency.
457 * @param pszFilename The filename.
458 * @param cchFilename The length of the filename.
459 */
460static PDEP depAdd(const char *pszFilename, size_t cchFilename)
461{
462 unsigned uHash = sdbm(pszFilename);
463 PDEP pDep;
464 PDEP pDepPrev;
465
466 /*
467 * Check if we've already got this one.
468 */
469 pDepPrev = NULL;
470 for (pDep = g_pDeps; pDep; pDepPrev = pDep, pDep = pDep->pNext)
471 if ( pDep->uHash == uHash
472 && pDep->cchFilename == cchFilename
473 && !memcmp(pDep->szFilename, pszFilename, cchFilename))
474 return pDep;
475
476 /*
477 * Add it.
478 */
479 pDep = (PDEP)malloc(sizeof(*pDep) + cchFilename);
480 if (!pDep)
481 {
482 fprintf(stderr, "\nOut of memory! (requested %#x bytes)\n\n", sizeof(*pDep) + cchFilename);
483 exit(1);
484 }
485
486 pDep->cchFilename = cchFilename;
487 memcpy(pDep->szFilename, pszFilename, cchFilename + 1);
488 pDep->uHash = uHash;
489
490 if (pDepPrev)
491 {
492 pDep->pNext = pDepPrev->pNext;
493 pDepPrev->pNext = pDep;
494 }
495 else
496 {
497 pDep->pNext = g_pDeps;
498 g_pDeps = pDep;
499 }
500 return pDep;
501}
502
503
504/**
505 * Parses the output from a preprocessor of a C-style language.
506 *
507 * @returns 0 on success.
508 * @returns 1 or other approriate exit code on failure.
509 * @param pInput Input stream. (probably not seekable)
510 */
511static int ParseCPrecompiler(FILE *pInput)
512{
513 enum
514 {
515 C_DISCOVER = 0,
516 C_SKIP_LINE,
517 C_PARSE_FILENAME,
518 C_EOF
519 } enmMode = C_DISCOVER;
520 PDEP pDep = NULL;
521 int ch;
522 char szBuf[8192];
523
524 for (;;)
525 {
526 switch (enmMode)
527 {
528 /*
529 * Start of line, need to look for '#[[:space]]*line <num> "file"' and '# <num> "file"'.
530 */
531 case C_DISCOVER:
532 /* first find '#' */
533 while ((ch = FGETC(pInput)) != EOF)
534 if (!isblank(ch))
535 break;
536 if (ch == '#')
537 {
538 /* skip spaces */
539 while ((ch = FGETC(pInput)) != EOF)
540 if (!isblank(ch))
541 break;
542
543 /* check for "line" */
544 if (ch == 'l')
545 {
546 if ( (ch = FGETC(pInput)) == 'i'
547 && (ch = FGETC(pInput)) == 'n'
548 && (ch = FGETC(pInput)) == 'e')
549 {
550 ch = FGETC(pInput);
551 if (isblank(ch))
552 {
553 /* skip spaces */
554 while ((ch = FGETC(pInput)) != EOF)
555 if (!isblank(ch))
556 break;
557 }
558 else
559 ch = 'x';
560 }
561 else
562 ch = 'x';
563 }
564
565 /* line number */
566 if (ch >= '0' && ch <= '9')
567 {
568 /* skip the number following spaces */
569 while ((ch = FGETC(pInput)) != EOF)
570 if (!isxdigit(ch))
571 break;
572 if (isblank(ch))
573 {
574 while ((ch = FGETC(pInput)) != EOF)
575 if (!isblank(ch))
576 break;
577 /* quoted filename */
578 if (ch == '"')
579 {
580 enmMode = C_PARSE_FILENAME;
581 break;
582 }
583 }
584 }
585 }
586 enmMode = C_SKIP_LINE;
587 break;
588
589 /*
590 * Skip past the end of the current line.
591 */
592 case C_SKIP_LINE:
593 do
594 {
595 if ( ch == '\r'
596 || ch == '\n')
597 break;
598 } while ((ch = FGETC(pInput)) != EOF);
599 enmMode = C_DISCOVER;
600 break;
601
602 /*
603 * Parse the filename.
604 */
605 case C_PARSE_FILENAME:
606 {
607 /* retreive and unescape the filename. */
608 char *psz = &szBuf[0];
609 while ( (ch = FGETC(pInput)) != EOF
610 && psz < &szBuf[sizeof(szBuf) - 1])
611 {
612 if (ch == '\\')
613 {
614 ch = FGETC(pInput);
615 switch (ch)
616 {
617 case '\\': ch = '/'; break;
618 case 't': ch = '\t'; break;
619 case 'r': ch = '\r'; break;
620 case 'n': ch = '\n'; break;
621 case 'b': ch = '\b'; break;
622 default:
623 fprintf(stderr, "warning: unknown escape char '%c'\n", ch);
624 continue;
625
626 }
627 *psz++ = ch == '\\' ? '/' : ch;
628 }
629 else if (ch != '"')
630 *psz++ = ch;
631 else
632 {
633 size_t cchFilename = psz - &szBuf[0];
634 *psz = '\0';
635 /* compare with current dep, add & switch on mismatch. */
636 if ( !pDep
637 || pDep->cchFilename != cchFilename
638 || memcmp(pDep->szFilename, szBuf, cchFilename))
639 pDep = depAdd(szBuf, cchFilename);
640 break;
641 }
642 }
643 enmMode = C_SKIP_LINE;
644 break;
645 }
646
647 /*
648 * Handle EOF.
649 */
650 case C_EOF:
651 if (feof(pInput))
652 return 0;
653 enmMode = C_DISCOVER;
654 break;
655 }
656 if (ch == EOF)
657 enmMode = C_EOF;
658 }
659
660 return 0;
661}
662
663
664/**
665 * Make an attempt at parsing a Visual C++ IDB file.
666 */
667static int ParseVCxxIDB(FILE *pInput, const char *argv0)
668{
669 char *pbFile;
670 long cbFile;
671 int rc = 0;
672
673 /*
674 * Figure out file size.
675 */
676 if ( fseek(pInput, 0, SEEK_END) < 0
677 || (cbFile = ftell(pInput)) < 0
678 || fseek(pInput, 0, SEEK_SET))
679 {
680 fprintf(stderr, "%s: error: Failed to determin file size of the Visual C++ IDB file.\n", argv0);
681 return -1;
682 }
683
684 /*
685 * Allocate memory and read the file.
686 */
687 pbFile = (char *)malloc(cbFile + 1);
688 if (!pbFile)
689 {
690 fprintf(stderr, "%s: error: Failed to allocate %ld bytes of memory for the Visual C++ IDB file.\n", argv0, cbFile);
691 return -1;
692 }
693 if (fread(pbFile, cbFile, 1, pInput))
694 {
695 const char *pszPrefix = NULL;
696 int cchPrefix = 0;
697 pbFile[cbFile] = '\0';
698
699 /*
700 * Check the header.
701 */
702 if (!strncmp(pbFile, "Microsoft C/C++ MSF 7.", sizeof("Microsoft C/C++ MSF 7.") - 1))
703 {
704 pszPrefix = "/mr/inversedeps/";
705 cchPrefix = sizeof("/mr/inversedeps/") - 1;
706 }
707 else if (!strncmp(pbFile, "Microsoft C/C++ program database 2.", sizeof("Microsoft C/C++ program database 2.") - 1))
708 {
709 pszPrefix = "/ipm/header/";
710 cchPrefix = sizeof("/ipm/header/") - 1;
711 }
712 if (pszPrefix)
713 {
714 /*
715 * Do a brute force scan of the file until we encounter "\0/mr/inversedeps/" (which is the
716 * vc70 and vc80 prefix) or "\0/ipm/header/" (which is the vc60 prefix).
717 * (This is highly experimental and I've no idea about the actual format of the file.)
718 */
719 char *pb = pbFile;
720 long cbLeft = cbFile;
721 while (cbLeft > cchPrefix + 3)
722 {
723 /** @todo use memchr? */
724 if ( *pb != *pszPrefix
725 || strncmp(pb, pszPrefix, cchPrefix))
726 {
727 pb++;
728 cbLeft--;
729 }
730 else
731 {
732 const char *psz = &pb[cchPrefix];
733 size_t cch = strlen(psz);
734 depAdd(psz, cch);
735 //printf("dep='%s'\n", psz);
736 pb += cch + cchPrefix;
737 cbLeft -= cch + cchPrefix;
738 }
739 }
740 }
741 else
742 {
743 fprintf(stderr, "%s: error: Doesn't recognize the header of the Visual C++ IDB file.\n", argv0, cbFile);
744 rc = 1;
745 }
746 }
747 else
748 {
749 fprintf(stderr, "%s: error: Failed to allocate %ld bytes of memory for the Visual C++ IDB file.\n", argv0, cbFile);
750 rc = 1;
751 }
752
753 return rc;
754}
755
756
757static void usage(const char *argv0)
758{
759 printf("syntax: %s [-l=c] -o <output> -t <target> [-f] [-s] < - | <filename> | -e <cmdline> | -i <vc idb-file> >\n", argv0);
760}
761
762
763int main(int argc, char *argv[])
764{
765 int i;
766
767 /* Arguments. */
768 int iExec = 0;
769 FILE *pOutput = NULL;
770 const char *pszOutput = NULL;
771 FILE *pInput = NULL;
772 const char *pszTarget = NULL;
773 int fStubs = 0;
774 int fFixCase = 0;
775 /* Argument parsing. */
776 int fInput = 0; /* set when we've found input argument. */
777 int fIDBMode = 0;
778
779 /*
780 * Parse arguments.
781 */
782 if (argc <= 1)
783 {
784 usage(argv[0]);
785 return 1;
786 }
787 for (i = 1; i < argc; i++)
788 {
789 if (argv[i][0] == '-')
790 {
791 switch (argv[i][1])
792 {
793 /*
794 * Output file.
795 */
796 case 'o':
797 {
798 pszOutput = &argv[i][2];
799 if (pOutput)
800 {
801 fprintf(stderr, "%s: syntax error: only one output file!\n", argv[0]);
802 return 1;
803 }
804 if (!*pszOutput)
805 {
806 if (++i >= argc)
807 {
808 fprintf(stderr, "%s: syntax error: The '-o' argument is missing the filename.\n", argv[0]);
809 return 1;
810 }
811 pszOutput = argv[i];
812 }
813 if (pszOutput[0] == '-' && !pszOutput[1])
814 pOutput = stdout;
815 else
816 pOutput = fopen(pszOutput, "w");
817 if (!pOutput)
818 {
819 fprintf(stderr, "%s: error: Failed to create output file '%s'.\n", argv[0], pszOutput);
820 return 1;
821 }
822 break;
823 }
824
825 /*
826 * Language spec.
827 */
828 case 'l':
829 {
830 const char *psz = &argv[i][2];
831 if (*psz == '=')
832 psz++;
833 if (!strcmp(psz, "c"))
834 ;
835 else
836 {
837 fprintf(stderr, "%s: error: The '%s' language is not supported.\n", argv[0], psz);
838 return 1;
839 }
840 break;
841 }
842
843 /*
844 * Target name.
845 */
846 case 't':
847 {
848 if (pszTarget)
849 {
850 fprintf(stderr, "%s: syntax error: only one target!\n", argv[0]);
851 return 1;
852 }
853 pszTarget = &argv[i][2];
854 if (!*pszTarget)
855 {
856 if (++i >= argc)
857 {
858 fprintf(stderr, "%s: syntax error: The '-t' argument is missing the target name.\n", argv[0]);
859 return 1;
860 }
861 pszTarget = argv[i];
862 }
863 break;
864 }
865
866 /*
867 * Exec.
868 */
869 case 'e':
870 {
871 if (++i >= argc)
872 {
873 fprintf(stderr, "%s: syntax error: The '-e' argument is missing the command.\n", argv[0]);
874 return 1;
875 }
876 iExec = i;
877 i = argc - 1;
878 break;
879 }
880
881 /*
882 * Pipe input.
883 */
884 case '\0':
885 {
886 pInput = stdin;
887 fInput = 1;
888 break;
889 }
890
891 /*
892 * IDB input.
893 */
894 case 'i':
895 {
896 if (++i >= argc)
897 {
898 fprintf(stderr, "%s: syntax error: The '-i' argument is missing IDB filename.\n", argv[0]);
899 return 1;
900 }
901 pInput = fopen(argv[i], "rb");
902 if (!pInput)
903 {
904 fprintf(stderr, "%s: error: Failed to open input file '%s'.\n", argv[0], argv[i]);
905 return 1;
906 }
907 fInput = 1;
908 fIDBMode = 1;
909 break;
910 }
911
912 /*
913 * Fix case.
914 */
915 case 'f':
916 {
917 fFixCase = 1;
918 break;
919 }
920
921 /*
922 * Generate stubs.
923 */
924 case 's':
925 {
926 fStubs = 1;
927 break;
928 }
929
930 /*
931 * Invalid argument.
932 */
933 default:
934 fprintf(stderr, "%s: syntax error: Invalid argument '%s'.\n", argv[0], argv[i]);
935 usage(argv[0]);
936 return 1;
937 }
938 }
939 else
940 {
941 pInput = fopen(argv[i], "r");
942 if (!pInput)
943 {
944 fprintf(stderr, "%s: error: Failed to open input file '%s'.\n", argv[0], argv[i]);
945 return 1;
946 }
947 fInput = 1;
948 }
949
950 /*
951 * End of the line?
952 */
953 if (fInput)
954 {
955 if (++i < argc)
956 {
957 fprintf(stderr, "%s: syntax error: No arguments shall follow the input spec.\n", argv[0]);
958 return 1;
959 }
960 break;
961 }
962 }
963
964 /*
965 * Got all we require?
966 */
967 if (!pInput && iExec <= 0)
968 {
969 fprintf(stderr, "%s: syntax error: No input!\n", argv[0]);
970 return 1;
971 }
972 if (!pOutput)
973 {
974 fprintf(stderr, "%s: syntax error: No output!\n", argv[0]);
975 return 1;
976 }
977 if (!pszTarget)
978 {
979 fprintf(stderr, "%s: syntax error: No target!\n", argv[0]);
980 return 1;
981 }
982
983 /*
984 * Spawn process?
985 */
986 if (iExec > 0)
987 {
988 fprintf(stderr, "%s: -e is not yet implemented!\n", argv[0]);
989 return 1;
990 }
991
992 /*
993 * Do the parsing.
994 */
995 if (!fIDBMode)
996 i = ParseCPrecompiler(pInput);
997 else
998 i = ParseVCxxIDB(pInput, argv[0]);
999
1000 /*
1001 * Reap child.
1002 */
1003 if (iExec > 0)
1004 {
1005 // later
1006 }
1007
1008 /*
1009 * Write the dependecy file.
1010 */
1011 if (!i)
1012 {
1013 depOptimize(fFixCase);
1014 fprintf(pOutput, "%s:", pszTarget);
1015 depPrint(pOutput);
1016 if (fStubs)
1017 depPrintStubs(pOutput);
1018 }
1019
1020 /*
1021 * Close the output, delete output on failure.
1022 */
1023 if (!i && ferror(pOutput))
1024 {
1025 i = 1;
1026 fprintf(stderr, "%s: error: Error writing to '%s'.\n", argv[0], pszOutput);
1027 }
1028 fclose(pOutput);
1029 if (i)
1030 {
1031 if (unlink(pszOutput))
1032 fprintf(stderr, "%s: warning: failed to remove output file '%s' on failure.\n", argv[0], pszOutput);
1033 }
1034
1035 return i;
1036}
Note: See TracBrowser for help on using the repository browser.

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