/*
 * Copyright (c) 1995, 1996, 1997, 1999 The University of Utah and
 * the Computer Systems Laboratory at the University of Utah (CSL).
 *
 * This file is part of Flick, the Flexible IDL Compiler Kit.
 *
 * Flick 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.
 *
 * Flick 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 Flick; see the file COPYING.  If not, write to
 * the Free Software Foundation, 59 Temple Place #330, Boston, MA 02111, USA.
 */

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <mom/compiler.h>

/*
 * `CPP', `CPPFLAGS', `CXXCPP', and `CXXCPPFLAGS' should all be defined by the
 * configuration process and communicated to us to through the compilation
 * command line.
 *
 * If `gcc -E' is the C preprocessor, `CPPFLAGS' must contain `-x c' or else
 * `gcc' will assume that an input `.x' file is a linker file.  Similarly, if
 * GNU C++ is the C++ preprocessor, `CPPCXXFLAGS' must contain `-x c++'.
 */

#ifndef CPP
#  define CPP "/lib/cpp"
#endif
#ifndef CPPFLAGS
#  define CPPFLAGS "-C"
#endif

#ifndef CXXCPP
#  define CXXCPP CPP
#endif
#ifndef CXXCPPFLAGS
/* Don't suck up `CPPFLAGS', since it may have C-specific options. */
#  define CXXCPPFLAGS "-C"
#endif

static char cpp_cmd[] = CPP;
static char cpp_flags[] = CPPFLAGS;

static char cxxcpp_cmd[] = CXXCPP;
static char cxxcpp_flags[] = CXXCPPFLAGS;

#define PP_ARGC_MAX (128)
extern char *infilename;


/*****************************************************************************/

/*
 * Invoke the named preprocessor on `infile', with command arguments `pp_flags'
 * and `other_flags'.  If `infile' is null, arrange for the preprocessor to
 * read from stdin.
 * 
 * Return a `FILE *' so that we receive the preprocessor's output.  As a side
 * effect, set the global variable `infilename' to be a printable version of
 * `infile'.
 *
 * This is the internal, shared work function used by `call_c_preprocessor' and
 * `call_cxx_preprocessor', defined later in this file.
 */
static FILE *
call_preprocessor(
	const char *pp_cmd,
	const char *pp_flags,
	const char *infile,
	const char *other_flags
	)
{
	int pp_flags_p;		/* Is `pp_flags' non-empty? */
	int other_flags_p;	/* Is `other_flags' non-empty? */
	
	char *pp_cmdline;
	int pp_cmdline_len;
	
	char *pp_argv[PP_ARGC_MAX];
	int pp_argc;
	
	char *pp_infile;
	
	int pd[2];
	
	/*
	 * Parse the preprocessor command line into an argument vector.
	 */
	pp_flags_p = (pp_flags && pp_flags[0]);
	other_flags_p = (other_flags && other_flags[0]);
	
	pp_cmdline_len = strlen(pp_cmd) + 1 /* NUL */;
	if (pp_flags_p)
		pp_cmdline_len += (1 /* SPC */ + strlen(pp_flags));
	if (other_flags_p)
		pp_cmdline_len += (1 /* SPC */ + strlen(other_flags));
	
	pp_cmdline = (char *) mustmalloc(pp_cmdline_len);
	
	strcpy(pp_cmdline, pp_cmd);
	if (pp_flags_p) {
		strcat(pp_cmdline, " ");
		strcat(pp_cmdline, pp_flags);
	}
	if (other_flags_p) {
		strcat(pp_cmdline, " ");
		strcat(pp_cmdline, other_flags);
	}
	
	for (pp_argc = 0; pp_argc < PP_ARGC_MAX; ++pp_argc) {
		pp_argv[pp_argc] =
			strtok(((pp_argc == 0) ? pp_cmdline : 0), " \t");
		if (!pp_argv[pp_argc])
			/* When we get a null pointer, we're done. */
			break;
	}
	if (pp_argc == 0)
		panic("The command to run the preprocessor is empty.");
	if (pp_argc >= PP_ARGC_MAX)
		panic("Too many arguments to the preprocessor.");
	
	if (infile) {
		/*
		 * At this point, `pp_argc' is the index of the null string
		 * in `pp_argv' that was returned by `strtok'.
		 */
		pp_infile = (char *) mustmalloc(strlen(infile) + 1);
		strcpy(pp_infile, infile);
		
		pp_argv[pp_argc] = pp_infile;
		++pp_argc;
		if (pp_argc >= PP_ARGC_MAX)
			panic("Too many arguments to the preprocessor.");
		pp_argv[pp_argc] = 0;
	} else
		pp_infile = 0;
	
	/* Set up our input pipeline. */
	infilename = (((infile == NULL) || (!strcmp(infile, "-"))) ?
		      "<stdin>" : pp_infile);
	(void) pipe(pd);
	switch (fork()) {
	case 0:
		(void) close(1);
		(void) dup2(pd[1], 1);
		(void) close(pd[0]);
		execvp(pp_argv[0], pp_argv);
		perror("execvp");
		exit(1);
	case -1:
		perror("fork");
		exit(1);
	}
	(void) close(pd[1]);
	return fdopen(pd[0], "r");
}


/*****************************************************************************/

/*
 * Invoke the C preprocessor on `filename', with command argument `flags', and
 * return a `FILE *' so that we receive the preprocessor's output.
 */
FILE *
call_c_preprocessor(
	const char *filename,
	const char *flags
	)
{
#ifdef CPP_DASH_FOR_STDIN
	/*
	 * We need to specify `-' on the command line to get the preprocessor
	 * to read from stdin.
	 */
	if (!filename)
		filename = "-";
#endif /* CPP_DASH_FOR_STDIN */
	
	return call_preprocessor(cpp_cmd, cpp_flags, filename, flags);
}

/*
 * Invoke the C++ preprocessor on `filename', with command argument `flags',
 * and return a `FILE *' so that we receive the preprocessor's output.
 */
FILE *
call_cxx_preprocessor(
	const char *filename,
	const char *flags
	)
{
#ifdef CXXCPP_DASH_FOR_STDIN
	/*
	 * We need to specify `-' on the command line to get the preprocessor
	 * to read from stdin.
	 */
	if (!filename)
		filename = "-";
#endif
	
	return call_preprocessor(cxxcpp_cmd, cxxcpp_flags, filename, flags);
}

/* End of file. */



syntax highlighted by Code2HTML, v. 0.9.1