/***********************************
  (C) Copyright 1993; dit/upm
   Distributed under the conditions stated in the
   TOPO General Public License (see file LICENSE)
 ***********************************
 $Log: toposet.c,v $
 * Revision 2.11  1994/12/19  15:11:02  lotos
 * prototypes integrated into topo
 * new pieces convention, and integrated into topo
 * clean objects
 *
 * Revision 2.10  1994/11/22  15:07:15  lotos
 * compatibility with lola for reusage
 *
 * Revision 2.9  1994/07/19  18:40:58  lotos
 * remove standard library automatic recompilation
 *
 * Revision 2.8  1993/09/30  13:17:15  lotos
 * context file may be explicit
 * options are options (order is not relevant)
 *
 * Revision 2.7  1993/07/08  18:07:52  lotos
 * fix a loop in -noglad
 *
 * Revision 2.6  1993/07/08  17:40:53  lotos
 * add option -noglad
 *
 * Revision 2.5  1993/07/01  19:19:00  lotos
 * forward -verbose to library actualization
 *
 * Revision 2.4  1993/06/24  09:20:14  lotos
 * Ada cleaning
 *
 * Revision 2.3  1993/06/23  16:06:35  lotos
 * new option -verbose
 *
 * Revision 2.2  1993/06/15  12:51:12  lotos
 * fix behaviour when there is a single argument (e.g. toposet pc)
 *
 * Revision 2.1  1993/06/10  14:10:24  lotos
 * extract context common part
 * extract C and Ada generation and cleaning functions
 * lots of bugs fixed
 *
 * Revision 1.4  1993/02/23  17:03:53  lotos
 * fix minor details to port to pc
 *
 * Revision 1.3  1993/02/22  16:09:58  lotos
 * better code,
 * bug fixing
 * revise library actualizacion criteria
 * add ditupm as one more standard library
 *
 * Revision 1.2  1993/02/17  14:32:26  lotos
 * code directly a case independent string comparator
 * make it portable to MS-DOS
 * add Arturo's library
 * add file remotion in ADA
 * allow '^# comments' in spec.ctx
 * bug fixing
 *
 * Revision 1.1  1993/01/25  15:23:46  lotos
 * Initial revision
 *
 ***********************************/

#ifndef lint
static char rcsid[]= "$Id: toposet.c,v 2.11 1994/12/19 15:11:02 lotos Exp $";
#endif

#include "context.h"

PRIVATE char D_LANGUAGE[VSIZE]=	"-";
PRIVATE char D_LIB[VSIZE]=	"-";
PRIVATE char D_TNAME[VSIZE]=	"-";
PRIVATE char D_DNAME[VSIZE]=	"-";
PRIVATE char D_TPCS[VSIZE]=	"-";
PRIVATE char D_DPCS[VSIZE]=	"-";
PRIVATE char D_GLDLIB[VSIZE]=	"-";
PRIVATE char D_MAKEFILE[VSIZE]=	"-";

PRIVATE void help ();
PRIVATE int cstrcmp ();
PRIVATE void update ();
PRIVATE void CleanBehaviour ();
PRIVATE void CleanData ();
PRIVATE void CleanObject ();

char* getenv ();

PRIVATE int List= FALSE;
PRIVATE char oldvalue[VSIZE];

PRIVATE int
next (argc, argv)
  int argc;
  char* argv[];
{
  if (argc < 3)
    return FALSE;
  if (argv[2][0] == '-')
    return FALSE;
  return TRUE;
}

PRIVATE void
setlib (newlib)
  char* newlib;
{
  (void) strcpy (oldvalue, LIB);

  if (strcmp (newlib, "") == 0) {
    (void) strcpy (LIB, "");
  }
  else {
    (void) sprintf (filename, "%s.lot", newlib);
    if (read_ok (filename)) {
      (void) strcpy (LIB, newlib);
    }
    else {
      (void) sprintf (filename, "%s.ls", newlib);
      if (read_ok (filename)) {
	(void) strcpy (LIB, newlib);
      }
      else {
	(void) sprintf (filename, "%s%c%s.ls", TOPOSTDLIB, DIRSEP, newlib);
	if (read_ok (filename)) {
	  (void) sprintf (filename, "%s%c%s", TOPOSTDLIB, DIRSEP, newlib);
	  (void) strcpy (LIB, filename);
	  if (FlagVerbose)
	    (void) fprintf (stderr, "Library %s\n", LIB);
	}
	else {
	  (void) fprintf (stderr, "unknown library: -l %s\n", newlib);
	  exit (1);
	}
      }
    }
  }

  if (strcmp (oldvalue, LIB) != 0) {
    Modified= TRUE;
    if (FlagVerbose)
      (void) fprintf (stderr, "remove %s.ls %s.lss %s.lsf %s.lsc %s.lcr\n",
	       SPEC, SPEC, SPEC, SPEC, SPEC);
    (void) sprintf (filename, "%s.ls", SPEC);
    (void) unlink (filename);
    (void) sprintf (filename, "%s.lss", SPEC);
    (void) unlink (filename);
    (void) sprintf (filename, "%s.lsf", SPEC);
    (void) unlink (filename);
    (void) sprintf (filename, "%s.lsc", SPEC);
    (void) unlink (filename);
    (void) sprintf (filename, "%s.lcr", SPEC);
    (void) unlink (filename);
  }
}

typedef enum option {
  opthelp, list, verbose,
  context, make,
  language, library, nolibrary,
  glad, noglad,
  tname, tpieces, dname, dpieces,
  noopt, unknown
} option;

PRIVATE struct {
  char*   keyword;
  option  kopt;
} kwtable [] = {
  "-context",	context,
  "-do",	dname,
  "-dname",	dname,
  "-dn",	dpieces,
  "-dpieces",	dpieces,
  "-glad",	glad,
  "-h",		opthelp,
  "-help",	opthelp,
  "-g",		language,
  "-language",	language,
  "-l",		library,
  "-library",	library,
  "-list",	list,
  "-make",	make,
  "-noglad",	noglad,
  "-nolib",	nolibrary,
  "-nolibrary",	nolibrary,
  "-to",	tname,
  "-tname",	tname,
  "-tn",	tpieces,
  "-tpieces",	tpieces,
  "-v",		verbose,
  "-verbose",	verbose,
  NULL
};

PRIVATE option
Classify (arg)
  char* arg;
{
  int i;

  if (arg == NULL)
    return noopt;
  for (i= 0; kwtable[i].keyword != NULL; i++)
    if (cstrcmp (arg, kwtable[i].keyword) == 0)
      return kwtable[i].kopt;
  if (*arg == '-')
    return unknown;
  return noopt;
}

#ifdef LOLACODE
toposetmain (argc, argv)
#else
/* KJT 20/01/23: added "int" type */
int main (argc, argv)
#endif
  int argc;
  char* argv[];
{
  char* s;

  read_env ();

  if (argc == 1) {
    help ();
    exit (0);
  }

  switch (Classify (argv[1])) {
  case noopt:
    break;
  case opthelp:
    help ();
    exit (0);
  case unknown:
    (void) fprintf (stderr, "unknown option %s\n", argv[1]);
  default:
    help ();
    exit (1);
  }

  (void) strcpy (SPEC, argv[1]);
  if (s= strrchr (SPEC, '.')) {
    if (strcmp (s, ".lot") == 0)
      *s= '\0';
  }
  shift;

  while (argc > 1) {
    switch (Classify (argv[1])) {

    case opthelp:
      help ();
      exit (0);

    case list:
      List= TRUE;
      shift;
      break;

    case verbose:
      FlagVerbose= TRUE;
      shift;
      break;

    case context:
      if (! next (argc, argv)) {
	(void) fprintf (stderr, "option -context requires one argument\n");
	exit (1);
      }
      (void) strcpy (CONTEXT, argv[2]);
      if ((s= strchr (CONTEXT, '.')) != 0) {
	if (strcmp (s, ".ctx") == 0)
	  *s= '\0';
      }
      shift; shift;
      break;

    case make:
      if (! next (argc, argv)) {
	(void) fprintf (stderr, "option -make requires one argument\n");
	exit (1);
      }
      (void) strcpy (D_MAKEFILE, argv[2]);
      shift; shift;
      break;

    case language:
      if (! next (argc, argv)) {
	(void) fprintf (stderr, "option -language requires one argument\n");
	exit (1);
      }
      if (cstrcmp (argv[2], "c") == 0)
	(void) strcpy (D_LANGUAGE, "C");
      else if (cstrcmp (argv[2], "ada") == 0)
	(void) strcpy (D_LANGUAGE, "ADA");
      else {
	(void) fprintf (stderr, "unknown language: -language %s\n", argv[2]);
	exit (1);
      }
      shift; shift;
      break;

    case nolibrary:
      (void) strcpy (D_LIB, "");
      shift;
      break;

    case library:
      if (next (argc, argv)) {
	(void) strcpy (D_LIB, argv[2]);
	shift;
      }
      else
	(void) strcpy (D_LIB, "");
      shift;
      break;

    case tname:
      if (! next (argc, argv)) {
	(void) fprintf (stderr, "option -tname requires one argument\n");
	exit (1);
      }
      (void) strcpy (D_TNAME, argv[2]);
      shift; shift;
      break;

    case dname:
      if (! next (argc, argv)) {
	(void) fprintf (stderr, "option -dname requires one argument\n");
	exit (1);
      }
      (void) strcpy (D_DNAME, argv[2]);
      shift; shift;
      break;

    case noglad:
      (void) strcpy (D_GLDLIB, "");
      shift;
      break;

    case glad:
      if (! next (argc, argv)) {
	(void) fprintf (stderr, "option -glad requires one argument\n");
	exit (1);
      }
      (void) strcpy (D_GLDLIB, argv[2]);
      shift; shift;
      break;

    case tpieces:
      if (! next (argc, argv)) {
	(void) fprintf (stderr, "option -tpieces requires one argument\n");
	exit (1);
      }
      (void) strcpy (D_TPCS, argv[2]);
      shift; shift;
      break;

    case dpieces:
      if (! next (argc, argv)) {
	(void) fprintf (stderr, "option -dpieces requires one argument\n");
	exit (1);
      }
      (void) strcpy (D_DPCS, argv[2]);
      shift; shift;
      break;

    case unknown:
      (void) fprintf (stderr, "unknown option %s\n", argv[1]);
      help ();
      exit (1);

    default:
      (void) fprintf (stderr, "I do not understand %s\n", argv[1]);
      help ();
      exit (1);
    }
  }

  read_ctx ();
  update ();
  write_ctx ();
  if (List)
    list_ctx (stdout);
#ifndef LOLACODE
  exit (0);
#endif
  return 0;
}

PRIVATE char* HelpText[]= {
  "usage: toposet SPEC [ options ] ...",
  "       options:",
  "         -context F    use file F.ctx as context [SPEC.ctx]",
  "         -list         list current options",
  "         -verbose      echo activity",
  "         -tname NAME   generates NAME.{hh,c} [lbc.{hh,c}]",
  "         -dname NAME   generates NAME.{hh,c} [ldc.{hh,c}]",
  "         -tpieces #    breaks the C code into # pieces (for behaviour)",
  "         -dpieces #    breaks the C code into # pieces (for data)",
  "         -glad #       data types annotations",
  "         -noglad       do not use any glad library (default)",
  "         -make F       use F as makefile",
  "         -language G   generates language G",
  "           C           C language (default)",
  "           ADA         ADA language",
  "         -nolibrary    use no standard library (default)",
  "         -library L    'standard' library L",
  "           minimal       only booleans",
  "           ditupm        improved and extended IS library",
  "           is            IS standard library",
  "           is-neq        IS standard library (equations removed)",
  "           mod-is        (L4 modified) IS",
  "           mod-is-neq    (L4 modified) IS (equations removed)",
  "           bool_nat      simplification: Bools and Nats",
#ifdef MSDOS
  "           <>            user defined at ./<>.ls",
#else
  "           <>            user defined at ./<>.ls",
#endif
  NULL
};

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

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

PRIVATE void
help ()
{
  ptext (stderr, HelpText);
}

PRIVATE 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;
}

PRIVATE void
update ()
{
  if (strcmp (D_LANGUAGE, "-") != 0 && strcmp (LANGUAGE, D_LANGUAGE) != 0) {
    (void) strcpy (LANGUAGE, D_LANGUAGE);
    Modified= TRUE;
  }

  if (strcmp (D_LIB, "-") != 0 && strcmp (LIB, D_LIB) != 0) {
    setlib (D_LIB);
    Modified= TRUE;
  }

  if (strcmp (D_TNAME, "-") != 0 && strcmp (TNAME, D_TNAME) != 0) {
    CleanBehaviour ();
    CleanObject ();
    (void) strcpy (TNAME, D_TNAME);
    Modified= TRUE;
  }

  if (strcmp (D_DNAME, "-") != 0 && strcmp (DNAME, D_DNAME) != 0) {
    CleanData ();
    CleanObject ();
    (void) strcpy (DNAME, D_DNAME);
    Modified= TRUE;
  }

  if (strcmp (D_GLDLIB, "-") != 0 && strcmp (GLDLIB, D_GLDLIB) != 0) {
    if (FlagVerbose)
      (void) fprintf (stderr, "remove %s.agf %s.aif\n", SPEC, SPEC);
    (void) sprintf (filename, "%s.agf", SPEC);
    (void) unlink (filename);
    (void) sprintf (filename, "%s.aif", SPEC);
    (void) unlink (filename);
    (void) strcpy (GLDLIB, D_GLDLIB);
    Modified= TRUE;
  }

  if (strcmp (D_TPCS, "-") != 0 && strcmp (TPCS, D_TPCS) != 0) {
    CleanBehaviour ();
    CleanObject ();
    (void) strcpy (TPCS, D_TPCS);
    Modified= TRUE;
  }

  if (strcmp (D_DPCS, "-") != 0 && strcmp (DPCS, D_DPCS) != 0) {
    CleanData ();
    CleanObject ();
    (void) strcpy (DPCS, D_DPCS);
    Modified= TRUE;
  }

  if (strcmp (D_MAKEFILE, "-") != 0 && strcmp (MAKEFILE, D_MAKEFILE) != 0) {
    CleanBehaviour ();
    CleanData ();
    CleanObject ();
    (void) strcpy (MAKEFILE, D_MAKEFILE);
    Modified= TRUE;
  }

}

PRIVATE void
CleanBehaviour ()
{
  Modified= TRUE;
  if (strcmp (LANGUAGE, "C") == 0)
    CCleanBehaviour ();
  else /* ADA */
    AdaCleanBehaviour ();
}

PRIVATE void
CleanData ()
{
  Modified= TRUE;
  if (strcmp (LANGUAGE, "C") == 0)
    CCleanData ();
  else /* ADA */
    AdaCleanData ();
}

PRIVATE void
CleanObject ()
{
  Modified= TRUE;
  if (strcmp (LANGUAGE, "C") == 0)
    CCleanObject ();
  else /* ADA */
    AdaCleanObject ();
}

