/*
 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 * See the copyright notice in the ACK home directory, in the file "Copyright".
 *
 */

#include <stdlib.h>
#include <string.h>
#include "ack.h"
#include "list.h"
#include "trans.h"
#include "grows.h"
#include "data.h"
#include <signal.h>

#ifndef NORCSID
static char rcs_id[] = "$Id$" ;
#endif

#define ARG_MORE  40            /* The size of args chunks to allocate */

extern growstring scanvars();

static char      **arglist ;    /* The first argument */
static unsigned  argcount ;     /* The current number of arguments */
static unsigned  argmax;        /* The maximum number of arguments so far */

int runphase(phase) register trf *phase ; {
	register list_elem *elem ;
      char *prog ; int result ;
      growstring bline ;

      bline=scanvars(phase->t_prog) ;
      prog=gr_final(&bline) ;
	if ( v_flag || debug ) {
		if ( v_flag==1 && !debug ) {
			vprint("%s",phase->t_name) ;
			if ( !phase->t_combine ) {
				vprint(" %s%s\n",p_basename,
					strrchr(in.p_path,SUFCHAR) ) ;
			} else {
				scanlist(l_first(phase->t_inputs), elem) {
					vprint(" %s",p_cont(*elem)->p_path);
				}
				vprint("\n") ;
			}
		} else {
			/* list all args */
                      vprint("%s",prog) ;
			scanlist(l_first(phase->t_flags), elem) {
				vprint(" %s",l_content(*elem)) ;
			}
			scanlist(l_first(phase->t_args), elem) {
				vprint(" %s",l_content(*elem)) ;
			}
			vprint("\n") ;
		}
	}
	argcount=0 ;
	x_arg(phase->t_name) ;
	scanlist(l_first(phase->t_flags), elem) {
		x_arg(l_content(*elem)) ;
	}
	scanlist(l_first(phase->t_args), elem) {
		x_arg(l_content(*elem)) ;
	}
	x_arg( (char *)0 ) ;
      result=run_exec(phase,prog) ;
      throws(prog) ;
      return result ;
}

int run_exec(phase,prog) trf *phase ; char *prog ; {
	int status, child, waitchild ;

	do_flush();
	while ( (child=fork())== -1 ) ;
	if ( child ) {
		/* The parent */
		do {
			waitchild= wait(&status) ;
			if ( waitchild== -1 ) {
				fatal("missing child") ;
			}
		} while ( waitchild!=child) ;
		if ( status ) {
			if ( status&0200 && (status&0177)!=SIGQUIT &&
				t_flag<=1 ) unlink("core") ;
			switch ( status&0177 ) {
			case 0 :
				break ;
			case SIGHUP:
			case SIGINT:
			case SIGQUIT:
			case SIGTERM:
				quit(-5) ;
			default:
				error("%s died with signal %d",
                                      prog,status&0177) ;
			}
			/* The assumption is that processes voluntarely
			   dying with a non-zero status already produced
			   some sort of error message to the outside world.
			*/
			n_error++ ;
			return 0 ;
		}
		return 1 ; /* From the parent */
	}
	/* The child */
	if ( phase->t_stdin ) {
		if ( !in.p_path ) {
			fatal("no input file for %s",phase->t_name) ;
		}
		close(0) ;
		if ( open(in.p_path,0)!=0 ) {
			error("cannot open %s",in.p_path) ;
			exit(1) ;
		}
	}
	if ( phase->t_stdout ) {
		if ( !out.p_path ) {
			fatal("no output file for %s",phase->t_name) ;
		}
		close(1) ;
		if ( creat(out.p_path,0666)!=1 ) {
			close(1); dup(2);
			error("cannot create %s",out.p_path) ;
			exit(1) ;
		}
	}
      execv(prog,arglist) ;
	if ( phase->t_stdout ) { close(1) ; dup(2) ; }
      error("Cannot execute %s",prog) ;
	exit(1) ;
	/*NOTREACHED*/
}

x_arg(string) char *string ; {
	/* Add one execute argument to the argument vector */
	if ( argcount==argmax ) {
		if ( argmax==0 ) {
			argmax= 2*ARG_MORE ;
			arglist= (char **)getcore(argmax*sizeof (char *)) ;
		} else {
			argmax += ARG_MORE ;
			arglist= (char **)changecore((char *)arglist,
					argmax*sizeof (char *)) ;
		}
	}
	*(arglist+argcount++) = string ;
}
