/* cpp.c cpp preprocessing support Copyright (C) 2002 Bill Currie Author: Bill Currie Date: 2002/06/04 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: Free Software Foundation, Inc. 59 Temple Place - Suite 330 Boston, MA 02111-1307, USA */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef HAVE_SYS_WAIT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_PROCESS_H # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_IO_H #include #endif #include #include #include "QF/dstring.h" #include "cpp.h" #include "options.h" typedef struct cpp_arg_s { struct cpp_arg_s *next; const char *arg; } cpp_arg_t; cpp_arg_t *cpp_arg_list; cpp_arg_t **cpp_arg_tail = &cpp_arg_list; cpp_arg_t *cpp_def_list; cpp_arg_t **cpp_def_tail = &cpp_def_list; const char **cpp_argv; const char *cpp_name = CPP_NAME; static int cpp_argc = 0; dstring_t *tempname; static void add_cpp_arg (const char *arg) { cpp_arg_t *cpp_arg = malloc (sizeof (cpp_arg_t)); cpp_arg->next = 0; cpp_arg->arg = arg; *cpp_arg_tail = cpp_arg; cpp_arg_tail = &(*cpp_arg_tail)->next; cpp_argc++; } void add_cpp_def (const char *arg) { cpp_arg_t *cpp_def = malloc (sizeof (cpp_arg_t)); cpp_def->next = 0; cpp_def->arg = arg; *cpp_def_tail = cpp_def; cpp_def_tail = &(*cpp_def_tail)->next; cpp_argc++; } void parse_cpp_name (void) { char *n; if (!cpp_name) return; n = strdup (cpp_name); while (*n) { while (*n && *n == ' ') n++; add_cpp_arg (n); while (*n && *n != ' ') n++; if (*n) *n++ = 0; } } static void build_cpp_args (const char *in_name, const char *out_name) { cpp_arg_t *cpp_arg; cpp_arg_t *cpp_def; const char **arg; if (cpp_argv) free (cpp_argv); cpp_argv = (const char **)malloc ((cpp_argc + 1) * sizeof (char**)); for (arg = cpp_argv, cpp_arg = cpp_arg_list; cpp_arg; cpp_arg = cpp_arg->next) { if (!strcmp (cpp_arg->arg, "%d")) { for (cpp_def = cpp_def_list; cpp_def; cpp_def = cpp_def->next) *arg++ = cpp_def->arg; } else if (!strcmp (cpp_arg->arg, "%i")) { *arg++ = in_name; } else if (!strcmp (cpp_arg->arg, "%o")) { if (!options.preprocess_only) { *arg++ = out_name; } } else { if (!options.preprocess_only || strcmp (cpp_arg->arg, "-o") != 0) *arg++ = cpp_arg->arg; } } *arg = 0; //for (arg = cpp_argv; *arg; arg++) // printf ("%s ", *arg); //puts (""); } //============================================================================ void intermediate_file (dstring_t *ifile, const char *filename, const char *ext, int local) { if (options.save_temps) { char *basename = strdup (filename); char *temp; temp = strrchr (basename, '/'); if (!temp) temp = basename; temp = strrchr (temp, '.'); if (temp) *temp = '\0'; // ignore the rest of the string temp = strrchr (basename, '/'); if (!temp) temp = basename; else temp++; if (*sourcedir) { dsprintf (ifile, "%s%c%s.%s", sourcedir, PATH_SEPARATOR, temp, ext); } else { dsprintf (ifile, "%s.%s", temp, ext); } free (basename); } else if (local) { char *temp2 = strrchr (this_program, PATH_SEPARATOR); dsprintf (ifile, "%sXXXXXX", temp2 ? temp2 + 1 : this_program); } else { const char *temp1 = getenv ("TMPDIR"); char *temp2 = strrchr (this_program, PATH_SEPARATOR); if ((!temp1) || (!temp1[0])) { temp1 = getenv ("TEMP"); if ((!temp1) || (!temp1[0])) { temp1 = "/tmp"; } } dsprintf (ifile, "%s%c%sXXXXXX", temp1, PATH_SEPARATOR, temp2 ? temp2 + 1 : this_program); } } FILE * preprocess_file (const char *filename, const char *ext) { #ifndef _WIN32 pid_t pid; int tempfd = 0; #endif if (cpp_name) { intermediate_file (tempname, filename, ext ? ext : "p", 0); build_cpp_args (filename, tempname->str); #ifdef _WIN32 if (!options.save_temps && !options.preprocess_only) mktemp (tempname->str); { FILE *tmp = fopen (tempname->str, "wb"); if (tmp == NULL) { fprintf (stderr, "%s: qfcc was unable to open\n", tempname->str); return 0; } fclose (tmp); } { int status; if (options.verbosity > 1) { const char **a; for (a = cpp_argv; *a; a++) printf ("%s ", *a); puts(""); } #ifdef _WIN64 status = spawnvp (_P_WAIT, cpp_argv[0], (char **) cpp_argv); #else status = spawnvp (_P_WAIT, cpp_argv[0], cpp_argv); #endif if (status) { fprintf (stderr, "%s: cpp returned error code %d\n", filename, status); return 0; } } if (options.preprocess_only) return 0; return fopen (tempname->str, "rb"); #else if (!options.save_temps && !options.preprocess_only) tempfd = mkstemp (tempname->str); if ((pid = fork ()) == -1) { perror ("fork"); return 0; } if (!pid) { // we're a child, check for abuse if (options.verbosity > 1) { const char **a; for (a = cpp_argv; *a; a++) printf ("%s ", *a); puts(""); } #ifdef HAVE_EXECVP execvp (cpp_argv[0], (char **)cpp_argv); #else execve (cpp_argv[0], (char **)cpp_argv, environ); #endif perror (cpp_argv[0]); exit (1); } else { // give parental guidance (or bury it in the back yard) int status; pid_t rc; // printf ("pid = %d\n", pid); #ifdef HAVE_WAITPID rc = waitpid (0, &status, 0 | WUNTRACED); #else rc = wait (&status); #endif if ((rc) != pid) { if (rc == -1) { perror ("wait"); return 0; } fprintf (stderr, "%s: The wrong child (%ld) died. Don't ask me, I don't know either.\n", this_program, (long) rc); return 0; } if (WIFEXITED (status)) { if (WEXITSTATUS (status)) { fprintf (stderr, "%s: cpp returned error code %d\n", filename, WEXITSTATUS (status)); return 0; } } else { fprintf (stderr, "%s: cpp returned prematurely.\n", filename); return 0; } } if (options.preprocess_only) return 0; else if (options.save_temps) return fopen (tempname->str, "rb"); else { return fdopen (tempfd, "rb"); } #endif } return fopen (filename, "rb"); }