3 * kDepPre - Dependency Generator using Precompiler output.
7 * Copyright (c) 2005-2010 knut st. osmundsen <bird-kBuild-spamx@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 pThis Pointer to the 'dep' instance.
59 * @param pInput Input stream. (probably not seekable)
61 static int ParseCPrecompiler(PDEPGLOBALS pThis
, FILE *pInput
)
69 } enmMode
= C_DISCOVER
;
79 * Start of line, need to look for '#[[:space]]*line <num> "file"' and '# <num> "file"'.
83 while ((ch
= FGETC(pInput
)) != EOF
)
89 while ((ch
= FGETC(pInput
)) != EOF
)
93 /* check for "line" */
96 if ( (ch
= FGETC(pInput
)) == 'i'
97 && (ch
= FGETC(pInput
)) == 'n'
98 && (ch
= FGETC(pInput
)) == 'e')
104 while ((ch
= FGETC(pInput
)) != EOF
)
116 if (ch
>= '0' && ch
<= '9')
118 /* skip the number following spaces */
119 while ((ch
= FGETC(pInput
)) != EOF
)
124 while ((ch
= FGETC(pInput
)) != EOF
)
127 /* quoted filename */
130 enmMode
= C_PARSE_FILENAME
;
136 enmMode
= C_SKIP_LINE
;
140 * Skip past the end of the current line.
148 } while ((ch
= FGETC(pInput
)) != EOF
);
149 enmMode
= C_DISCOVER
;
153 * Parse the filename.
155 case C_PARSE_FILENAME
:
157 /* retreive and unescape the filename. */
158 char *psz
= &szBuf
[0];
159 while ( (ch
= FGETC(pInput
)) != EOF
160 && psz
< &szBuf
[sizeof(szBuf
) - 1])
167 case '\\': ch
= '/'; break;
168 case 't': ch
= '\t'; break;
169 case 'r': ch
= '\r'; break;
170 case 'n': ch
= '\n'; break;
171 case 'b': ch
= '\b'; break;
173 fprintf(stderr
, "warning: unknown escape char '%c'\n", ch
);
177 *psz
++ = ch
== '\\' ? '/' : ch
;
183 size_t cchFilename
= psz
- &szBuf
[0];
185 /* compare with current dep, add & switch on mismatch. */
187 || pDep
->cchFilename
!= cchFilename
188 || memcmp(pDep
->szFilename
, szBuf
, cchFilename
))
189 pDep
= depAdd(pThis
, szBuf
, cchFilename
);
193 enmMode
= C_SKIP_LINE
;
203 enmMode
= C_DISCOVER
;
214 static int usage(FILE *pOut
, const char *argv0
)
217 "usage: %s [-l=c] -o <output> -t <target> [-f] [-s] < - | <filename> | -e <cmdline> >\n"
219 " or: %s --version\n",
220 argv0
, argv0
, argv0
);
225 int main(int argc
, char *argv
[])
232 FILE *pOutput
= NULL
;
233 const char *pszOutput
= NULL
;
235 const char *pszTarget
= NULL
;
238 /* Argument parsing. */
239 int fInput
= 0; /* set when we've found input argument. */
245 return usage(stderr
, argv
[0]);
246 for (i
= 1; i
< argc
; i
++)
248 if (argv
[i
][0] == '-')
250 const char *psz
= &argv
[i
][1];
253 if (!strcmp(psz
, "-help"))
255 else if (!strcmp(psz
, "-version"))
266 pszOutput
= &argv
[i
][2];
269 fprintf(stderr
, "%s: syntax error: only one output file!\n", argv
[0]);
276 fprintf(stderr
, "%s: syntax error: The '-o' argument is missing the filename.\n", argv
[0]);
281 if (pszOutput
[0] == '-' && !pszOutput
[1])
284 pOutput
= fopen(pszOutput
, "w");
287 fprintf(stderr
, "%s: error: Failed to create output file '%s'.\n", argv
[0], pszOutput
);
298 const char *pszValue
= &argv
[i
][2];
299 if (*pszValue
== '=')
301 if (!strcmp(pszValue
, "c"))
305 fprintf(stderr
, "%s: error: The '%s' language is not supported.\n", argv
[0], pszValue
);
318 fprintf(stderr
, "%s: syntax error: only one target!\n", argv
[0]);
321 pszTarget
= &argv
[i
][2];
326 fprintf(stderr
, "%s: syntax error: The '-t' argument is missing the target name.\n", argv
[0]);
341 fprintf(stderr
, "%s: syntax error: The '-e' argument is missing the command.\n", argv
[0]);
378 * The obligatory help and version.
381 usage(stdout
, argv
[0]);
385 printf("kDepPre - kBuild version %d.%d.%d\n"
386 "Copyright (C) 2005-2008 knut st. osmundsen\n",
387 KBUILD_VERSION_MAJOR
, KBUILD_VERSION_MINOR
, KBUILD_VERSION_PATCH
);
394 fprintf(stderr
, "%s: syntax error: Invalid argument '%s'.\n", argv
[0], argv
[i
]);
395 return usage(stderr
, argv
[0]);
400 pInput
= fopen(argv
[i
], "r");
403 fprintf(stderr
, "%s: error: Failed to open input file '%s'.\n", argv
[0], argv
[i
]);
416 fprintf(stderr
, "%s: syntax error: No arguments shall follow the input spec.\n", argv
[0]);
424 * Got all we require?
426 if (!pInput
&& iExec
<= 0)
428 fprintf(stderr
, "%s: syntax error: No input!\n", argv
[0]);
433 fprintf(stderr
, "%s: syntax error: No output!\n", argv
[0]);
438 fprintf(stderr
, "%s: syntax error: No target!\n", argv
[0]);
447 fprintf(stderr
, "%s: -e is not yet implemented!\n", argv
[0]);
455 i
= ParseCPrecompiler(&This
, pInput
);
466 * Write the dependecy file.
470 depOptimize(&This
, fFixCase
, 0 /* fQuiet */, NULL
/*pszIgnoredExt*/);
471 depPrintTargetWithDeps(&This
, pOutput
, pszTarget
, 1 /*fEscapeTarget*/);
473 depPrintStubs(&This
, pOutput
);
477 * Close the output, delete output on failure.
479 if (!i
&& ferror(pOutput
))
482 fprintf(stderr
, "%s: error: Error writing to '%s'.\n", argv
[0], pszOutput
);
487 if (unlink(pszOutput
))
488 fprintf(stderr
, "%s: warning: failed to remove output file '%s' on failure.\n", argv
[0], pszOutput
);