/*ScianPreInstall.c
  Eric Pepke
  October 10, 1991
  Pre-installation program for SciAn
*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "machine.h"

#if (MACHINE == CRAYYMP) || (MACHINE == CONVEX)
/*fgets doesn't work properly on stdin*/
#define FGETS_IS_SO_STUPID
#endif

int fortranP = 0;			/*True iff FORTRAN is linkable*/
int okSoFar = 1;
int warnings = 0;

#define MAXLINE		400
char curLine[MAXLINE + 1];		/*Current line read from console or file*/
char linkLine[MAXLINE + 1];		/*Link flags line*/
char compLine[MAXLINE + 1];		/*Compilation flags line*/
char tempStr[MAXLINE + 1];		/*Temporary string*/
char f77Name[MAXLINE + 1];		/*Name of f77 compiler*/

int nAnswers;
int curAnswer;
char **answers;

/*File names*/
#define LINKMAKEFILE	"lfiles.make"	/*File containing link flags*/

/*Library directories to search*/
char *libDir[] =
    {
	"/lib",
	"/usr/lib",
	"/usr/local/lib"
    };

/*Executable directories to search*/
char *exeDir[] =
    {
	".",
	"/bin",
	"/usr/bin",
	"/usr/local/bin"
    };

#define NYESSTRINGS	6

/*Strings that count as "yes"*/
char *yesStrings[NYESSTRINGS] =
    {
	"y",
	"yes",
	"yeah",
	"yep",
	"ok",
	"sure"
    };

#define NNOSTRINGS	4

/*Strings that count as "no"*/
char *noStrings[NNOSTRINGS] = 
    {
	"n",
	"no",
	"nah",
	"nope"
    };

void Warning()
/*Prints warning message*/
{
    printf("------------------------------- WARNING -------------------------------\n");
    ++warnings;
}

void Danger()
/*Prints danger message*/
{
    printf("******************************* DANGER *******************************\n");
    okSoFar = 0;
}

void PrintDontChangeScript(outFile)
FILE *outFile;
/*Prints a don't change warning on script outFile*/
{
    fputs("# This file is produced by ScianPreInstall.c, which is run when you\n", outFile);
    fputs("# do a make INSTALL.  Do not change this file!\n\n", outFile);
}

void PrintDontChangeC(outFile)
FILE *outFile;
/*Prints a don't change warning on script outFile*/
{
    fputs("/*This file is produced by ScianPreInstall.c, which is run when you\n", outFile);
    fputs("  do a make INSTALL.  Do not change this file!\n*/\n", outFile);
}

void CopyFile(source, dest)
char *source, *dest;
/*Copies a file source to dest; blows up if it can't.  Side-effect--may
  set compiler stuff*/
{
    FILE *inFile, *outFile;

    inFile = fopen(source, "r");
    if (!inFile)
    {
	perror(source);
	exit(-1);
    }
    outFile = fopen(dest, "w");
    if (!outFile)
    {
	perror(dest);
	exit(-1);
    }
    PrintDontChangeScript(outFile);
    while (fgets(curLine, MAXLINE, inFile))
    {
	sscanf(curLine, " F77 = %s\n", f77Name);
	fputs(curLine, outFile);
    }
    fclose(inFile);
    fclose(outFile);
}

int FindLib(s)
char *s;
/*Returns the directory number iff s is a library that can be found or
  -1 if not*/
{
    int k;
    FILE *temp;

    for (k = 0; k < sizeof(libDir) / sizeof(char *); ++k)
    {
	struct stat buf;

	sprintf(tempStr, "%s/lib%s.a", libDir[k], s);
	if (stat(tempStr, &buf) == 0)
	{
	    return k;
	}
    }
    return -1;
}

int FindExe(s)
char *s;
/*Returns 1 iff s is an executable that can be found or
  0 if not*/
{
    int k;
    FILE *temp;
    struct stat buf;

    if (stat(s, &buf) == 0)
    {
	return 1;
    }

    for (k = 0; k < sizeof(exeDir) / sizeof(char *); ++k)
    {

	sprintf(tempStr, "%s/%s", exeDir[k], s);
	if (stat(tempStr, &buf) == 0)
	{
	    return 1;
	}
    }
    return 0;
}

void AppendLibrary(s)
char *s;
/*Appends library s to group of link files.  May emit warning message if
not found*/
{
    if (FindLib(s) < 0)
    {
	int k;
	Warning();
	printf("Library lib%s.a is not found in ", s);
	for (k = 0; k < sizeof(libDir) / sizeof(char *); ++k)
	{
	    if (k == (sizeof(libDir) / sizeof(char *)) - 1)
	    {
		printf(", or ");
	    }
	    else if (k)
	    {
		printf(", ");
	    }
	    printf("%s", libDir[k]);
	}
	printf("\nSciAn will probably not link.\n\n"); 
    }
    sprintf(tempStr, "-l%s ", s);
    strcat(linkLine, tempStr);
}

void ReadLibraries(f)
char *f;
/*Reads the libraries in file f into the link line*/
{
    FILE *inFile;
    char *s, *t;
    char libLine[MAXLINE + 1];

    inFile = fopen(f, "r");
    if (inFile)
    {
	while (fgets(libLine, MAXLINE, inFile))
	{
	    s = libLine;
	    while (*s && isspace(*s)) ++s;
	    if (*s && *s != '#')
	    {
		/*Not a comment*/
		t = s;
		while (*t && !isspace(*t)) ++t;
		*t = 0;
		AppendLibrary(s);
	    }
	}
    }
    else
    {
	perror(f);
    }
}

void EmitLinks()
/*Emits the link commands.  If it fails, blows up.*/
{
    FILE *outFile;

    /*Terminate links with a newline*/
    strcat(linkLine, "\n");

    /*Emit them into the file*/
    outFile = fopen(LINKMAKEFILE, "w");
    if (!outFile)
    {
	perror(LINKMAKEFILE);
	exit(-1);
    }
    PrintDontChangeScript(outFile);
    fputs("#If you need to change something about the link path, do so in the link\n", outFile);
    fputs("# file for  your machine.  You can get a list of those files by doing an\n", outFile);
    fputs("#    ls lfiles.*.make\n", outFile);
    fputs("# Then do make INSTALL again.\n\n", outFile); 
 
    fprintf(outFile, "LFILES =\t");
    fputs(linkLine, outFile);
    fprintf(outFile, "\n");

    if (fortranP)
    {
	fprintf(outFile, "OBJFILES = $(COBJ) $(FOBJ)\n");
    }
    else
    {
	fprintf(outFile, "OBJFILES = $(COBJ)\n");
    }
    fclose(outFile);
}

void FailAbort()
/*Fails and aborts*/
{
    printf("After you have made the changes to 'machine.h,' please try 'make INSTALL'\n");
    printf("once more.\n");
    exit(-1);
}

int YorNp()
/*Asks for an answer to a yes-or-no question*/
{
    char *s, *t;
    int k;

    fflush(stdout);

    for (;;)
    {
	if (curAnswer < nAnswers)
	{
	    strcpy(curLine, answers[curAnswer]);
	    ++curAnswer;
	}
	else
#if FGETS_IS_SO_STUPID
	gets(curLine);
#else
	fgets(curLine, MAXLINE, stdin);
#endif
	s = curLine;
	while (*s && isspace(*s)) ++s;
	t = s;

	while (isalpha(*t)) *t++ = tolower(*t);
	*t = 0;

	for (k = 0; k < NYESSTRINGS; ++k)
	{
	    if (0 == strcmp(s, yesStrings[k]))
	    {
		printf("\n");
		return 1;
	    }
	}
	for (k = 0; k < NNOSTRINGS; ++k)
	{
	    if (0 == strcmp(s, noStrings[k]))
	    {
		printf("\n");
		return 0;
	    }
	}
	printf("Please answer yes or no: ");
	fflush(stdout);
    }
}

void GuessMachine()
/*Guesses the machine type*/
{
#if MACHINE == IRIS4D
    printf("Your computer appears to be a Silicon Graphics IRIS.\n");
#else
#if MACHINE == RS6000
    printf("Your computer appears to be an IBM RISC computer.\n");
#else
    printf("The type of your computer could not be determined.  You will need to enter it\n");
    printf("by hand.  Please edit the file 'machine.h' and look for the defined constant\n");
    printf("MACHINE.\n\n");
    FailAbort();
#endif
#endif
    printf("Is this correct? ");
    if (!YorNp())
    {
	printf("\nYou will need to enter the type of your computer by hand.  Please edit the\n");
	printf("file 'machine.h' and look for the defined constant MACHINE.\n\n");
	FailAbort();
    }
#if MACHINE == RS6000
    Warning();
    printf("Not all versions of the IBM RS/6000 support SciAn.  In order to run,\n");
    printf("your system MUST have one of the graphics cards that support the GL library,\n");
    printf("and it MUST be equipped with a Z-buffer.  If this is not the case, SciAn\n");
    printf("will compile fine, but it will give an error when you try to run it.\n\n");


    ReadLibraries("lfiles.ibm6k.make");
    CopyFile("flags.ibm6k.make", "flags.make");
#else
#if MACHINE == IRIS4D
    ReadLibraries("lfiles.sgi4d.make");
    CopyFile("flags.sgi4d.make", "flags.make");
#endif
#endif
}

void FindMalloc()
/*Finds the malloc library according to MALLOCH and appends the string to lfiles*/
{
    int found;
    FILE *includeFile;

    /*See if the library can be found*/
    found = (FindLib(LIBMALLOC) >= 0);

    if (found)
    {
	printf("The fast malloc library will be used.\n\n");
    }
    else
    {
	printf("The standard malloc library will be used.\n\n");
    }

    if (found)
    {
	AppendLibrary(LIBMALLOC);
    }

    includeFile = fopen("machine.malloc.h", "w");
    if (!includeFile)
    {
	perror("machine.malloc.h");
	exit(-1);
    }

    PrintDontChangeC(includeFile);

    if (found)
    {
	fprintf(includeFile, "\n#define MALLOCH\n");
    }
    fclose(includeFile);
}

void FindHDF()
/*Finds the NCSA HDF library according to HDFDEF and appends the string to lfiles*/
{
    int found;
    int foundVersion = 0;
    int k;
    FILE *includeFile;

    /*See if the HDF library has been requested*/

    /*See if the library can be found*/
    k = FindLib(LIBHDF);

    if (k >= 0)
    {
	FILE *temp;

	found = 1;

	    /*Try to get the found version*/
	    sprintf(tempStr, "ar -t %s/lib%s.a > ./temp", libDir[k], LIBHDF);
	    if (system(tempStr) >= 0)
	    {
		/*Now search file temp for the version*/
		temp = fopen("temp", "r");
		if (temp)
		{
		    foundVersion = -1;
		    while (fgets(tempStr, MAXLINE, temp))
		    {
			if (strstr(tempStr, "dfsdF.o"))
			{
			    foundVersion = foundVersion < 0 ? 31 : 0;
			}
			if (strstr(tempStr, "vparse.o"))
			{
			    foundVersion = foundVersion < 0 ? 32 : 0;
			}
		    }
		    if (foundVersion < 0) foundVersion = 0;
		}
		else
		{
		    foundVersion = 0;
		}
	    }
	    else
	    {
		foundVersion = 0;
	    }
    }
    else
    {
	found = 0;
    }

    if (found)
    {
	printf("The NCSA HDF library has been located on your machine.  If you install\n");
	printf("SciAn with this library, it will provide a useful file format.\n\n");

	if (!foundVersion)
	{
	    Warning();
	    printf("SciAn has not been tested with the version of the HDF library installed\n");
	    printf("on your machine.  In all probability, it will work just fine, but there\n");
	    printf("is a small possibility you might get link errors.\n\n");
	}

	printf("Do you want to install with the HDF library? ");

	found = YorNp();
    }
    else
    {
	Warning();
	printf("The NCSA HDF library was not found on your machine and will not be linked\n");
	printf("into SciAn.  You may want to consider getting the HDF library, as it\n");
	printf("provides a useful file format.  It is available via anonymous ftp from\n");
	printf("the fine folks at the National Center for Supercomputing Applications\n");
	printf("at the University of Illinois at Champaign-Urbana (ftp.ncsa.uiuc.edu).\n");
	printf("Install the HDF library in /usr/local/lib and MAKE INSTALL again.\n\n");
    }

    includeFile = fopen("machine.hdf.h", "w");
    if (!includeFile)
    {
	perror("machine.hdf.h");
	exit(-1);
    }

    PrintDontChangeC(includeFile);

    if (found)
    {
	fprintf(includeFile, "\n#define HDFDEF\n");
	if (foundVersion == 31)
	{
	    fprintf(includeFile, "#define HDF31\n");
	}
    }
    fclose(includeFile);

    if (found)
    {
	AppendLibrary(LIBHDF);
    }
}

void FindFORTRAN()
/*Finds FORTRAN*/
{
    int k;
    FILE *includeFile;

    /*See if FORTRAN can be found*/
    k = FindExe(f77Name);

    if (k)
    {
	printf("SciAn will be compiled using FORTRAN as well as C, which will give you\n");
	printf("the entire PLOT-3D file reader.\n\n");
    }
    else
    {
	Warning();
	printf("FORTRAN could not be found on your machine.  SciAn will compile without\n");
	printf("it, but some features such as the PLOT-3D file reader which require FORTRAN\n");
	printf("will not work fully.\n\n");
    }

    includeFile = fopen("machine.fortran.h", "w");
    if (!includeFile)
    {
	perror("machine.hdf.h");
	exit(-1);
    }

    PrintDontChangeC(includeFile);

    if (k)
    {
	fortranP = 1;
	fprintf(includeFile, "\n#define FORTRAN\n");
#if MACHINE == IRIS4D
	ReadLibraries("flfiles.sgi4d.make");
#else
#if MACHINE == RS6000
	ReadLibraries("flfiles.ibm6k.make");
#endif
#endif
    }
    fclose(includeFile);
}

main(argc, argv)
int argc;
char *argv[];
{
    strcpy(f77Name, "f77");

    nAnswers = argc - 1;
    curAnswer = 0;
    if (nAnswers)
    {
	answers = &(argv[1]);
    }

    printf("\nScianPreInstall version 1.1 by Eric Pepke, 2 Feb 1993\n\n");
    printf("The way SciAn will be compiled on your computer depends mostly on predefined\n");
    printf("symbols and various flags defined in the 'machine.h' include file.  This\n");
    printf("program determines whether 'machine.h' is consistent with the characteristics\n");
    printf("of your computer and tells you what to do if they are not.\n\n");
    printf("Please pay CAREFUL ATTENTION to the messages generated by this program.\n");
    printf("Messages that begin with DANGER describe problems which will cause SciAn\n");
    printf("not to compile or link properly.  Messages that begin with WARNING describe\n");
    printf("possible problems that you must be aware of.\n\n");
    
    GuessMachine();
    
    if (!okSoFar)
    {
	FailAbort();
    }

    FindMalloc();
    
    if (!okSoFar)
    {
	FailAbort();
    }

    FindHDF();
    
    if (!okSoFar)
    {
	FailAbort();
    }

    FindFORTRAN();
    
    if (!okSoFar)
    {
	FailAbort();
    }

    EmitLinks();

    if (warnings)
    {
	printf("The pre-installation process produced %d warning message%s.  Please read the\n", warnings, warnings == 1 ? "" : "s");
	printf("message%s to see if %s to your case.  You can try to compile SciAn\n", warnings == 1 ? "" : "s", warnings == 1 ? "it applies" : "they apply");
	printf("in spite of the warning%s by entering 'make scian' now.\n\n", warnings == 1 ? "" : "s");
    }
    else
    {
	printf("The link commands should now be set up properly.  To make SciAn, enter\n");
	printf("make scian\n\n");
    }

#if MACHINE == IRIS4D
    printf("If you have more than one processor on your computer, use pmake\n");
    printf("instead of make to speed things up.\n\n");
#endif
    exit(0);
}
