/****************************************************************************
* cscript - run c programs as scripts.
*
* (c) copyright 2001 Eric Lammerts <eric@lammerts.org>
*****************************************************************************
* 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.
*
* A copy of the GNU General Public License is available on the World Wide Web
* at `http://www.gnu.org/copyleft/gpl.html'.  You can also obtain it by
* writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*****************************************************************************/

#define COMPILER_PROG "gcc"
#define COMPILER_ARGS "-pipe", "-Wall", "-O6", "-o", exe, "-x", "c", "-"

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
              
int main(int argc, char **argv)
{
	char *p, exe[256], *src, buf[4096];
	int r, fd, status, pipefds[2];
	FILE *f, *outf;
	
	if(argc < 2) exit(1);
	src = argv[1];

	if((f = fopen(src, "r")) == NULL) {
		perror(src);
		exit(1);
	}
	if(pipe(pipefds) == -1) {
		perror("pipe");
		exit(1);
	}

	p = strrchr(src, '/');
	if(p == NULL) p = src;
	sprintf(exe, "/tmp/%.224s.tmp.XXXXXX", p);
 		
 	if((fd = mkstemp(exe)) == -1) {
		perror("mkstemp");
		exit(1);
	}
	close(fd);

	switch(fork()) {
		case -1:
			perror("fork");
			exit(1);
		case 0:
			/*child*/

			/* close write end of the pipe */
			close(pipefds[1]);

			/* connect read end of the pipe to stdin */
			dup2(pipefds[0], 0);
			close(pipefds[0]);

			/* redirect the compiler's stdout to stderr */
			dup2(2, 1);

			/* run gcc */
			execlp(COMPILER_PROG, COMPILER_PROG, COMPILER_ARGS, NULL);
			perror(COMPILER_PROG);
			exit(1);
		default:
			/*parent*/
			break;
	}
	
	close(pipefds[0]);
	if((outf = fdopen(pipefds[1], "w")) == NULL) {
		perror("fdopen");
		exit(1);
	}
	
	/* feed source to gcc, comment out the first (#!/...) line */
	fprintf(outf, "//");
	while((r = fread(buf, 1, 4096, f))) {
		if(fwrite(buf, 1, r, outf) != r) {
			exit(1);
		}
	}
	fclose(f);
	fclose(outf);
	
	/* wait for the compiler to finish */
	while(wait(&status) >= 0) { }
	
	if(!WIFEXITED(status) || WEXITSTATUS(status) != 0) exit(1);
	
	switch(fork()) {
		case -1:
			perror("fork");
			exit(1);
		case 0:
			/*child*/
			break;
		default:
			/*parent*/
			execv(exe, argv + 1);
			perror(exe);
			exit(1);
	}

	/* don't interfere with parent */	
	close(0);
	close(1);
	close(2);
	chdir("/");

	/* protect us from signals sent to our parent */	
	setpgrp();

	/* wait until command exits */
	while(getppid() != 1) {
		sleep(1);
	}

	/* delete tmp exe */
	unlink(exe);

	return 0;
}
