3 * kDepPre - Dependency Generator using Precompiler output.
7 * Copyright (c) 2005-2009 knut st. osmundsen <bird-kBuild-spamix@anduin.net>
9 * This file is part of kBuild.
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.
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.
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/>
26 /*******************************************************************************
28 *******************************************************************************/
40 #ifdef HAVE_FGETC_UNLOCKED
41 # define FGETC(s) getc_unlocked(s)
43 # define FGETC(s) fgetc(s)
47 # define isblank(ch) ( (unsigned char)(ch) == ' ' || (unsigned char)(ch) == '\t' )
54 * Parses the output from a preprocessor of a C-style language.
56 * @returns 0 on success.
57 * @returns 1 or other approriate exit code on failure.
58 * @param pInput Input stream. (probably not seekable)
60 static int ParseCPrecompiler(FILE *pInput
)
68 } enmMode
= C_DISCOVER
;
78 * Start of line, need to look for '#[[:space]]*line <num> "file"' and '# <num> "file"'.
82 while ((ch
= FGETC(pInput
)) != EOF
)
88 while ((ch
= FGETC(pInput
)) != EOF
)
92 /* check for "line" */
95 if ( (ch
= FGETC(pInput
)) == 'i'
96 && (ch
= FGETC(pInput
)) == 'n'
97 && (ch
= FGETC(pInput
)) == 'e')
103 while ((ch
= FGETC(pInput
)) != EOF
)
115 if (ch
>= '0' && ch
<= '9')
117 /* skip the number following spaces */
118 while ((ch
= FGETC(pInput
)) != EOF
)
123 while ((ch
= FGETC(pInput
)) != EOF
)
126 /* quoted filename */
129 enmMode
= C_PARSE_FILENAME
;
135 enmMode
= C_SKIP_LINE
;
139 * Skip past the end of the current line.
147 } while ((ch
= FGETC(pInput
)) != EOF
);
148 enmMode
= C_DISCOVER
;
152 * Parse the filename.
154 case C_PARSE_FILENAME
:
156 /* retreive and unescape the filename. */
157 char *psz
= &szBuf
[0];
158 while ( (ch
= FGETC(pInput
)) != EOF
159 && psz
< &szBuf
[sizeof(szBuf
) - 1])
166 case '\\': ch
= '/'; break;
167 case 't': ch
= '\t'; break;
168 case 'r': ch
= '\r'; break;
169 case 'n': ch
= '\n'; break;
170 case 'b': ch
= '\b'; break;
172 fprintf(stderr
, "warning: unknown escape char '%c'\n", ch
);
176 *psz
++ = ch
== '\\' ? '/' : ch
;
182 size_t cchFilename
= psz
- &szBuf
[0];
184 /* compare with current dep, add & switch on mismatch. */
186 || pDep
->cchFilename
!= cchFilename
187 || memcmp(pDep
->szFilename
, szBuf
, cchFilename
))
188 pDep
= depAdd(szBuf
, cchFilename
);
192 enmMode
= C_SKIP_LINE
;
202 enmMode
= C_DISCOVER
;
213 static int usage(FILE *pOut
, const char *argv0
)
216 "usage: %s [-l=c] -o <output> -t <target> [-f] [-s] < - | <filename> | -e <cmdline> >\n"
218 " or: %s --version\n",
219 argv0
, argv0
, argv0
);
224 int main(int argc
, char *argv
[])
230 FILE *pOutput
= NULL
;
231 const char *pszOutput
= NULL
;
233 const char *pszTarget
= NULL
;
236 /* Argument parsing. */
237 int fInput
= 0; /* set when we've found input argument. */
243 return usage(stderr
, argv
[0]);
244 for (i
= 1; i
< argc
; i
++)
246 if (argv
[i
][0] == '-')
248 const char *psz
= &argv
[i
][1];
251 if (!strcmp(psz
, "-help"))
253 else if (!strcmp(psz
, "-version"))
264 pszOutput
= &argv
[i
][2];
267 fprintf(stderr
, "%s: syntax error: only one output file!\n", argv
[0]);
274 fprintf(stderr
, "%s: syntax error: The '-o' argument is missing the filename.\n", argv
[0]);
279 if (pszOutput
[0] == '-' && !pszOutput
[1])
282 pOutput
= fopen(pszOutput
, "w");
285 fprintf(stderr
, "%s: error: Failed to create output file '%s'.\n", argv
[0], pszOutput
);
296 const char *psz
= &argv
[i
][2];
299 if (!strcmp(psz
, "c"))
303 fprintf(stderr
, "%s: error: The '%s' language is not supported.\n", argv
[0], psz
);
316 fprintf(stderr
, "%s: syntax error: only one target!\n", argv
[0]);
319 pszTarget
= &argv
[i
][2];
324 fprintf(stderr
, "%s: syntax error: The '-t' argument is missing the target name.\n", argv
[0]);
339 fprintf(stderr
, "%s: syntax error: The '-e' argument is missing the command.\n", argv
[0]);
376 * The obligatory help and version.
379 usage(stdout
, argv
[0]);
383 printf("kDepPre - kBuild version %d.%d.%d\n"
384 "Copyright (C) 2005-2008 knut st. osmundsen\n",
385 KBUILD_VERSION_MAJOR
, KBUILD_VERSION_MINOR
, KBUILD_VERSION_PATCH
);
392 fprintf(stderr
, "%s: syntax error: Invalid argument '%s'.\n", argv
[0], argv
[i
]);
393 return usage(stderr
, argv
[0]);
398 pInput
= fopen(argv
[i
], "r");
401 fprintf(stderr
, "%s: error: Failed to open input file '%s'.\n", argv
[0], argv
[i
]);
414 fprintf(stderr
, "%s: syntax error: No arguments shall follow the input spec.\n", argv
[0]);
422 * Got all we require?
424 if (!pInput
&& iExec
<= 0)
426 fprintf(stderr
, "%s: syntax error: No input!\n", argv
[0]);
431 fprintf(stderr
, "%s: syntax error: No output!\n", argv
[0]);
436 fprintf(stderr
, "%s: syntax error: No target!\n", argv
[0]);
445 fprintf(stderr
, "%s: -e is not yet implemented!\n", argv
[0]);
452 i
= ParseCPrecompiler(pInput
);
463 * Write the dependecy file.
467 depOptimize(fFixCase
, 0 /* fQuiet */);
468 fprintf(pOutput
, "%s:", pszTarget
);
471 depPrintStubs(pOutput
);
475 * Close the output, delete output on failure.
477 if (!i
&& ferror(pOutput
))
480 fprintf(stderr
, "%s: error: Error writing to '%s'.\n", argv
[0], pszOutput
);
485 if (unlink(pszOutput
))
486 fprintf(stderr
, "%s: warning: failed to remove output file '%s' on failure.\n", argv
[0], pszOutput
);