static char rcsid[] = "$Id: fpp.c,v 1.10 2000/07/28 12:26:34 m-hirano Exp $";
/* 
 * $RWC_Release: Omni-1.6 $
 * $RWC_Copyright:
 *  Omni Compiler Software Version 1.5-1.6
 *  Copyright (C) 2002 PC Cluster Consortium
 *  
 *  This software is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License version
 *  2.1 published by the Free Software Foundation.
 *  
 *  Omni Compiler Software Version 1.0-1.4
 *  Copyright (C) 1999, 2000, 2001.
 *   Tsukuba Research Center, Real World Computing Partnership, Japan.
 *  
 *  Please check the Copyright and License information in the files named
 *  COPYRIGHT and LICENSE under the top  directory of the Omni Compiler
 *  Software release kit.
 *  
 *  
 *  $
 */

#include "F-front.h"
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>

static int execAsCpp = 0;

#ifndef HAVE_STRDUP
char *
strdup(s)
     char *s;
{
    char *p;
    int len = strlen(s);
    
    p = (char *)malloc(sizeof(char) * (len + 1));
    memcpy(p, s, len);
    p[len] = '\0';
    return p;
}
#endif /* !HAVE_STRDUP */


static int
execIt(argv, stdIn, stdOut, stdErr)
     char *argv[];
     int *stdIn, *stdOut, *stdErr;
{
    pid_t pid = fork();
    
    if (pid < 0) {
	return -1;
    } else if (pid == 0) {
	if (stdIn != NULL) {
	    dup2(*stdIn, 0);
	}
	if (stdOut != NULL) {
	    dup2(*stdOut, 1);
	}
	if (stdErr != NULL) {
	    dup2(*stdErr, 2);
	}
	execvp(argv[0], argv);
	exit(1);
    } else {
	int stat;
	pid_t wPid = waitpid(pid, &stat, 0);
	if (wPid != pid) {
	    return -1;
	}
	return WEXITSTATUS(stat);
    }
    return -1;
}


static char *
Basename(path)
    char *path;
{
    char buf[4096];
    char *lastS = strrchr(path, '/');
    char *lastP;

    if (lastS == NULL) {
        strcpy(buf, path);
    } else {
        lastS++;
        strcpy(buf, lastS);
    }
    lastP = strrchr(buf, '.');
    if (lastP != NULL) {
        *lastP = 0;
    }
    return strdup(buf);
}


static char *
makeTemp(file)
     char *file;
{
    char tmpName[65536];
    char *base = Basename(file);
    struct stat s;

    srand((int)time(NULL));
    while (1) {
	sprintf(tmpName, "/tmp/%s.%d.tmp.c",
		base, rand());
	errno = 0;
	if (stat(tmpName, &s) < 0) {
	    if (errno == ENOENT) {
		free(base);
		return strdup(tmpName);
	    }
	}
    }
}


static char *
getEnvCc()
{
    char *envCc = getenv("OMNI_CC_FOR_F77_CPP");
    char *envCCisCPP = getenv("OMNI_CC_FOR_F77_CPP_IS_CPP");

    char *ret = NULL;
    char *cp = NULL;
    char *rp;
    int len;
    
    if (envCc == NULL) {
	envCc = getenv("CC");
	if (envCc == NULL) {
	    return NULL;
	}
    }

    if (envCCisCPP != NULL) {
	execAsCpp = 1;
    }

    len = strlen(envCc);
    ret = (char *)malloc(sizeof(char) * (len + 1));
    memset(ret, 0, len + 1);
    rp = ret;

    cp = envCc;
    while (isspace((int)*cp)) {
	cp++;
    }

    while (*cp != '\0' && !isspace((int)*cp)) {
	*rp++ = *cp++;
    }

    return ret;
}


int
main(argc, argv)
     int argc;
     char *argv[];
{
    char **opt;
    char **files;
    char *envCc = NULL;
    int i;
    int nOpt = 3;
    int nFiles = 0;
    char *cutOpt[4];
    char cutCmd[65536];
    char *tmpFile, *tmpFile2;
    int eStat = 1;
    int ignoreError = FALSE;
    int outFd;

    opt = (char **)malloc(sizeof(char *) * (argc + 5));
    files = (char **)malloc(sizeof(char *) * argc);
    for (i = 0; i < argc + 5; i++) {
	opt[i] = NULL;
	if (i < argc) {
	    files[i] = NULL;
	}
    }

    envCc = getEnvCc();
    if (envCc != NULL) {
	opt[0] = envCc;
    } else {
	opt[0] = DEFAULT_CC;
    }

    if (execAsCpp == 1) {
	nOpt = 1;
    } else {
	opt[1] = "-E";
	opt[2] = "-C";
	nOpt = 3;
    }

    for (i = 1; i < argc; i++) {
	if (*argv[i] == '-') {
	    if (strcmp(argv[i], "-ignore-error") == 0) {
		ignoreError = TRUE;
	    } else {
		opt[nOpt++] = argv[i];
	    }
	} else {
	    files[nFiles++] = argv[i];
	}
    }

    if (nFiles < 1) {
	return 0;
    }

    cutOpt[0] = "sh";
    cutOpt[1] = "-c";
    for (i = 0; i < nFiles; i++) {
	tmpFile = NULL;
	tmpFile2 = NULL;
	outFd = -1;
	tmpFile = makeTemp(files[i]);
	sprintf(cutCmd, "cut -b1-80 %s > %s; exit $?",
		files[i], tmpFile);
	cutOpt[2] = cutCmd;
	cutOpt[3] = NULL;
	eStat = execIt(cutOpt, (int *)NULL, (int *)NULL, (int *)NULL);
	if (eStat != 0) {
	    goto LoopEnd;
	}

	opt[nOpt] = tmpFile;
	opt[nOpt + 1] = NULL;
	tmpFile2 = makeTemp(files[i]);
	outFd = open(tmpFile2, O_CREAT|O_WRONLY|O_TRUNC|O_APPEND, 0644);
	if (outFd < 0) {
	    fprintf(stderr, "can't open temporary file. exit\n");
	    goto LoopEnd;
	}
#if 0
	{
	    char **x = opt;
	    while (*x != NULL) {
		fprintf(stderr, "debug: '%s'\n", *x);
		x++;
	    }
	}
#endif
	eStat = execIt(opt, (int *)NULL, &outFd, (int *)NULL);
	if (eStat != 0) {
	    if (ignoreError == FALSE) {
		goto LoopEnd;
	    } else {
		eStat = 0;
	    }
	}

	sprintf(cutCmd, "sed 's:%s:%s:g' %s; exit $?",
		tmpFile, files[i], tmpFile2);
	cutOpt[2] = cutCmd;
	cutOpt[3] = NULL;
	eStat = execIt(cutOpt, (int *)NULL, (int *)NULL, (int *)NULL);
	if (eStat != 0) {
	    if (ignoreError == FALSE) {
		goto LoopEnd;
	    } else {
		eStat = 0;
	    }
	}

	LoopEnd:
	if (tmpFile != NULL) {
	    (void)unlink(tmpFile);
	    (void)free(tmpFile);
	}
	if (tmpFile2 != NULL) {
	    (void)unlink(tmpFile2);
	    (void)free(tmpFile2);
	}
	if (outFd >= 0) {
	    (void)close(outFd);
	}
	if (eStat != 0) {
	    break;
	}
    }

    return eStat;
}
