#include <string.h>
#include <stdarg.h>
#include <errno.h>
+#include <limits.h>
#define _GNU_SOURCE
#include <getopt.h>
#include <unistd.h>
int len; /* amount of data in buffer */
int rd; /* data buffer read offset */
int nxt; /* pushed back data if non-zero */
+ char path[PATH_MAX]; /* current input file */
+ int line; /* current input line number */
} input_t;
typedef struct {
char *output; /* output path */
int gnuld; /* generate GNU ld script */
int verbose; /* verbosity */
+ int dump; /* just dump preprocessed output */
} config_t;
typedef struct {
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
+ fflush(stderr);
exit(1);
}
" -g, --gnu-ld <script> generate GNU ld linker script\n"
" -v, --verbose increase verbosity\n"
" -q, --quiet decrease verbosity\n"
+ " -D, --dump just dump preprocessor output\n"
" -h, --help show this help on usage\n",
argv0);
static void parse_cmdline(config_t *cfg, int argc, char **argv)
{
-# define OPTIONS "P:c:p:o:gvqh"
+# define OPTIONS "P:c:p:o:gvqDh"
struct option options[] = {
{ "preprocessor" , required_argument, NULL, 'P' },
{ "compiler-flags", required_argument, NULL, 'c' },
{ "gnu-ld" , no_argument , NULL, 'g' },
{ "verbose" , no_argument , NULL, 'v' },
{ "quiet" , no_argument , NULL, 'q' },
+ { "dump" , no_argument , NULL, 'D' },
{ "help" , no_argument , NULL, 'h' },
{ NULL, 0, NULL, 0 }
};
verbosity--;
break;
+ case 'D':
+ cfg->dump = 1;
+ break;
+
case 'h':
print_usage(argv[0], -1, "");
exit(0);
*/
if (pipe(fd) != 0)
- fatal_error("failed to create pipe (%d: %s).", errno, strerror(errno));
+ fatal_error("failed to create pipe (%d: %s)\n", errno, strerror(errno));
*pid = fork();
switch (*pid) {
case -1:
- fatal_error("failed to for preprocessor (%d: %s).",
+ fatal_error("failed to fork preprocessor (%d: %s)\n",
errno, strerror(errno));
break;
}
if (dup2(fd[WR], fileno(stdout)) < 0)
- fatal_error("failed to redirect stdout (%d: %s)",
+ fatal_error("failed to redirect stdout (%d: %s)\n",
errno, strerror(errno));
if (execv("/bin/sh", argv) != 0)
- fatal_error("failed to exec command '%s' (%d: %s)", cmd,
+ fatal_error("failed to exec command '%s' (%d: %s)\n", cmd,
errno, strerror(errno));
break;
}
-static char *input_parse_linemarker(input_t *in, char *buf, size_t size)
+static int input_parse_linemarker(input_t *in, char *buf, size_t size)
{
char ch;
int i;
- while((ch = input_read(in)) != '"' && ch != '\n' && ch)
+ while ((ch = input_read(in)) == ' ' || ch == '\t')
;
- if (ch != '"')
- return NULL;
+ verbose_message(2, "**** ch = '%c' (%u) *** \n", ch, (unsigned int)ch);
+
+ if ('0' <= ch && ch <= '9') {
+ while ((ch = input_read(in)) != '"' && ch)
+ ;
+
+ if (!ch) {
+ fatal_error("missing '\"' from preprocessor linemarker '#'\n");
+ return -1;
+ }
- for (i = 0; i < (int)size - 1; i++) {
- buf[i] = ch = input_read(in);
+ for (i = 0; i < (int)size - 1; i++) {
+ buf[i] = ch = input_read(in);
- if (ch == '"') {
- buf[i] = '\0';
+ if (ch == '"') {
+ buf[i] = '\0';
- while ((ch = input_read(in)) != '\n' && ch)
- ;
+ while ((ch = input_read(in)) != '\n' && ch)
+ ;
- return buf;
+ return 0;
+ }
}
}
- return NULL;
+ /* assume a #pragma, or something else, just consume it */
+ while ((ch = input_read(in)) != '\n' && ch)
+ ;
+ *buf = '\0';
+
+ return 0;
}
/* extract path name from preprocessor line-markers */
case '#':
- v = input_parse_linemarker(in, path, sizeof(path));
- if (v != NULL) {
- tokens[n].type = TOKEN_LINEMARKER;
- tokens[n].value = ringbuf_save(rb, v, -1);
- if (n == 0)
- return n + 1;
- else
- return -1;
+ verbose_message(2, "input buffer now [%*.*s]\n",
+ in->len - in->rd, in->len - in->rd,
+ in->buf + in->rd);
+ if (input_parse_linemarker(in, path, sizeof(path)) < 0)
+ return -1;
+
+ if (!same_file(in->path, path)) {
+ verbose_message(2, "input switched to file '%s'...\n", path);
+ strcpy(in->path, path);
}
break;
case '{':
case '(':
case '[':
- if (input_discard_block(in, ch) != 0)
+ if (input_discard_block(in, ch) != 0) {
+ fatal_error("failed to discard input block\n");
return -1;
+ }
else {
/* filter out __attribute__ ((.*)) token pairs */
if (ch == '(' && n > 0 &&
tokens[n].value = v;
n++;
}
- else
+ else {
+ fatal_error("failed to collect word token\n");
return -1;
+ }
break;
case '=':
}
errno = EOVERFLOW;
+ fatal_error("input buffer overflow\n");
return -1;
}
return;
}
- fatal_error("failed to save symbol '%s'", sym);
+ fatal_error("failed to save symbol '%s'\n", sym);
}
- fatal_error("failed to allocate new symbol table entry");
+ fatal_error("failed to allocate new symbol table entry\n");
}
foreign = 0;
while ((ntoken = collect_tokens(&in, &rb, tokens, MAX_TOKENS)) > 0) {
- if (tokens[0].type == TOKEN_LINEMARKER) {
- foreign = !same_file(path, tokens[0].value);
-
- verbose_message(2, "input switched to %s file '%s'...\n",
- foreign ? "foreign" : "input", tokens[0].value);
-
- continue;
- }
-
+ foreign = !same_file(path, in.path);
if (foreign) {
verbose_message(2, "ignoring token stream from foreign file...\n");
continue;
}
}
+ {
+ ssize_t n;
+ char buf[8192];
+
+ while ((n = read(fd, buf, sizeof(buf))) > 0) {
+ verbose_message(2, "%d unprocessed bytes of input from '%s':", n,
+ path);
+ verbose_message(4, "[%*.*s]", (int)n, (int)n, buf);
+ }
+ }
+
+ close(fd);
+ waitpid(pp_pid, &pp_status, 0);
+
+ if (WIFEXITED(pp_status) && WEXITSTATUS(pp_status) != 0)
+ fatal_error("preprocessing of '%s' failed (%d)\n", path,
+ WEXITSTATUS(pp_status));
+}
+
+
+static void dump_preprocessed(const char *preproc, const char *path,
+ const char *cflags)
+{
+ pid_t pp_pid;
+ int pp_status, fd;
+ ssize_t n;
+ char buf[8192];
+
+ fd = preprocess_file(preproc, path, cflags, &pp_pid);
+
+ while ((n = read(fd, buf, sizeof(buf))) > 0)
+ printf("%*.*s", (int)n, (int)n, buf);
+
+ printf("\n");
+
close(fd);
waitpid(pp_pid, &pp_status, 0);
if (WIFEXITED(pp_status) && WEXITSTATUS(pp_status) != 0)
- fatal_error("preprocessing of '%s' failed\n", path);
+ fatal_error("preprocessing of '%s' failed (%d)", path,
+ WEXITSTATUS(pp_status));
}
verbose_message(1, "using preprocessor '%s', cflags '%s'\n", cfg.preproc,
cfg.cflags ? cfg.cflags : "");
+
+ if (cfg.dump) {
+ for (i = 0; i < cfg.nfile; i++)
+ dump_preprocessed(cfg.preproc, cfg.files[i], cfg.cflags);
+
+ exit(0);
+ }
+
if (cfg.pattern != NULL) {
err = regcomp(&rebuf, cfg.pattern, REG_EXTENDED);
out = fopen(cfg.output, "w");
if (out == NULL)
- fatal_error("failed to open '%s' (%d: %s)", cfg.output,
+ fatal_error("failed to open '%s' (%d: %s)\n", cfg.output,
errno, strerror(errno));
}
else