/* * On some NetBSD versions, throws errors if included * without first including various other files, usually . * * In my opinion this simply means those include files are buggy and * need to be fixed, and that's what I've done on my own systems. In * most cases, on other systems, I use include-shadow to shadow such * broken files with workarounds. But this is one of the very first * programs we try to build when bringing up /local on a new system, * making it inconvenient to do that. So we hold our nose and include * as a bug workaround. */ #include #include #include #include #include #include #include #include #include #ifndef __linux__ #include /* bug workaround - see file header comment */ #include #endif #ifdef __linux__ #include /* bug workaround - see file header comment */ #endif extern const char *__progname; static const char ccpgm[] = "/usr/bin/cc"; static const char *extra[] = { "-I&($LOCALROOT=/local)/include-shadow", "-I&($LOCALROOT=/local)/include", "-L&($LOCALROOT=/local)/lib", #ifndef __linux__ "&(Mnext68k)-m68040", #endif "-D_FILE_OFFSET_BITS=64", /* grr, Linux */ "-Wl,-rpath,&($LOCALROOT=/local)/lib" }; static const char *subst[][2] = { { "-V", "-v" } }; static const char *envvar[] = { "CCWRAPPER_OPTS", 0 }; static const char *debug_env = "CCWRAPPER_DEBUG"; static const char *flags_env = "CCWRAPPER_FLAGS"; static int nextra = sizeof(extra) / sizeof(extra[0]); static int nsubst = sizeof(subst) / sizeof(subst[0]); static const char **newav; static char **envav; static int nenv; static int debugging; static int env_err = 0; static int no_massage_output = 0; static unsigned char *ccline; static int ccla; static int ccll; static char and_fail; #define NSTART 1 #define NINC 1 static void env_args(void) { int i; int have; int used; char *ep; char *cp; char *dp; char backslash; envav = 0; ep = 0; for (i=0;envvar[i];i++) { ep = getenv(envvar[i]); if (ep) break; if (debugging) { printf("no `%s' in environment\n",envvar[i]); } } if (ep == 0) { static char *zblk[] = { 0 }; envav = zblk; nenv = 0; if (debugging) { printf("no options variable found in environment\n"); } return; } if (debugging) { printf("getenv(\"%s\") -> `%s'\n",envvar[i],ep); } have = NSTART; envav = (char **) malloc((NSTART+1)*sizeof(char *)); used = 0; backslash = 0; cp = ep; while (*cp) { if (*cp == ' ') { cp ++; continue; } if (used >= have) { have += NINC; envav = (char **) realloc((char *)envav,(have+1)*sizeof(char *)); } envav[used++] = cp; if (debugging) { printf("new arg at `%s'\n",cp); } dp = cp; while (*cp && (backslash || (*cp != ' '))) { if ((*cp == '\\') && !backslash) { cp ++; backslash = 1; continue; } *dp++ = *cp++; backslash = 0; } if (*cp) { *dp++ = '\0'; cp ++; } else { *dp = '\0'; } if (debugging) { printf("arg finished as `%s'\n",envav[used-1]); } } nenv = used; envav[used] = '\0'; if (debugging) { printf("%d from environment\n",nenv); } } #undef NSTART #undef NINC static void env_flag(const char *f, int len) { switch (len) { case 7: if (! bcmp(f,"massage",len)) { no_massage_output = 0; return; } break; case 10: if (! bcmp(f,"no-massage",len)) { no_massage_output = 1; return; } break; } fprintf(stderr,"%s: unrecognized environment flag `%.*s'\n",__progname,len,f); env_err = 1; } static void env_flags(void) { const char *s; int i0; int i; s = getenv(flags_env); if (! s) return; i0 = -1; for (i=0;s[i];i++) { if (s[i] == ' ') { if (i0 >= 0) { env_flag(s+i0,i-i0); i0 = -1; } } else { if (i0 < 0) i0 = i; } } if (i0 >= 0) env_flag(s+i0,i-i0); } static void readenv(void) { env_args(); env_flags(); } static int linecontains(const char *str) { const char *lp; const char *sp; sp = str; lp = ccline; while (1) { if (!*sp) return(1); if (!*lp) return(0); if (*sp == *lp) { sp ++; } else if (sp != str) { lp -= sp - str; sp = str; } lp ++; } } static int linebegins(const char *str) { return(!bcmp(ccline,str,strlen(str))); } static char *and_envar(const char **sp) { const char *s; const char *s0; int l; char *t; char *e; s = *sp; s0 = ++s; while (*s && (*s != ')') && (*s != '=')) s ++; if (! *s) return(0); l = s - s0; t = malloc(l+1); bcopy(s0,t,l); t[l] = '\0'; e = getenv(t); free(t); if (e) { while (*s && (*s != ')')) s ++; if (! *s) return(0); t = malloc(strlen(e)+1); strcpy(t,e); } else { if (*s == '=') { s0 = ++s; while (*s && (*s != ')')) s ++; if (! *s) return(0); l = s - s0; t = malloc(l+1); bcopy(s0,t,l); t[l] = '\0'; } else { t = malloc(1); t[0] = '\0'; } } *sp = s + 1; return(t); } static char *and_home(const char **sp) { const char *s; const char *s0; int l; char *t; struct passwd *pw; s = *sp; s0 = ++s; while (*s && (*s != ')')) s ++; if (! *s) return(0); l = s - s0; t = malloc(l+1); bcopy(s0,t,l); t[l] = '\0'; pw = getpwnam(t); free(t); if (pw == 0) return(0); l = strlen(pw->pw_dir); t = malloc(l+1); strcpy(t,pw->pw_dir); *sp = s + 1; return(t); } #ifndef __linux__ static char *and_machine(const char **sp) { const char *s; const char *s0; char arch[64]; size_t archlen; int mib[2]; s = *sp; s0 = ++s; while (*s && (*s != ')')) s ++; if (! *s) return(0); mib[0] = CTL_HW; mib[1] = HW_MACHINE; archlen = sizeof(arch) - 1; if (sysctl(&mib[0],2,&arch[0],&archlen,0,0) < 0) return(0); if (archlen >= sizeof(arch)) return(0); while ((archlen > 0) && (arch[archlen-1] == '\0')) archlen --; if (archlen != s-s0) return(&and_fail); if (bcmp(&arch[0],s0,archlen)) return(&and_fail); *sp = ""; return(strdup(s+1)); } #endif static char *and_result(const char **sp) { switch (**sp) { case '$': return(and_envar(sp)); break; case '~': return(and_home(sp)); break; #ifndef __linux__ case 'M': return(and_machine(sp)); break; #endif } return(0); } static const char *and_process(const char *s) { char *rv; int rvl; int rvh; char *app; char *app0; char c; if (! index(s,'&')) return(s); if (debugging) printf("and_process: initial %s\n",s); rv = malloc(1); rvl = 0; rvh = 0; app = 0; while (1) { if (app) { if (*app) { c = *app++; } else { free(app0); app = 0; continue; } } else { switch (*s) { case '\0': rv[rvl] = '\0'; if (debugging) printf("and_process: returning %s\n",rv); return(rv); break; case '&': switch (s[1]) { case '\0': c = '&'; s ++; break; case '(': s += 2; app0 = app = and_result(&s); if (app == &and_fail) { free(rv); return(0); } continue; break; default: s += 2; c = s[-1]; break; } break; default: c = *s++; break; } } if (rvl >= rvh) rv = realloc(rv,(rvh=rvl+16)+1); rv[rvl++] = c; } } static void add_ccline(int ch) { if (ccll >= ccla) ccline = realloc(ccline,ccla=ccll+32); ccline[ccll++] = ch; if ((ccll >= 3) && (ccline[ccll-3] == 0xe2)) { if ((ccline[ccll-2] == 0x80) && (ccline[ccll-1] == 0x98)) { ccll -= 2; ccline[ccll-1] = '`'; } else if ((ccline[ccll-2] == 0x80) && (ccline[ccll-1] == 0x99)) { ccll -= 2; ccline[ccll-1] = '\''; } } } static int get_ccline(void) { int c; ccll = 0; while (1) { c = getchar(); switch (c) { case EOF: if (ccll == 0) return(0); /* fall through */ case '\n': add_ccline('\0'); ccll --; return(1); break; } add_ccline(c); } } int main(int, char **); int main(int ac, char **av) { const char **np; int i; int j; const char *cp; int p[2]; int skipping; #define SKIP_DEFDIR 1 #define SKIP_SEARCH 2 debugging = !!getenv(debug_env); readenv(); if (env_err) exit(1); newav = malloc((ac+nenv+nextra+1)*sizeof(char *)); np = newav; for (i=0;i 0) && (ccline[ccll-1] == '\n')) ccline[--ccll] = '\0'; if (debugging) { fprintf(stderr,"sk=%d line=%s\n",skipping,ccline); } if (no_massage_output) { fprintf(stderr,"%s\n",ccline); continue; } if ( linebegins("Using built-in specs.") || linebegins("Target: ") || linebegins("Compiler executable checksum: ") || linebegins("gcc version ") || linebegins("GNU CPP version ") || linebegins("Configured with: ") || linebegins("Thread model: ") || linebegins("gcc version ") || linebegins("GNU C ") || linebegins("GNU assembler version ") || linebegins("cc: file path prefix ") || linebegins("gcc: file path prefix ") || linebegins("Reading specs from ") || linebegins("Using builtin specs") || linebegins("default target switches ") || linebegins("\tcompiled by ") || linebegins("GGC heuristics: ") || linebegins("ignoring nonexistent directory ") || linebegins("cc1: warnings being treated as errors") || linebegins("COLLECT_GCC_OPTIONS=") || linebegins("COMPILER_PATH=") || linebegins("LIBRARY_PATH=") || linecontains("(Each undeclared identifier is reported only once") || linecontains("for each function it appears in.)") || linecontains("note: each undeclared identifier is reported only once for each function it appears in") || linecontains("its scope is only this definition or declaration") || linecontains("which is probably not what you want.") || linecontains("linker input file unused since linking not done") || linecontains("linker input file unused because linking not done") ) { continue; } else if (linebegins("The following default directories have been omitted from the search path:")) { skipping |= SKIP_DEFDIR; } else if (linebegins("End of omitted list.")) { skipping &= ~SKIP_DEFDIR; } else if (linecontains("search starts here")) { skipping |= SKIP_SEARCH; continue; } else if (linebegins("End of search list.")) { skipping &= ~SKIP_SEARCH; continue; } else if (skipping) { continue; } else if ( (ccline[0] == ' ') && ( (ccline[1] == '/') || ( (ccline[1] == 'a') && (ccline[2] == 's') && (ccline[3] == ' ') ) || ( (ccline[1] == 'l') && (ccline[2] == 'd') && (ccline[3] == ' ') ) ) ) { fprintf(stderr,"\n",ccline+1); } else { unsigned char *colon; unsigned char *cp; colon = index(ccline,':'); cp = index(ccline,' '); if (colon && (!cp || (colon < cp)) && isdigit(colon[1])) { for (cp=colon+1;*cp&&isdigit(*cp);cp++) ; if (*cp == ':') { fprintf(stderr,"\"%.*s\", line %.*s%s\n",(int)(colon-ccline),ccline,(int)(cp-(colon+1)),colon+1,cp); ccline[0] = '\0'; } } if (ccline[0]) fprintf(stderr,"%s\n",ccline); } /* Should never need to fflush stderr, but apparently some stdios are broken enough to not default it to unbuffered, and it's cheap enough on non-broken stdios to just always do it. */ fflush(stderr); } while (1) { int w; i = wait(&w); if (i < 0) { if (errno == EINTR) continue; perror("wait"); if (errno == ECHILD) { exit(1); } } if (WIFSIGNALED(w)) { if (WCOREDUMP(w)) { fprintf(stderr,"%s dumped core\n",ccpgm); exit(1); } signal(WTERMSIG(w),SIG_DFL); kill(getpid(),WTERMSIG(w)); exit(1); } else { exit(WEXITSTATUS(w)); } } }