VirtualBox

source: kBuild/trunk/src/kmk/kmkbuiltin/kDepIDB.c@ 2452

Last change on this file since 2452 was 2413, checked in by bird, 14 years ago

copyright year update.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.9 KB
Line 
1/* $Id: kDepIDB.c 2413 2010-09-11 17:43:04Z bird $ */
2/** @file
3 * kDepIDB - Extract dependency information from a MS Visual C++ .idb file.
4 */
5
6/*
7 * Copyright (c) 2007-2010 knut st. osmundsen <[email protected]>
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 3 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, see <http://www.gnu.org/licenses/>
23 *
24 */
25
26/*******************************************************************************
27* Header Files *
28*******************************************************************************/
29#include "config.h"
30#include <stdio.h>
31#include <stdlib.h>
32#include <stddef.h>
33#include <string.h>
34#include <errno.h>
35#include <ctype.h>
36#ifdef HAVE_ALLOCA_H
37# include <alloca.h>
38#endif
39#if !defined(_MSC_VER)
40# include <unistd.h>
41#else
42# include <io.h>
43#endif
44#include "../../lib/k/kDefs.h"
45#include "../../lib/k/kTypes.h"
46#include "../../lib/kDep.h"
47#include "kmkbuiltin.h"
48
49
50/*******************************************************************************
51* Defined Constants And Macros *
52*******************************************************************************/
53/*#define DEBUG*/
54#ifdef DEBUG
55# define dprintf(a) printf a
56# define dump(pb, cb, offBase) depHexDump(pb,cb,offBase)
57#else
58# define dprintf(a) do {} while (0)
59# define dump(pb, cb, offBase) do {} while (0)
60#endif
61
62
63/*******************************************************************************
64* Global Variables *
65*******************************************************************************/
66/** the executable name. */
67static const char *argv0 = "";
68
69
70/**
71 * Scans a stream (chunk of data really) for dependencies.
72 *
73 * @returns 0 on success.
74 * @returns !0 on failure.
75 * @param pbStream The stream bits.
76 * @param cbStream The size of the stream.
77 * @param pszPrefix The dependency prefix.
78 * @param cchPrefix The size of the prefix.
79 */
80static int ScanStream(KU8 *pbStream, size_t cbStream, const char *pszPrefix, size_t cchPrefix)
81{
82 const KU8 *pbCur = pbStream;
83 size_t cbLeft = cbStream;
84 register char chFirst = *pszPrefix;
85 while (cbLeft > cchPrefix + 2)
86 {
87 if ( *pbCur != chFirst
88 || memcmp(pbCur, pszPrefix, cchPrefix))
89 {
90 pbCur++;
91 cbLeft--;
92 }
93 else
94 {
95 size_t cchDep;
96 pbCur += cchPrefix;
97 cchDep = strlen((const char *)pbCur);
98 depAdd((const char *)pbCur, cchDep);
99 dprintf(("%05x: '%s'\n", pbCur - pbStream, pbCur));
100
101 pbCur += cchDep;
102 cbLeft -= cchDep + cchPrefix;
103 }
104 }
105
106 return 0;
107}
108
109
110/*/////////////////////////////////////////////////////////////////////////////
111//
112//
113// P D B 7 . 0
114//
115//
116/////////////////////////////////////////////////////////////////////////////*/
117
118/** A PDB 7.0 Page number. */
119typedef KU32 PDB70PAGE;
120/** Pointer to a PDB 7.0 Page number. */
121typedef PDB70PAGE *PPDB70PAGE;
122
123/**
124 * A PDB 7.0 stream.
125 */
126typedef struct PDB70STREAM
127{
128 /** The size of the stream. */
129 KU32 cbStream;
130} PDB70STREAM, *PPDB70STREAM;
131
132
133/** The PDB 7.00 signature. */
134#define PDB_SIGNATURE_700 "Microsoft C/C++ MSF 7.00\r\n\x1A" "DS\0\0"
135/**
136 * The PDB 7.0 header.
137 */
138typedef struct PDB70HDR
139{
140 /** The signature string. */
141 KU8 szSignature[sizeof(PDB_SIGNATURE_700)];
142 /** The page size. */
143 KU32 cbPage;
144 /** The start page. */
145 PDB70PAGE iStartPage;
146 /** The number of pages in the file. */
147 PDB70PAGE cPages;
148 /** The root stream directory. */
149 KU32 cbRoot;
150 /** Unknown function, always 0. */
151 KU32 u32Reserved;
152 /** The page index of the root page table. */
153 PDB70PAGE iRootPages;
154} PDB70HDR, *PPDB70HDR;
155
156/**
157 * The PDB 7.0 root directory.
158 */
159typedef struct PDB70ROOT
160{
161 /** The number of streams */
162 KU32 cStreams;
163 /** Array of streams. */
164 PDB70STREAM aStreams[1];
165 /* KU32 aiPages[] */
166} PDB70ROOT, *PPDB70ROOT;
167
168/**
169 * The PDB 7.0 name stream (#1) header.
170 */
171typedef struct PDB70NAMES
172{
173 /** The structure version. */
174 KU32 Version;
175 /** Timestamp. */
176 KU32 TimeStamp;
177 /** Unknown. */
178 KU32 Unknown1;
179 /** GUID. */
180 KU32 u32Guid[4];
181 /** The size of the following name table. */
182 KU32 cbNames;
183 /** The name table. */
184 char szzNames[1];
185} PDB70NAMES, *PPDB70NAMES;
186
187/** The version / magic of the names structure. */
188#define PDB70NAMES_VERSION 20000404
189
190
191static int Pdb70ValidateHeader(PPDB70HDR pHdr, size_t cbFile)
192{
193 if (pHdr->cbPage * pHdr->cPages != cbFile)
194 {
195 fprintf(stderr, "%s: error: Bad PDB 2.0 header - cbPage * cPages != cbFile.\n", argv0);
196 return 1;
197 }
198 if (pHdr->iStartPage >= pHdr->cPages && pHdr->iStartPage <= 0)
199 {
200 fprintf(stderr, "%s: error: Bad PDB 2.0 header - iStartPage=%u cPages=%u.\n", argv0,
201 pHdr->iStartPage, pHdr->cPages);
202 return 1;
203 }
204 if (pHdr->iRootPages >= pHdr->cPages && pHdr->iRootPages <= 0)
205 {
206 fprintf(stderr, "%s: error: Bad PDB 2.0 header - iRootPages=%u cPage=%u.\n", argv0,
207 pHdr->iStartPage, pHdr->cPages);
208 return 1;
209 }
210 return 0;
211}
212
213#ifdef DEBUG
214static size_t Pdb70Align(PPDB70HDR pHdr, size_t cb)
215{
216 if (cb == ~(KU32)0 || !cb)
217 return 0;
218 return ((cb + pHdr->cbPage - 1) / pHdr->cbPage) * pHdr->cbPage;
219}
220#endif /* DEBUG */
221
222static size_t Pdb70Pages(PPDB70HDR pHdr, size_t cb)
223{
224 if (cb == ~(KU32)0 || !cb)
225 return 0;
226 return (cb + pHdr->cbPage - 1) / pHdr->cbPage;
227}
228
229static void *Pdb70AllocAndRead(PPDB70HDR pHdr, size_t cb, PPDB70PAGE paiPageMap)
230{
231 const size_t cbPage = pHdr->cbPage;
232 size_t cPages = Pdb70Pages(pHdr, cb);
233 KU8 *pbBuf = malloc(cPages * cbPage + 1);
234 if (pbBuf)
235 {
236 size_t iPage = 0;
237 while (iPage < cPages)
238 {
239 size_t off = paiPageMap[iPage];
240 if (off < pHdr->cPages)
241 {
242 off *= cbPage;
243 memcpy(pbBuf + iPage * cbPage, (KU8 *)pHdr + off, cbPage);
244 dump(pbBuf + iPage * cbPage, iPage + 1 < cPages ? cbPage : cb % cbPage, off);
245 }
246 else
247 {
248 fprintf(stderr, "%s: warning: Invalid page index %u (max %u)!\n", argv0,
249 (unsigned)off, pHdr->cPages);
250 memset(pbBuf + iPage * cbPage, 0, cbPage);
251 }
252
253 iPage++;
254 }
255 pbBuf[cPages * cbPage] = '\0';
256 }
257 else
258 fprintf(stderr, "%s: error: failed to allocate %lu bytes\n", argv0, (unsigned long)(cPages * cbPage + 1));
259 return pbBuf;
260}
261
262static PPDB70ROOT Pdb70AllocAndReadRoot(PPDB70HDR pHdr)
263{
264 /*
265 * The tricky bit here is to find the right length. Really?
266 * (Todo: Check if we can just use the stream #0 size..)
267 */
268 PPDB70PAGE piPageMap = (KU32 *)((KU8 *)pHdr + pHdr->iRootPages * pHdr->cbPage);
269 PPDB70ROOT pRoot = Pdb70AllocAndRead(pHdr, pHdr->cbRoot, piPageMap);
270 if (pRoot)
271 {
272#if 1
273 /* This stuff is probably unnecessary: */
274 /* size = stream header + array of stream. */
275 size_t cb = K_OFFSETOF(PDB70ROOT, aStreams[pRoot->cStreams]);
276 free(pRoot);
277 pRoot = Pdb70AllocAndRead(pHdr, cb, piPageMap);
278 if (pRoot)
279 {
280 /* size += page tables. */
281 unsigned iStream = pRoot->cStreams;
282 while (iStream-- > 0)
283 if (pRoot->aStreams[iStream].cbStream != ~(KU32)0)
284 cb += Pdb70Pages(pHdr, pRoot->aStreams[iStream].cbStream) * sizeof(PDB70PAGE);
285 free(pRoot);
286 pRoot = Pdb70AllocAndRead(pHdr, cb, piPageMap);
287 if (pRoot)
288 {
289 /* validate? */
290 return pRoot;
291 }
292 }
293#else
294 /* validate? */
295 return pRoot;
296#endif
297 }
298 return NULL;
299}
300
301static void *Pdb70AllocAndReadStream(PPDB70HDR pHdr, PPDB70ROOT pRoot, unsigned iStream, size_t *pcbStream)
302{
303 const size_t cbStream = pRoot->aStreams[iStream].cbStream;
304 PPDB70PAGE paiPageMap;
305 if ( iStream >= pRoot->cStreams
306 || cbStream == ~(KU32)0)
307 {
308 fprintf(stderr, "%s: error: Invalid stream %d\n", argv0, iStream);
309 return NULL;
310 }
311
312 paiPageMap = (PPDB70PAGE)&pRoot->aStreams[pRoot->cStreams];
313 while (iStream-- > 0)
314 if (pRoot->aStreams[iStream].cbStream != ~(KU32)0)
315 paiPageMap += Pdb70Pages(pHdr, pRoot->aStreams[iStream].cbStream);
316
317 if (pcbStream)
318 *pcbStream = cbStream;
319 return Pdb70AllocAndRead(pHdr, cbStream, paiPageMap);
320}
321
322static int Pdb70Process(KU8 *pbFile, size_t cbFile)
323{
324 PPDB70HDR pHdr = (PPDB70HDR)pbFile;
325 PPDB70ROOT pRoot;
326 PPDB70NAMES pNames;
327 size_t cbStream = 0;
328 unsigned fDone = 0;
329 unsigned iStream;
330 int rc = 0;
331 dprintf(("pdb70\n"));
332
333 /*
334 * Validate the header and read the root stream.
335 */
336 if (Pdb70ValidateHeader(pHdr, cbFile))
337 return 1;
338 pRoot = Pdb70AllocAndReadRoot(pHdr);
339 if (!pRoot)
340 return 1;
341
342 /*
343 * The names we want are usually all found in the 'Names' stream, that is #1.
344 */
345 dprintf(("Reading the names stream....\n"));
346 pNames = Pdb70AllocAndReadStream(pHdr, pRoot, 1, &cbStream);
347 if (pNames)
348 {
349 dprintf(("Names: Version=%u cbNames=%u (%#x)\n", pNames->Version, pNames->cbNames, pNames->cbNames));
350 if ( pNames->Version == PDB70NAMES_VERSION
351 && pNames->cbNames > 32
352 && pNames->cbNames + K_OFFSETOF(PDB70NAMES, szzNames) <= pRoot->aStreams[1].cbStream)
353 {
354 /*
355 * Iterate the names and add the /mr/inversedeps/ ones to the dependency list.
356 */
357 const char *psz = &pNames->szzNames[0];
358 size_t cb = pNames->cbNames;
359 size_t off = 0;
360 dprintf(("0x0000 #0: %6d bytes [root / toc]\n", pRoot->aStreams[0].cbStream));
361 for (iStream = 1; cb > 0; iStream++)
362 {
363 int fAdded = 0;
364 size_t cch = strlen(psz);
365 if ( cch >= sizeof("/mr/inversedeps/")
366 && !memcmp(psz, "/mr/inversedeps/", sizeof("/mr/inversedeps/") - 1))
367 {
368 depAdd(psz + sizeof("/mr/inversedeps/") - 1, cch - (sizeof("/mr/inversedeps/") - 1));
369 fAdded = 1;
370 }
371 dprintf(("%#06x #%d: %6d bytes %s%s\n", off, iStream,
372 iStream < pRoot->cStreams ? pRoot->aStreams[iStream].cbStream : -1,
373 psz, fAdded ? " [dep]" : ""));
374 (void)fAdded;
375
376 /* next */
377 if (cch >= cb)
378 {
379 dprintf(("warning! cch=%d cb=%d\n", cch, cb));
380 cch = cb - 1;
381 }
382 cb -= cch + 1;
383 psz += cch + 1;
384 off += cch + 1;
385 }
386 rc = 0;
387 fDone = 1;
388 }
389 else
390 dprintf(("Unknown version or bad size: Version=%u cbNames=%d cbStream=%d\n",
391 pNames->Version, pNames->cbNames, cbStream));
392 free(pNames);
393 }
394
395 if (!fDone)
396 {
397 /*
398 * Iterate the streams in the root and scan their content for
399 * dependencies.
400 */
401 rc = 0;
402 for (iStream = 0; iStream < pRoot->cStreams && !rc; iStream++)
403 {
404 KU8 *pbStream;
405 if ( pRoot->aStreams[iStream].cbStream == ~(KU32)0
406 || !pRoot->aStreams[iStream].cbStream)
407 continue;
408 dprintf(("Stream #%d: %#x bytes (%#x aligned)\n", iStream, pRoot->aStreams[iStream].cbStream,
409 Pdb70Align(pHdr, pRoot->aStreams[iStream].cbStream)));
410 pbStream = (KU8 *)Pdb70AllocAndReadStream(pHdr, pRoot, iStream, &cbStream);
411 if (pbStream)
412 {
413 rc = ScanStream(pbStream, cbStream, "/mr/inversedeps/", sizeof("/mr/inversedeps/") - 1);
414 free(pbStream);
415 }
416 else
417 rc = 1;
418 }
419 }
420
421 free(pRoot);
422 return rc;
423}
424
425
426
427/*/////////////////////////////////////////////////////////////////////////////
428//
429//
430// P D B 2 . 0
431//
432//
433/////////////////////////////////////////////////////////////////////////////*/
434
435
436/** A PDB 2.0 Page number. */
437typedef KU16 PDB20PAGE;
438/** Pointer to a PDB 2.0 Page number. */
439typedef PDB20PAGE *PPDB20PAGE;
440
441/**
442 * A PDB 2.0 stream.
443 */
444typedef struct PDB20STREAM
445{
446 /** The size of the stream. */
447 KU32 cbStream;
448 /** Some unknown value. */
449 KU32 u32Unknown;
450} PDB20STREAM, *PPDB20STREAM;
451
452/** The PDB 2.00 signature. */
453#define PDB_SIGNATURE_200 "Microsoft C/C++ program database 2.00\r\n\x1A" "JG\0"
454/**
455 * The PDB 2.0 header.
456 */
457typedef struct PDB20HDR
458{
459 /** The signature string. */
460 KU8 szSignature[sizeof(PDB_SIGNATURE_200)];
461 /** The page size. */
462 KU32 cbPage;
463 /** The start page - whatever that is... */
464 PDB20PAGE iStartPage;
465 /** The number of pages in the file. */
466 PDB20PAGE cPages;
467 /** The root stream directory. */
468 PDB20STREAM RootStream;
469 /** The root page table. */
470 PDB20PAGE aiRootPageMap[1];
471} PDB20HDR, *PPDB20HDR;
472
473/**
474 * The PDB 2.0 root directory.
475 */
476typedef struct PDB20ROOT
477{
478 /** The number of streams */
479 KU16 cStreams;
480 /** Reserved or high part of cStreams. */
481 KU16 u16Reserved;
482 /** Array of streams. */
483 PDB20STREAM aStreams[1];
484} PDB20ROOT, *PPDB20ROOT;
485
486
487static int Pdb20ValidateHeader(PPDB20HDR pHdr, size_t cbFile)
488{
489 if (pHdr->cbPage * pHdr->cPages != cbFile)
490 {
491 fprintf(stderr, "%s: error: Bad PDB 2.0 header - cbPage * cPages != cbFile.\n", argv0);
492 return 1;
493 }
494 if (pHdr->iStartPage >= pHdr->cPages && pHdr->iStartPage <= 0)
495 {
496 fprintf(stderr, "%s: error: Bad PDB 2.0 header - cbPage * cPages != cbFile.\n", argv0);
497 return 1;
498 }
499 return 0;
500}
501
502static size_t Pdb20Pages(PPDB20HDR pHdr, size_t cb)
503{
504 if (cb == ~(KU32)0 || !cb)
505 return 0;
506 return (cb + pHdr->cbPage - 1) / pHdr->cbPage;
507}
508
509static void *Pdb20AllocAndRead(PPDB20HDR pHdr, size_t cb, PPDB20PAGE paiPageMap)
510{
511 size_t cPages = Pdb20Pages(pHdr, cb);
512 KU8 *pbBuf = malloc(cPages * pHdr->cbPage + 1);
513 if (pbBuf)
514 {
515 size_t iPage = 0;
516 while (iPage < cPages)
517 {
518 size_t off = paiPageMap[iPage];
519 off *= pHdr->cbPage;
520 memcpy(pbBuf + iPage * pHdr->cbPage, (KU8 *)pHdr + off, pHdr->cbPage);
521 iPage++;
522 }
523 pbBuf[cPages * pHdr->cbPage] = '\0';
524 }
525 else
526 fprintf(stderr, "%s: error: failed to allocate %lu bytes\n", argv0, (unsigned long)(cPages * pHdr->cbPage + 1));
527 return pbBuf;
528}
529
530static PPDB20ROOT Pdb20AllocAndReadRoot(PPDB20HDR pHdr)
531{
532 /*
533 * The tricky bit here is to find the right length.
534 * (Todo: Check if we can just use the stream size..)
535 */
536 PPDB20ROOT pRoot = Pdb20AllocAndRead(pHdr, sizeof(*pRoot), &pHdr->aiRootPageMap[0]);
537 if (pRoot)
538 {
539 /* size = stream header + array of stream. */
540 size_t cb = K_OFFSETOF(PDB20ROOT, aStreams[pRoot->cStreams]);
541 free(pRoot);
542 pRoot = Pdb20AllocAndRead(pHdr, cb, &pHdr->aiRootPageMap[0]);
543 if (pRoot)
544 {
545 /* size += page tables. */
546 unsigned iStream = pRoot->cStreams;
547 while (iStream-- > 0)
548 if (pRoot->aStreams[iStream].cbStream != ~(KU32)0)
549 cb += Pdb20Pages(pHdr, pRoot->aStreams[iStream].cbStream) * sizeof(PDB20PAGE);
550 free(pRoot);
551 pRoot = Pdb20AllocAndRead(pHdr, cb, &pHdr->aiRootPageMap[0]);
552 if (pRoot)
553 {
554 /* validate? */
555 return pRoot;
556 }
557 }
558 }
559 return NULL;
560
561}
562
563static void *Pdb20AllocAndReadStream(PPDB20HDR pHdr, PPDB20ROOT pRoot, unsigned iStream, size_t *pcbStream)
564{
565 size_t cbStream = pRoot->aStreams[iStream].cbStream;
566 PPDB20PAGE paiPageMap;
567 if ( iStream >= pRoot->cStreams
568 || cbStream == ~(KU32)0)
569 {
570 fprintf(stderr, "%s: error: Invalid stream %d\n", argv0, iStream);
571 return NULL;
572 }
573
574 paiPageMap = (PPDB20PAGE)&pRoot->aStreams[pRoot->cStreams];
575 while (iStream-- > 0)
576 if (pRoot->aStreams[iStream].cbStream != ~(KU32)0)
577 paiPageMap += Pdb20Pages(pHdr, pRoot->aStreams[iStream].cbStream);
578
579 if (pcbStream)
580 *pcbStream = cbStream;
581 return Pdb20AllocAndRead(pHdr, cbStream, paiPageMap);
582}
583
584static int Pdb20Process(KU8 *pbFile, size_t cbFile)
585{
586 PPDB20HDR pHdr = (PPDB20HDR)pbFile;
587 PPDB20ROOT pRoot;
588 unsigned iStream;
589 int rc = 0;
590
591 /*
592 * Validate the header and read the root stream.
593 */
594 if (Pdb20ValidateHeader(pHdr, cbFile))
595 return 1;
596 pRoot = Pdb20AllocAndReadRoot(pHdr);
597 if (!pRoot)
598 return 1;
599
600 /*
601 * Iterate the streams in the root and scan their content for
602 * dependencies.
603 */
604 rc = 0;
605 for (iStream = 0; iStream < pRoot->cStreams && !rc; iStream++)
606 {
607 KU8 *pbStream;
608 if (pRoot->aStreams[iStream].cbStream == ~(KU32)0)
609 continue;
610 pbStream = (KU8 *)Pdb20AllocAndReadStream(pHdr, pRoot, iStream, NULL);
611 if (pbStream)
612 {
613 rc = ScanStream(pbStream, pRoot->aStreams[iStream].cbStream, "/ipm/header/", sizeof("/ipm/header/") - 1);
614 free(pbStream);
615 }
616 else
617 rc = 1;
618 }
619
620 free(pRoot);
621 return rc;
622}
623
624
625/**
626 * Make an attempt at parsing a Visual C++ IDB file.
627 */
628static int ProcessIDB(FILE *pInput)
629{
630 size_t cbFile;
631 KU8 *pbFile;
632 void *pvOpaque;
633 int rc = 0;
634
635 /*
636 * Read the file into memory.
637 */
638 pbFile = (KU8 *)depReadFileIntoMemory(pInput, &cbFile, &pvOpaque);
639 if (!pbFile)
640 return 1;
641
642 /*
643 * Figure out which parser to use.
644 */
645 if (!memcmp(pbFile, PDB_SIGNATURE_700, sizeof(PDB_SIGNATURE_700)))
646 rc = Pdb70Process(pbFile, cbFile);
647 else if (!memcmp(pbFile, PDB_SIGNATURE_200, sizeof(PDB_SIGNATURE_200)))
648 rc = Pdb20Process(pbFile, cbFile);
649 else
650 {
651 fprintf(stderr, "%s: error: Doesn't recognize the header of the Visual C++ IDB file.\n", argv0);
652 rc = 1;
653 }
654
655 depFreeFileMemory(pbFile, pvOpaque);
656 return rc;
657}
658
659
660static void usage(const char *a_argv0)
661{
662 printf("usage: %s -o <output> -t <target> [-fqs] <vc idb-file>\n"
663 " or: %s --help\n"
664 " or: %s --version\n",
665 a_argv0, a_argv0, a_argv0);
666}
667
668
669int kmk_builtin_kDepIDB(int argc, char *argv[], char **envp)
670{
671 int i;
672
673 /* Arguments. */
674 FILE *pOutput = NULL;
675 const char *pszOutput = NULL;
676 FILE *pInput = NULL;
677 const char *pszTarget = NULL;
678 int fStubs = 0;
679 int fFixCase = 0;
680 /* Argument parsing. */
681 int fInput = 0; /* set when we've found input argument. */
682 int fQuiet = 0;
683
684 argv0 = argv[0];
685
686 /*
687 * Parse arguments.
688 */
689 if (argc <= 1)
690 {
691 usage(argv[0]);
692 return 1;
693 }
694 for (i = 1; i < argc; i++)
695 {
696 if (argv[i][0] == '-')
697 {
698 const char *psz = &argv[i][1];
699 if (*psz == '-')
700 {
701 if (!strcmp(psz, "-quiet"))
702 psz = "q";
703 else if (!strcmp(psz, "-help"))
704 psz = "?";
705 else if (!strcmp(psz, "-version"))
706 psz = "V";
707 }
708
709 switch (*psz)
710 {
711 /*
712 * Output file.
713 */
714 case 'o':
715 {
716 pszOutput = &argv[i][2];
717 if (pOutput)
718 {
719 fprintf(stderr, "%s: syntax error: only one output file!\n", argv[0]);
720 return 1;
721 }
722 if (!*pszOutput)
723 {
724 if (++i >= argc)
725 {
726 fprintf(stderr, "%s: syntax error: The '-o' argument is missing the filename.\n", argv[0]);
727 return 1;
728 }
729 pszOutput = argv[i];
730 }
731 if (pszOutput[0] == '-' && !pszOutput[1])
732 pOutput = stdout;
733 else
734 pOutput = fopen(pszOutput, "w");
735 if (!pOutput)
736 {
737 fprintf(stderr, "%s: error: Failed to create output file '%s'.\n", argv[0], pszOutput);
738 return 1;
739 }
740 break;
741 }
742
743 /*
744 * Target name.
745 */
746 case 't':
747 {
748 if (pszTarget)
749 {
750 fprintf(stderr, "%s: syntax error: only one target!\n", argv[0]);
751 return 1;
752 }
753 pszTarget = &argv[i][2];
754 if (!*pszTarget)
755 {
756 if (++i >= argc)
757 {
758 fprintf(stderr, "%s: syntax error: The '-t' argument is missing the target name.\n", argv[0]);
759 return 1;
760 }
761 pszTarget = argv[i];
762 }
763 break;
764 }
765
766 /*
767 * Fix case.
768 */
769 case 'f':
770 {
771 fFixCase = 1;
772 break;
773 }
774
775 /*
776 * Quiet.
777 */
778 case 'q':
779 {
780 fQuiet = 1;
781 break;
782 }
783
784 /*
785 * Generate stubs.
786 */
787 case 's':
788 {
789 fStubs = 1;
790 break;
791 }
792
793 /*
794 * The mandatory version & help.
795 */
796 case '?':
797 usage(argv[0]);
798 return 0;
799 case 'V':
800 case 'v':
801 return kbuild_version(argv[0]);
802
803 /*
804 * Invalid argument.
805 */
806 default:
807 fprintf(stderr, "%s: syntax error: Invalid argument '%s'.\n", argv[0], argv[i]);
808 usage(argv[0]);
809 return 1;
810 }
811 }
812 else
813 {
814 pInput = fopen(argv[i], "rb");
815 if (!pInput)
816 {
817 fprintf(stderr, "%s: error: Failed to open input file '%s'.\n", argv[0], argv[i]);
818 return 1;
819 }
820 fInput = 1;
821 }
822
823 /*
824 * End of the line?
825 */
826 if (fInput)
827 {
828 if (++i < argc)
829 {
830 fprintf(stderr, "%s: syntax error: No arguments shall follow the input spec.\n", argv[0]);
831 return 1;
832 }
833 break;
834 }
835 }
836
837 /*
838 * Got all we require?
839 */
840 if (!pInput)
841 {
842 fprintf(stderr, "%s: syntax error: No input!\n", argv[0]);
843 return 1;
844 }
845 if (!pOutput)
846 {
847 fprintf(stderr, "%s: syntax error: No output!\n", argv[0]);
848 return 1;
849 }
850 if (!pszTarget)
851 {
852 fprintf(stderr, "%s: syntax error: No target!\n", argv[0]);
853 return 1;
854 }
855
856 /*
857 * Do the parsing.
858 */
859 i = ProcessIDB(pInput);
860 fclose(pInput);
861
862 /*
863 * Write the dependecy file.
864 */
865 if (!i)
866 {
867 depOptimize(fFixCase, fQuiet);
868 fprintf(pOutput, "%s:", pszTarget);
869 depPrint(pOutput);
870 if (fStubs)
871 depPrintStubs(pOutput);
872 }
873
874 /*
875 * Close the output, delete output on failure.
876 */
877 if (!i && ferror(pOutput))
878 {
879 i = 1;
880 fprintf(stderr, "%s: error: Error writing to '%s'.\n", argv[0], pszOutput);
881 }
882 fclose(pOutput);
883 if (i)
884 {
885 if (unlink(pszOutput))
886 fprintf(stderr, "%s: warning: failed to remove output file '%s' on failure.\n", argv[0], pszOutput);
887 }
888
889 depCleanup();
890 return i;
891}
892
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