/* * cpp.c - CPP subprocess * * Written 2002-2004, 2006, 2008 by Werner Almesberger * Copyright 2002, 2003 California Institute of Technology * Copyright 2004, 2006 Werner Almesberger * Copyright 2008 by OpenMoko, Inc. * * 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. */ #include #include #include #include #include #include #include #include #include "cpp.h" const char *cpp_command = CPP; static pid_t cpp_pid; static int cpp_argc = 0; static const char **cpp_argv = NULL; static int real_stdin = -1; void add_cpp_arg(const char *arg) { if (!cpp_argc) cpp_argc = 1; cpp_argv = realloc(cpp_argv,sizeof(const char *)*(cpp_argc+1)); if (!cpp_argv) { perror("realloc"); exit(1); } if (cpp_argc == 1) cpp_argv[0] = cpp_command; if (arg) { arg = strdup(arg); if (!arg) { perror("strdup"); exit(1); } } cpp_argv[cpp_argc++] = arg; } void add_cpp_Wp(const char *arg) { char *tmp = strdup(arg); char *curr,*end; if (!tmp) { perror("strdup"); exit(1); } curr = tmp; do { end = strchr(curr,','); if (end) *end++ = 0; add_cpp_arg(curr); curr = end; } while (end); free(tmp); } static void kill_cpp(void) { if (cpp_pid) (void) kill(cpp_pid,SIGTERM); } static void run_cpp(const char *name,int fd,int close_fd) { char **arg; int fds[2]; if (pipe(fds) < 0) { perror("pipe"); exit(1); } if (name) add_cpp_arg(name); add_cpp_arg(NULL); cpp_pid = fork(); if (cpp_pid < 0) { perror("fork"); exit(1); } if (!cpp_pid) { if (close(fds[0]) < 0) { perror("close"); exit(1); } if (close_fd != -1 && close(close_fd) < 0) { perror("close"); exit(1); } if (fd != -1 && dup2(fd,0) < 0) { perror("dup2"); exit(1); } if (dup2(fds[1],1) < 0) { perror("dup2"); exit(1); } if (execvp(cpp_command,(char **) cpp_argv) < 0) { /* prototype is weird */ perror(cpp_command); exit(1); } /* not reached */ } if (close(fds[1]) < 0) { perror("close"); exit(1); } real_stdin = dup(0); if (real_stdin < 0) { perror("dup"); exit(1); } if (fd != -1 && close(fd) < 0) { perror("close"); exit(1); } if (dup2(fds[0],0) < 0) { perror("dup2"); exit(1); } for (arg = (char **) cpp_argv+1; *arg; arg++) free(*arg); free(cpp_argv); cpp_argv = NULL; cpp_argc = 0; } void run_cpp_on_file(const char *name) { run_cpp(name,name ? -1 : 0,-1); atexit(kill_cpp); } void run_cpp_on_string(const char *str) { int fds[2]; pid_t pid; int left,wrote; if (pipe(fds) < 0) { perror("pipe"); exit(1); } run_cpp(NULL,fds[0],fds[1]); pid = fork(); if (pid < 0) { perror("fork"); exit(1); } if (!pid) { for (left = strlen(str); left; left -= wrote) { wrote = write(fds[1],str,left); if (wrote < 0) break; /* die silently */ str += wrote; } exit(0); } if (close(fds[1]) < 0) { perror("close"); exit(1); } atexit(kill_cpp); } void reap_cpp(void) { int status; cpp_pid = 0; if (waitpid(cpp_pid,&status,0) < 0) { perror("waitpid"); exit(1); } if (!status) { if (dup2(real_stdin,0) < 0) { perror("dup2"); exit(1); } return; } if (WIFEXITED(status)) exit(WEXITSTATUS(status)); if (WIFSIGNALED(status)) fprintf(stderr,"cpp terminated with signal %d\n",WTERMSIG(status)); else fprintf(stderr,"cpp terminated with incomprehensible status %d\n", status); exit(1); }