/************************************************************
**      eps1 -- prepares a script to install EPS
**      (C) 1994, Jose A. Manas <jmanas@dit.upm.es>
**
**  94/10/04   1.1  inicial
**  94/11/02   1.2  OSTYPE= {unix, dos}
**  94/11/03   1.3  Makefile.OSTYPE
**  94/11/07   1.4  remove <DRIVE>: from paths
**  94/11/07   1.5  PCEXEC
**  94/11/14   1.6  set multitoken
**  94/11/14   1.7  ld library path
**  94/11/15   1.8  no BSD needed in solaris
**  94/11/16   1.9  use MSDOS, predefined
**  94/11/16   1.10 use getcwd() rather than getwd()
**  94/11/18   1.11 option -O to optimize
**  94/11/18   1.12 GO32 as GOXX
**  94/12/23   1.13 GO32 as GOXX
**  94/12/23   1.14 read CF_DBX from environment
**  95/01/11   1.15 GOXX everywhere
**  95/01/27   1.16 CreateDir
************************************************************/

#define VERSION "1.16"

#include <unistd.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>

/* KJT 11/03/98: added for NS/OS*/

#ifdef __NeXT__
#include <sys/file.h>
#endif

#ifndef TRUE
#define TRUE  1
#define FALSE 0
#endif

int FlagY= FALSE;

char *DataFile= "eps2.bat";
FILE *dfp;

/* KJT 11/03/98: added strdup for NS/OS */

#ifdef __NeXT__
char *strdup(s) register char *s; {

  register char *ns;

  return(((ns=malloc(strlen(s)+1))==0)?0:strcpy(ns,s)); }

#define getcwd getwd
#endif

char ReadBuffer[BUFSIZ];
char pathname[MAXPATHLEN];;
char makefilename[MAXPATHLEN];;

char *OSTYPE;

char *EPS;
char *EPSBIN;
char *EPSINC;
char *EPSLIB;

char *CC;
char *CF_DBX;
char *LD_OPTIONS;
char *LD_LIBRARY_PATH;
char *GOXX;

char *UserHelp[] = {
  "usage: eps1 [-flag ...]",
  "  -h    help",
  "  -v    version",
  "  -y    say YES to every question (in fact, do not ask!)",
  "  -data file   file to save configuration data [eps2.bat]",
  NULL
};

/*************************************************************
**  Dialog
**       KEY
**       Question
**       Help material
**       //
*************************************************************/

char *OnlineHelp[]= {
  "OK",
  "Doy you agree with these data?",
  "YES => continue",
  "NO => ask again",
  "//",

  "OSTYPE",
  "Operating System?",
  "Usual systems are:",
  " unix  dos",
  "//",

  "EPS",
  "EPS installation directory",
  "//",
  "EPSBIN",
  "EPS binaries directory?",
  "For lag, and rag",
  "//",
  "EPSINC",
  "EPS includes directory?",
  "For cast.hh, rag.hh, and alga.hh",
  "//",
  "EPSLIB",
  "EPS library directory?",
  "For -l cast, -l rag, and -l alga",
  "//",

  "CC",
  "C compiler?",
  "Usual one is native cc,",
  "but you may prefer GNU gcc",
  "//",
  "CF_DBX",
  "Flags for the C compiler",
  "Some ideas:",
  "  -g        for debugging",
  "  -J        for old Sun 3 to generate long jumps",
  "  -DNDEBUG  to avoid debug code inclusion",
  "  -O        to optimize",
  "//",
  "LD_OPTIONS",
  "Link options?",
  "  usually: empty",
  "  SunOS: -Bstatic (suggested)",
/*"  Solaris: -lbsd (required) -Bstatic (suggested)", */
  "//",
  "LD_LIBRARY_PATH",
  "Path to search for extra libraries?",
/*  "  Solaris: /usr/ucblib (required)", */
  "//",
  "GO32",
  "Full path for go32?",
  "//",

  NULL
};

/****************************************************************
** print a text array                                          **
****************************************************************/

void
ptext (fp, text)
  FILE *fp;
  char *text[];
{
  int i;

  for (i= 0; text[i] != NULL; i++)
    (void) fprintf (fp, "%s\n", text[i]);
}

/****************************************************************
** case independent string comparision /for portability/       **
****************************************************************/

int
cstrcmp (s1, s2)
  char *s1, *s2;
{
  register char ls1, ls2;

  while (*s1 && *s2) {
    ls1= isupper (*s1) ? tolower (*s1) : *s1;
    ls2= isupper (*s2) ? tolower (*s2) : *s2;
    if (ls1 < ls2)
      return -1;
    else if (ls1 > ls2)
      return 1;
    s1++; s2++;
  }
  if (*s1 == *s2)
    return 0;
  else if (*s1)
    return 1;
  else
    return -1;
}

int
cstrncmp (s1, s2, n)
  char *s1, *s2;
  int n;
{
  register char ls1, ls2;

  for (;;) {
    if (n-- <= 0)
      return 0;
    if (*s1 == 0 || *s2 == 0)
      break;
    ls1= isupper (*s1) ? tolower (*s1) : *s1;
    ls2= isupper (*s2) ? tolower (*s2) : *s2;
    if (ls1 < ls2)
      return -1;
    else if (ls1 > ls2)
      return 1;
    s1++; s2++;
  }
  if (*s1 == *s2)
    return 0;
  else if (*s1)
    return 1;
  else
    return -1;
}

int
Yes (data)
  char *data;
{
  if (data[0] == 'y' || data[0] == 'Y' ||
      data[0] == 's' || data[0] == 'S')
    return TRUE;
  return FALSE;
}

int
HasAny (data)
  char *data;
{
  char *p;

  p= data;
  if (*p == '\0') return FALSE;
  while (isspace (*p)) p++;
  if (*p == '\0') return FALSE;
  return TRUE;
}

/****************************************************************
** remove initial <drive>: for PC paths                        **
****************************************************************/

char*
nodrive (p)
  char *p;
{
  if (*(p+1) == ':')
    return p+2;
  else
    return p;
}

/****************************************************************
** replace '/' => '\'                                          **
****************************************************************/

char*
pcdir (path)
  char *path;
{
  static char MyPath[128];
  char *p;
  char good, bad;

  good= '\\';
  bad= '/';
  (void) strcpy (MyPath, path);
  while ((p= strchr (MyPath, bad)) != NULL)
    *p= good;
  return MyPath;
}

void
CreateDir (path)
  char *path;
{
  if (chdir (path) < 0) {
    (void) mkdir (path, 0755);
    if (chdir (path) < 0) {
      (void) fprintf (stderr,
		      "cannot chdir into %s directory\n",
		      path);
      exit (1);
    }
  }
  (void) chdir ("..");
}

void
SetEPS (p)
  char *p;
{
  EPS= nodrive (p);
  (void) sprintf (ReadBuffer, "%s/%s", EPS, "bin");
  EPSBIN= strdup (ReadBuffer);
  (void) sprintf (ReadBuffer, "%s/%s", EPS, "lib");
  EPSINC= strdup (ReadBuffer);
  (void) sprintf (ReadBuffer, "%s/%s", EPS, "lib");
  EPSLIB= strdup (ReadBuffer);
}

void
InitData ()
{
  char *p;

#ifdef MSDOS
  OSTYPE= "dos";
#else
  OSTYPE= "unix";
#endif

  if ((p= getenv ("EPS")) != NULL)
    SetEPS (strdup (p));
  else {
    (void) getcwd (pathname, MAXPATHLEN);
    SetEPS (strdup (pathname));
  }

  CC= "gcc";
  if ((p= getenv ("CC")) != NULL)
    CC= strdup (p);
  CF_DBX= "-DNDEBUG -O2";
  if ((p= getenv ("CF_DBX")) != NULL)
    CF_DBX= strdup (p);

  if (cstrcmp (OSTYPE, "dos") == 0)
    LD_OPTIONS= "";
  else
    LD_OPTIONS= "-Bstatic";
  if ((p= getenv ("LD_OPTIONS")) != NULL)
    LD_OPTIONS= strdup (p);

  LD_LIBRARY_PATH= "";
  if ((p= getenv ("LD_LIBRARY_PATH")) != NULL)
    LD_LIBRARY_PATH= strdup (p);

  GOXX= "/djgpp/bin/go32.exe";
  if ((p= getenv ("GOXX")) != NULL)
    GOXX= strdup (p);
}

void
LoadData ()
{
  FILE *fp;
  char *p, *q;

  fp= fopen (DataFile, "r");
  if (fp == NULL)
    return;
  while (fgets (ReadBuffer, sizeof (ReadBuffer), fp) != NULL) {
    if ((p= strchr (ReadBuffer, '\n')) != NULL)
      *p= '\0';
    if (ReadBuffer[0] == '\0')
      continue;
    if (ReadBuffer[0] == '#')
      continue;

    if (cstrncmp (ReadBuffer, "SET ", 4) == 0)
      p= ReadBuffer+4;
    else
      p= ReadBuffer;
    q= strchr (p, '=');
    if (q != NULL) {
      *q= '\0';
      q++;
    if (*q == '"')
      q++;
    if (strlen (q) > 0 && *(q + strlen (q) -1) == '"')
      *(q + strlen (q) -1)= '\0';

      if (strcmp (p, "OSTYPE") == 0)
	OSTYPE= strdup (q);

      else if (strcmp (p, "EPS") == 0)
	EPS= strdup (q);
      else if (strcmp (p, "EPSBIN") == 0)
	EPSBIN= strdup (q);
      else if (strcmp (p, "EPSINC") == 0)
	EPSINC= strdup (q);
      else if (strcmp (p, "EPSLIB") == 0)
	EPSLIB= strdup (q);

      else if (strcmp (p, "CC") == 0)
	CC= strdup (q);
      else if (strcmp (p, "CF_DBX") == 0)
	CF_DBX= strdup (q);
      else if (strcmp (p, "LD_OPTIONS") == 0)
	LD_OPTIONS= strdup (q);
      else if (strcmp (p, "LD_LIBRARY_PATH") == 0)
	LD_LIBRARY_PATH= strdup (q);
      else if (strcmp (p, "GOXX") == 0)
	GOXX= strdup (q);
    }
  }
  (void) fclose (fp);
}

char*
ReadData (key, def)
  char *key;
  char *def;
{
  int h, q, i;
  char *p, *e;

  if (FlagY)
    return def;

  for (h= 0; OnlineHelp[h] != NULL; h++)
    if (cstrcmp (OnlineHelp[h], key) == 0)
      break;
  if (OnlineHelp[h] == NULL) {
    fprintf (stderr, "No such keyword (%s)!\n", key);
    return "";
  }
  h++;
  q= h;         /* question */
  h++;          /* help */

  for (;;) {
    (void) printf ("%s [%s]: ", OnlineHelp[q], def);
    (void) fflush (stdout);
    if (fgets (ReadBuffer, sizeof (ReadBuffer), stdin) == NULL)
      return def;
    if ((p= strchr (ReadBuffer, '\n')) != NULL)
      *p= '\0';
    for (p= ReadBuffer; isspace (*p); p++)
      ;
    if (*p == '\0')
      return def;
    if (*p == '?') {
      printf ("\n");
      for (i= h; strcmp (OnlineHelp[i], "//") != 0; i++) {
        printf ("%s\n", OnlineHelp[i]);
      }
      continue;
    }
    if (strcmp (p, "-") == 0)
      return "";
    for (e= ReadBuffer + strlen (ReadBuffer) - 1; isspace (*e); e--)
      ;
    e++;
    *e= '\0';
    return strdup (p);
  }
}

void
AskData ()
{
  char *p;

  if (!FlagY) {
    printf ("Please, answer the following questions\n");
    printf ("to the best of your knowledge.\n");
    printf ("I'll try to provide consistent defaults,\n");
    printf ("and to inform of inconsistencies.\n");
    printf ("\n");
    printf ("The first time you run me, I use my own defaults.\n");
    printf ("After a run, eps2.bat holds your opinions,\n");
    printf ("(you may even edit it manually)\n");
    printf ("and I'll use them if you run me twice or more.\n");
    printf ("So, do not worry too much upon mistakes:\n");
    printf ("just run me again!\n");
    printf ("\n");
    printf ("Type just RETURN if you accept the default value.\n");
    printf ("Type ? if you need some help (explanation).\n");
    printf ("Type - if you want to clear out any value.\n");
    printf ("\n");
  }

  /*
  Datax= ReadData ("x", Datax);
  */

  do {
    OSTYPE= ReadData ("OSTYPE", OSTYPE);

    p= ReadData ("EPS", EPS);
    if (strcmp (p, EPS) != 0)
      SetEPS (p);
    EPSBIN= ReadData ("EPSBIN", EPSBIN);
    EPSINC= ReadData ("EPSINC", EPSINC);
    EPSLIB= ReadData ("EPSLIB", EPSLIB);

    CC= ReadData ("CC", CC);
    CF_DBX= ReadData ("CF_DBX", CF_DBX);
    LD_OPTIONS= ReadData ("LD_OPTIONS", LD_OPTIONS);
    LD_LIBRARY_PATH= ReadData ("LD_LIBRARY_PATH", LD_LIBRARY_PATH);

    if (cstrcmp (OSTYPE, "dos") == 0)
      GOXX= ReadData ("GO32", GOXX);
  } while (! Yes (ReadData ("OK", "yes")));
}

void
BackUp (filename)
  char *filename;
{
  FILE *srcfp, *bakfp;
  char *ext;
  static char backfilename[BUFSIZ];

  srcfp= fopen (filename, "r");
  if (srcfp == NULL)
    return;

  (void) strcpy (backfilename, filename);
  ext= strrchr (backfilename, '.');
  if (ext != NULL)
    *ext= '\0';
  (void) strcat (backfilename, ".bak");

  bakfp= fopen (backfilename, "w");
  if (bakfp == NULL) {
    fprintf (stderr, "cannot open %s\n", backfilename);
    return;
  }
  while (fgets (ReadBuffer, sizeof (ReadBuffer), srcfp) != NULL)
    fputs (ReadBuffer, bakfp);
  (void) fclose (srcfp);
  (void) fclose (bakfp);
}

void
DumpData ()
{
  char *prefix;

  if (cstrcmp (OSTYPE, "dos") == 0)
    prefix= "SET ";
  else
    prefix= "";

  fprintf (dfp, "%sOSTYPE=%s\n", prefix, OSTYPE);

  fprintf (dfp, "%sEPS=%s\n", prefix, EPS);
  fprintf (dfp, "%sEPSBIN=%s\n", prefix, EPSBIN);
  fprintf (dfp, "%sEPSINC=%s\n", prefix, EPSINC);
  fprintf (dfp, "%sEPSLIB=%s\n", prefix, EPSLIB);

  if (cstrcmp (OSTYPE, "dos") == 0) {
    fprintf (dfp, "%sCC=%s\n", prefix, CC);
    fprintf (dfp, "%sCF_DBX=%s\n", prefix, CF_DBX);
    fprintf (dfp, "%sLD_OPTIONS=%s\n", prefix, LD_OPTIONS);
    fprintf (dfp, "%sLD_LIBRARY_PATH=%s\n", prefix, LD_LIBRARY_PATH);
    fprintf (dfp, "%sGOXX=%s\n", prefix, GOXX);
  }
  else {
    fprintf (dfp, "%sCC=\"%s\"\n", prefix, CC);
    fprintf (dfp, "%sCF_DBX=\"%s\"\n", prefix, CF_DBX);
    fprintf (dfp, "%sLD_OPTIONS=\"%s\"\n", prefix, LD_OPTIONS);
    fprintf (dfp, "%sLD_LIBRARY_PATH=\"%s\"\n", prefix, LD_LIBRARY_PATH);
  }

  fprintf (dfp, "\n");

  if (cstrcmp (OSTYPE, "dos") != 0) {
    fprintf (dfp, "export OSTYPE\n");
    fprintf (dfp, "export EPS EPSBIN EPSINC EPSLIB\n");
    fprintf (dfp, "export CC CF_DBX LD_OPTIONS LD_LIBRARY_PATH\n");
    fprintf (dfp, "SHELL=/bin/sh\n");
    fprintf (dfp, "export SHELL\n");
    fprintf (dfp, "\n");
  }
}

void
TryIt (package, descr)
  char* package;
  char* descr;
{
  static struct stat sb;

  fprintf (stderr, "  %s (%s):", package, descr);
  (void) sprintf (pathname, "%s/src/%s", EPS, package);
  (void) sprintf (makefilename, "%s/src/%s/Makefile.%s",
		  EPS, package, OSTYPE);
  if (stat (pathname, &sb) >= 0)
    if (S_IFDIR == (sb.st_mode & S_IFMT))  {
      fprintf (dfp, "echo %s ...\n", package);
      if (access (makefilename, R_OK) == 0)
	(void) sprintf (makefilename, "-f Makefile.%s", OSTYPE);
      else
	(void) strcpy (makefilename, "");

      if (cstrcmp (OSTYPE, "dos") == 0) {
        fprintf (dfp, "cd %s\n", pcdir (pathname));
        fprintf (dfp, "make %s install\n", makefilename);
        fprintf (dfp, "cd ..\\..\n");
      }
      else {
	fprintf (dfp, "( ");
	fprintf (dfp, "cd %s; ", pathname);
	fprintf (dfp, "make %s install ", makefilename);
	fprintf (dfp, ")\n");
      }
      fprintf (stderr, " OK\n");
      return;
    }
  fprintf (stderr, " no\n");
}

void
DumpMakes ()
{
  TryIt ("misc", "Miscellaneous");
  TryIt ("cast", "A library to manage CAST (Coloured Abstract Syntax Trees)");
  TryIt ("rag", "Evaluates a coloured CAST");
  TryIt ("lag", "Generates a CAST generator (language processor)");
  TryIt ("alga", "Assembler-Like Grammar trAnslation");
}

void
Gen ()
{
  char *prefix;
  time_t TheTime;
  struct tm *TimeSplit;

  dfp= fopen (DataFile, "w");
  if (dfp == NULL) {
    fprintf (stderr, "cannot open %s\n", DataFile);
    exit (1);
  }

  EPS= nodrive (EPS);
  EPSBIN= nodrive (EPSBIN);
  EPSINC= nodrive (EPSINC);
  EPSLIB= nodrive (EPSLIB);
  GOXX= nodrive (GOXX);

  if (cstrcmp (OSTYPE, "dos") == 0)
    prefix= "REM";
  else
    prefix= "#";

  TheTime= time (NULL);
  TimeSplit= localtime (&TheTime);

  if (cstrcmp (OSTYPE, "dos") == 0)
    fprintf (dfp, "@ECHO OFF\n");
  else
    fprintf (dfp, "#!/bin/sh\n");

  fprintf (dfp, "%s ###########################\n", prefix);
  fprintf (dfp, "%s EPS Configuration File\n", prefix);
  fprintf (dfp, "%s %02d/%02d/%02d %02d:%02d:%02d\n",
	 prefix,
         TimeSplit->tm_year, TimeSplit->tm_mon + 1, TimeSplit->tm_mday,
         TimeSplit->tm_hour, TimeSplit->tm_min, TimeSplit->tm_sec);
  fprintf (dfp, "%s at %s\n", prefix, EPS);
  fprintf (dfp, "%s ###########################\n", prefix);
  fprintf (dfp, "\n");

  DumpData ();
  DumpMakes ();

  fclose (dfp);
}

main (argc, argv)
  int argc;
  char *argv[];
{
  while (argc > 1) {
    if (*argv[1] == '-') {
      if ((cstrcmp (argv[1], "-h"   ) == 0)  ||
          (cstrcmp (argv[1], "-help") == 0)) {
        ptext (stderr, UserHelp);
        exit (0);
      }
      if ((cstrcmp (argv[1], "-v"      ) == 0)  ||
          (cstrcmp (argv[1], "-version") == 0)) {
        (void) fprintf (stderr, "eps1: version %s\n", VERSION);
        exit (0);
      }
      else if ((cstrcmp (argv[1], "-y"  ) == 0)  ||
          (cstrcmp (argv[1], "-yes") == 0)) {
        FlagY++;
      }
      else if (cstrcmp (argv[1], "-data") == 0) {
        DataFile= argv[2];
        argc--; argv++;
      }

      else {
        (void) fprintf (stderr, "eps1: invalid option %s\n", argv[1]);
        ptext (stderr, UserHelp);
        exit (1);
      }
    }
    else {
      (void) fprintf (stderr, "eps1: invalid option %s\n", argv[1]);
      ptext (stderr, UserHelp);
      exit (1);
    }

    argc--;
    argv++;
  }

  InitData ();
  LoadData ();
  AskData ();
  BackUp (DataFile);
  Gen ();

  CreateDir (EPSBIN);
  CreateDir (EPSINC);
  CreateDir (EPSLIB);

  exit (0);
  return 0;
}

