diff -ruN distcc.orig/Makefile.in distcc/Makefile.in --- distcc.orig/Makefile.in 2002-11-11 00:26:38.000000000 +0100 +++ distcc/Makefile.in 2002-11-10 22:41:32.000000000 +0100 @@ -116,7 +116,7 @@ common_obj = src/trace.o src/util.o src/io.o src/exec.o src/arg.o \ src/rpc.o src/tempfile.o src/bulk.o src/help.o src/filename.o \ -src/lock.o src/where.o src/hosts.o +src/lock.o src/where.o src/hosts.o src/postproc.o distcc_obj = src/distcc.o src/clinet.o src/strip.o src/implicit.o $(common_obj) @@ -135,12 +135,12 @@ src/h_exten.c src/h_hosts.c src/h_issource.c src/h_scanargs.c \ src/help.c src/hosts.c src/io.c src/rpc.c src/serve.c src/srvnet.c \ src/tempfile.c src/trace.c src/util.c src/where.c src/zip.c src/strip.c \ -src/h_strip.c src/implicit.c src/lock.c +src/h_strip.c src/implicit.c src/lock.c src/postproc.c HEADERS = src/clinet.h src/distcc.h src/exitcode.h src/hosts.h \ src/io.h src/tempfile.h src/strip.h src/implicit.h \ src/opt.h src/rpc.h src/trace.h src/util.h src/bulk.h \ - src/exec.h src/lock.h src/where.h + src/exec.h src/lock.h src/where.h src/postproc.h MEN = man/distcc.1 man/distccd.1 diff -ruN distcc.orig/src/distcc.c distcc/src/distcc.c --- distcc.orig/src/distcc.c 2002-11-11 00:26:38.000000000 +0100 +++ distcc/src/distcc.c 2002-11-10 23:14:02.000000000 +0100 @@ -60,6 +60,7 @@ #include "exec.h" #include "where.h" #include "lock.h" +#include "postproc.h" /* for trace.c */ @@ -173,6 +174,7 @@ const char *cpp_fname) { long stime_usec, utime_usec; + char *pp_fname; int ret; if ((ret = dcc_x_req_header(net_fd)) @@ -203,7 +205,10 @@ return EXIT_IO_ERROR; } - if ((ret = dcc_x_file(net_fd, cpp_fname, "DOTI", NULL))) + if ((ret = dcc_post_process (cpp_fname, &pp_fname) != 0)) + return ret; + + if ((ret = dcc_x_file(net_fd, pp_fname, "DOTI", NULL))) return ret; rs_trace("client finished sending request to server"); @@ -450,6 +455,9 @@ if ((ret = dcc_strip_local_args(argv, &argv_stripped))) goto fallback; + if ((ret = dcc_post_process_set_source (input_fname))) + goto fallback; + if ((ret = dcc_compile_remote(argv_stripped, cpp_fname, output_fname, cpp_pid, host, status)) != 0) { /* Returns zero if we successfully ran the compiler, even if diff -ruN distcc.orig/src/postproc.c distcc/src/postproc.c --- distcc.orig/src/postproc.c 1970-01-01 01:00:00.000000000 +0100 +++ distcc/src/postproc.c 2002-11-10 23:57:17.000000000 +0100 @@ -0,0 +1,360 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * $Header: $ + * + * Copyright (C) 2002 by Tim Janik + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "distcc.h" +#include "trace.h" +#include "assert.h" +#include "tempfile.h" +#include "postproc.h" + + +/* buffered input */ +#define BUFFER_SIZE 4000 +typedef struct { + int fd; + char *bound; + char buffer[BUFFER_SIZE + 1]; + char *text; +} PPInput; + +static inline int peek_char (PPInput *inp) +{ + if (inp->text < inp->bound) + return *inp->text; + else if (inp->fd >= 0) { + int count; + char *buffer = inp->buffer; + do + count = read (inp->fd, buffer, BUFFER_SIZE); + while (count == -1 && (errno == EINTR || errno == EAGAIN)); + if (count < 1) { + inp->fd = -1; + return EOF; + } else { + inp->text = buffer; + inp->bound = buffer + count; + return *inp->text; + } + } else + return EOF; +} + +static inline int get_char (PPInput *inp) +{ + int c = peek_char (inp); + if (c != EOF) + inp->text++; + return c; +} + +static void unget_char (PPInput *inp, + char c) +{ + /* we only allow unget backs after a non-EOF get_char() */ + assert (inp->text > inp->buffer); + inp->text--; + inp->text[0] = c; +} + + +/* buffered output */ +typedef struct { + int fd; + char *p; + char buffer[BUFFER_SIZE + 1]; +} PPOutput; + +static void flush_output (PPOutput *out) +{ + int count, n = out->p - out->buffer; + errno = 0; + if (n) { + do + count = write (out->fd, out->buffer, n); + while (count == -1 && (errno == EINTR || errno == EAGAIN)); + if (count != n) + rs_log_error ("failed to write %u bytes: %s", n, strerror (errno)); + } + out->p = out->buffer; +} + +static inline void write_char (PPOutput *out, + int ch) +{ + *(out->p++) = ch; + if (out->p - out->buffer >= BUFFER_SIZE) + flush_output (out); +} + + +/* source file path name */ +static char *pp_source_name = NULL; + +/* rarely triggered. post processed output usually doesn't + * contain comments (an exception would be gcc -E -C) + */ +static void post_process_comment_rest (PPInput *inp, + PPOutput *out, + int term /* must be '\n' or '/' */) +{ + int seenast = FALSE; + /* read up to \n or * followed by / */ + while (1) { + int c = get_char (inp); + switch (c) { + case EOF: + return; /* broken input */ + case '*': + write_char (out, c); + seenast = TRUE; + break; + case '/': + write_char (out, c); + if (seenast && term == c) + return; + break; + case '\n': + write_char (out, c); + if (term == c) + return; + seenast = FALSE; + break; + default: + write_char (out, c); + seenast = FALSE; + break; + } + } +} + +/* process the rest of a string, after the initial '\'' or '\"' has been read */ +static inline void post_process_string_rest (PPInput *inp, + PPOutput *out, + int term /* must be '\"' or '\'' */) +{ + int escape = FALSE; + while (1) { + int c = get_char (inp); + switch (c) { + case EOF: + return; /* broken input */ + case '\\': + write_char (out, c); + escape = !escape; + break; + case '\"': + case '\'': + write_char (out, c); + if (c == term && !escape) + return; + escape = FALSE; + break; + default: + write_char (out, c); + escape = FALSE; + break; + } + } +} + +/* handle the case where a line starts with '#' which indicates + * preprocessor instructions. the ones to care about here are + * '# 3 "files/foo.c"', i.e. source file references. those are + * patched up to only contain absolute pathnames. + */ +static int post_process_hashcross (PPInput *inp, + PPOutput *out, + const char *pathprefix) +{ + int c; + /* check whether here comes a #-line directive, hash already parsed. + * we need to return the last char processed for our caller to update state. + */ + + /* read up spaces */ + c = get_char (inp); + while (c == ' ' || c == '\t') { + write_char (out, c); + c = get_char (inp); + } + /* read up digits */ + while (c >= '0' && c <= '9') { + write_char (out, c); + c = get_char (inp); + } + /* read up spaces */ + while (c == ' ' || c == '\t') { + write_char (out, c); + c = get_char (inp); + } + /* read up double quote */ + if (c != '\"') + goto abort; + write_char (out, c); + c = get_char (inp); + /* here it comes: if c is a slash, we got an absolute + * pathname. otherwise we insert our prefix and handle + * the rest as an ordinary string. + */ + if (c != '/') { + const char *p = pathprefix; + while (*p) + write_char (out, *p++); + } + unget_char (inp, c); + post_process_string_rest (inp, out, '\"'); + return '\"'; + + abort: + if (c != EOF) + write_char (out, c); + return c; +} + +static void post_process (PPInput *inp, + PPOutput *out, + const char *pathprefix) +{ + int seennewline = TRUE; + int lastc, c = '\n'; + while (1) { + lastc = c; + c = get_char (inp); + switch (c) { + case EOF: + return; + case '\n': + write_char (out, c); + seennewline = TRUE; + break; + case '#': + write_char (out, c); + if (seennewline) { + c = post_process_hashcross (inp, out, pathprefix); + if (c == EOF) + return; + } + seennewline = c == '\n'; + break; + case ' ': + case '\t': + write_char (out, c); + /* preserve seennewline */ + break; + case '*': + write_char (out, c); + if (lastc == '/') { + post_process_comment_rest (inp, out, '/'); + c = '/'; + } + seennewline = FALSE; + break; + case '\"': case '\'': + write_char (out, c); + post_process_string_rest (inp, out, c); + seennewline = FALSE; + break; + default: + write_char (out, c); + seennewline = FALSE; + break; + } + } +} + +int dcc_post_process (const char *in_fname, + char **out_fname) +{ + char *p, *dirname; + PPOutput out = { -1, 0, { 0, } }; + PPInput inp = { -1, 0, { 0, }, 0 }; + + *out_fname = dcc_make_tmpnam ("ppline", ".i"); + + inp.fd = open (in_fname, O_RDONLY); + if (inp.fd < 0) { + rs_log_error ("opening input \"%s\" failed: %s", in_fname, strerror (errno)); + return -1; + } + + out.p = out.buffer; + out.fd = open (*out_fname, O_CREAT | O_TRUNC | O_WRONLY, 0644); + if (out.fd < 0) { + rs_log_error ("opening output \"%s\" failed: %s", *out_fname, strerror (errno)); + close (inp.fd); + return -1; + } + + if (!pp_source_name) + pp_source_name = strdup (""); + + /* figure slash terminated directory name */ + if (pp_source_name[0] == '/') { + dirname = strdup (pp_source_name); + } else { + int dl, sl = strlen (pp_source_name); + char cdirbuf[8192]; + char *cdir = getcwd (cdirbuf, sizeof (cdirbuf)); + if (!cdir) + return -1; + dl = strlen (cdir); + dirname = malloc (dl + 1 + sl + 1); + strcpy (dirname, cdir); + dirname[dl++] = '/'; + strcpy (dirname + dl, pp_source_name); + } + p = strrchr (dirname, '/'); + if (p) + p[1] = 0; + + post_process (&inp, &out, dirname); + flush_output (&out); + free (dirname); + + close (inp.fd); + if (close (out.fd)) { + rs_log_error ("flushing output %s failed: %s\n", *out_fname, strerror (errno)); + return -1; + } + return 0; +} + +int dcc_post_process_set_source (const char *source_name) +{ + if (pp_source_name) + free (pp_source_name); + pp_source_name = source_name ? strdup (source_name) : NULL; + return 0; +} diff -ruN distcc.orig/src/postproc.h distcc/src/postproc.h --- distcc.orig/src/postproc.h 1970-01-01 01:00:00.000000000 +0100 +++ distcc/src/postproc.h 2002-11-10 22:44:33.000000000 +0100 @@ -0,0 +1,28 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * $Header: $ + * + * Copyright (C) 2002 by Tim Janik + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +/* postproc.c */ +int dcc_post_process_set_source (const char *source_name); +int dcc_post_process (const char *in_fname, + char **out_fname); +