static char *SccsId = "@(#)main.c 4.23 (TU-Delft) 12/01/92";
/**********************************************************

Name/Version      : xsls/4.23

Language          : C
Operating system  : UNIX SYSTEM V
Host machine      : HP9000

Author(s)         : A.J. van Genderen
Creation date     : 16-Feb-1987
Modified by       : A.J. van Genderen
Modification date : 16-Feb-1987


        Delft University of Technology
        Department of Electrical Engineering
        Network Theory Section
        Mekelweg 4 - P.O.Box 5031
        2600 GA DELFT
        The Netherlands

        Phone : 015 - 786234

        COPYRIGHT (C) 1987 , All rights reserved
**********************************************************/
#include <signal.h>
#include "incl.h"
#include <time.h>
#ifdef ESE
#include "eseOption.h"
#include "tversion.h"
#endif

#ifndef ESE
#ifndef XSPICE
#ifdef XEDIF
char *argv0 = "xedif";
char *use_msg = "\nUsage: %s [-efhiv] cell\n\n";
#else
char *argv0 = "xsls";
char *use_msg = "\nUsage: %s [-fhirtv] cell\n\n";
#endif
#else
char *argv0 = "xspice";
char *use_msg = "\nUsage: %s [-afhivElmnptuxy -z name] cell\n\n";
#endif
#else /* ESE */
#ifndef XSPICE
#ifdef XEDIF
char *argv0 = "getedifnet";
char *use_msg = "\nUsage: %s [options] cell\n\n";
#else
char *argv0 = "getsls";
char *use_msg = "\nUsage: %s [options] cell\n\n";
#endif
#else
char *argv0 = "getspice";
char *use_msg = "\nUsage: %s [options] cell\n\n";
#endif
#endif

DM_PROJECT *dmproject = NULL;

FILE *fp_out;
int language;
int dialect;
int incl_model;
int tog_range;
int tog_irange;
int tog_nodnbr;
int tog_comma;
int tog_pnod;
int tog_nnod;
int choosebulk;
int tog_nobrack;
int tog_use0;
int tog_vss0;
int tog_gnd0;
int tog_arrayExpand;
int tog_noPrExt;
int tog_prExt;
int xtree;
int alsoImport;
int globconv;
int verbose;
int listnames;
int usenames;
int ofile;
int eldo;
int noUnconnect;
int cirFlag;
char node0[32];
char *node0ptr;

char **globNets;
int *globNetsCheck;
char **globConA;
char **globConB;
int globNets_cnt;

#define GLOBNETFILE "global_nets"

time_t t;
struct tm *tstruct;

#ifdef ESE
#ifndef XSPICE
#ifdef XEDIF
/* getedifnet */
OptionSpec optionSpecs[] = {
    { "usage", NO, eseHelp, (void *) optionSpecs,
            "-usage:            getedifnet [options] cell\nOptions (may be abbreviated) are:"},
    { "expand", NO, eseTurnOn, (void *) & tog_arrayExpand ,
            "    -expand:           expand array names into single names "  },
    { "file", NO, eseTurnOn, (void *) & ofile,
            "    -file:             send output to file 'cell.edif'"  },
    { "hierarchy", NO, eseTurnOn, (void *) & xtree,
            "    -hierarchy:        also retrieve all (local) sub-cells"  },
    { "imported", NO, eseTurnOn, (void *) & alsoImport,
            "    -imported:         also retrieve all imported sub-cells"  },
    { "verbose", NO, eseTurnOn, (void *) & verbose,
            "    -verbose:          print run-time information" },
    { "%etext", NO, eseText, (void *) NULL,
            "    -%etext:           print the '(int) & etext' number" },
    { "%help", NO, eseHelpAll, (void *) optionSpecs,
            "    -%help:            print this list" },
    { "help", NO, eseHelp, (void *) optionSpecs,
            "    -help:             print this list" },
    { "release", NO, esePrintString, (void *) TOOLVERSION,
            "    -release:          print the release number of this tool"},
    { (char *) 0, (char) 0, (IFP) 0, (void *) 0, (char *) 0 },
};
#else
/* getsls */
OptionSpec optionSpecs[] = {
    { "usage", NO, eseHelp, (void *) optionSpecs,
            "-usage:            getsls [options] cell\nOptions (may be abbreviated) are:"},
    { "file", NO, eseTurnOn, (void *) & ofile,
            "    -file:             send output to file 'cell.sls'"  },
    { "filter", NO, eseTurnOn, (void *) & noUnconnect,
            "    -filter:           do not output unconnected instances"  },
    /*
    { "global", NO, eseTurnOn, (void *) & globconv,
            "    -global:           convert global nets to strictly hierarchical format"  },
    */
    { "hierarchy", NO, eseTurnOn, (void *) & xtree,
            "    -hierarchy:        also retrieve all (local) sub-cells"  },
    { "imported", NO, eseTurnOn, (void *) & alsoImport,
            "    -imported:         also retrieve all imported sub-cells"  },
    { "noextern", NO, eseTurnOn, (void *) & tog_noPrExt,
            "    -noextern:         do not include extern network definitions"  },
    { "verbose", NO, eseTurnOn, (void *) & verbose,
            "    -verbose:          print run-time information" },
    { "%etext", NO, eseText, (void *) NULL,
            "    -%etext:           print the '(int) & etext' number" },
    { "%help", NO, eseHelpAll, (void *) optionSpecs,
            "    -%help:            print this list" },
    { "help", NO, eseHelp, (void *) optionSpecs,
            "    -help:             print this list" },
    { "release", NO, esePrintString, (void *) TOOLVERSION,
            "    -release:          print the release number of this tool"},
    { (char *) 0, (char) 0, (IFP) 0, (void *) 0, (char *) 0 },
};
#endif
#else
/* getspice */
OptionSpec optionSpecs[] = {
    { "usage", NO, eseHelp, (void *) optionSpecs,
            "-usage:            getspice [options] cell\nOptions (may be abbreviated) are:"},
    { "eldo", NO, eseTurnOn, (void *) & eldo,
            "    -eldo:             generate output for eldo simulator"  },
    { "file", NO, eseTurnOn, (void *) & ofile,
            "    -file:             send output to file 'cell.spc'"  },
    { "filter", NO, eseTurnOn, (void *) & noUnconnect,
            "    -filter:           do not output unconnected instances"  },
    { "hierarchy", NO, eseTurnOn, (void *) & xtree,
            "    -hierarchy:        also retrieve all (local) sub-cells"  },
    { "imported", NO, eseTurnOn, (void *) & alsoImport,
            "    -imported:         also retrieve all imported sub-cells"  },
    { "%etext", NO, eseText, (void *) NULL,
            "    -%etext:           print the '(int) & etext' number" },
    { "%namelist", NO, eseTurnOn, (void *) & listnames,
            "    -%namelist:        generate a name list for the node numbers in the circuit" },
    { "names", NO, eseTurnOn, (void *) & usenames,
            "    -names:            use node names in the circuit description" },
    { "nomodels", NO, eseTurnOff, (void *) & incl_model,
            "    -nomodels:         exclude device model definitions from the output file" },
    { "%nonbulk", NO, eseTurnOff, (void *) & tog_nnod,
            "    -%nonbulk:         exclude terminals for n-bulk connections" },
    { "%nopbulk", NO, eseTurnOn, (void *) & tog_pnod,
            "    -%nopbulk:         exclude terminals for p-bulk connections" },
    { "noautobulk", NO, eseTurnOff, (void *) & choosebulk, 
	    "    -noautobulk:       do not atomatically infer need for p- & n-bulk connections" },
    { "verbose", NO, eseTurnOn, (void *) & verbose,
            "    -verbose:          print run-time information" },
    { "gnd", NO, eseTurnOn, (void *) & tog_gnd0,
            "    -gnd:              replace node names starting with 'gnd' or 'GND' by '0'" },
    { "vss", NO, eseTurnOn, (void *) & tog_vss0,
            "    -vss:              replace node names starting with 'vss' or 'VSS' by '0'" },
    { "nilprefix", YES, eseAssignArgument, (void *) &node0ptr,
            "    -nilprefix prefix: replace node names starting with 'prefix' by '0'" },
    { "%help", NO, eseHelpAll, (void *) optionSpecs,
            "    -%help:            print this list" },
    { "help", NO, eseHelp, (void *) optionSpecs,
            "    -help:             print this list" },
    { "release", NO, esePrintString, (void *) TOOLVERSION,
            "    -release:          print the release number of this tool"},
    { (char *) 0, (char) 0, (IFP) 0, (void *) 0, (char *) 0 },
};
#endif
#endif


main (argc, argv)
int argc;
char *argv[];
{
    char *s;
    char *network;
    char ofname[BUFSIZ];
    char edifline[BUFSIZ];
    struct cir *cl;
    struct cir *cirTree ();
    struct cir *locateTopCell ();

    xtree = 0;
    alsoImport = 0;
    globconv = 0;
    verbose = 0;
    listnames = 0;
    usenames = 0;
#ifdef ESE
#ifdef XSPICE
    incl_model = 1;
#else
    incl_model = 0;
#endif
#else
    incl_model = 0;
#endif
    eldo = 0;
    ofile = 0;
    network = NULL;
    noUnconnect = 0;
    cirFlag = 0;
#ifdef XSPICE
    language = SPICE;
    dialect = SPICE;
#else
#ifdef XEDIF
    language = EDIF;
#else
    language = SLS;
#endif
#endif
    tog_noPrExt = 0;

    tog_arrayExpand = 0;
    tog_use0 = 0;
    tog_gnd0 = 0;
    tog_vss0 = 0;
    tog_pnod = 0;
    tog_nnod = 0;
    choosebulk = 1;    /* this options has been improved; turn it on always ! */
    node0[0] = '\0';
    node0ptr = NULL;

#ifndef ESE
    while (--argc > 0) {
        if ((*++argv)[0] == '-' ) {
	    for (s = *argv + 1; *s != '\0'; s++) {
	        switch (*s) {
		    case 'E':
			language = SPICE;
			dialect = ESPICE;
			break;
		    case 'S':
			language = SPICE;
			dialect = SPICE;
			break;
		    case 'M':
			language = SIMON;
			break;
		    case 'F':
			language = EDIF;
			break;
		    case 'a':
			usenames = 1;
			break;
		    case 'e':
			tog_arrayExpand = 1;
			break;
		    case 'f':
			ofile = 1;
			break;
		    /*
		    case 'g':
			globconv = 1;
			break;
		    */
		    case 'h':
			xtree = 1;
			break;
		    case 'i':
			alsoImport = 1;
			break;
		    case 'l':
			listnames = 1;
			break;
		    case 'm':
			incl_model = 1;
			break;
		    case 'n':
			tog_nnod = 1;
			break;
		    case 'p':
			tog_pnod = 1;
			break;
		    case 'b':
			choosebulk = 1;
			break;
		    case 'r':
			tog_noPrExt = 1;
			break;
		    case 't':
			noUnconnect = 1;
			break;
		    case 'u':
			choosebulk = 0;
			break;
		    case 'v':
			verbose = 1;
			break;
		    case 'x':
			tog_gnd0 = 1;
			break;
		    case 'y':
			tog_vss0 = 1;
			break;
		    case 'z':
			if (*(s + 1) != '\0' 
			|| --argc <= 0
			|| sscanf (*++argv, "%s", node0) != 1) {
			    fprintf (stderr, use_msg, argv0);
			    exit (1);
			}
			break;
		    default: 
		        fprintf (stderr, 
				 "%s: illegal option: %c\n", argv0, *s);
		        exit (1);
	        }
	    }
	}
	else {
            if (network == NULL) {
		network = *argv;
	    }
	    else {
		fprintf (stderr, use_msg, argv0);
		exit (1);
	    }
	}
    }
    if (network == NULL) {
	fprintf (stderr, use_msg, argv0);
	exit (1);
    }
    if (language == EDIF && globconv) {
	fprintf (stderr, 
		 "\nwarning: option -g has no effect for EDIF netlists\n\n");
    }
#else
    if (eseOptionHandler (argc, argv, optionSpecs, 1, &network) > 0 ||
            network == NULL) {
	fprintf (stderr, use_msg, argv0);
	exit (1);
    }

    if (node0ptr) 
	strcpy (node0, node0ptr);
#endif

    dmInit (argv0);
    dmproject = dmOpenProject (DEFAULT_PROJECT, PROJ_READ);

    initIntrup ();

#if NCF_RELEASE >= 400

#define FUNCTIONAL "functional"
    {

	/* Unfortunately, 

	if ((int)dmGetMetaDesignData (EXISTVIEW, dmproject, FUNCTIONAL) != 1) {
        }

	   does not work since it calls dmError if the view does not exist.
	*/

        data **view_list;
        int view_entry;
        int exist_funcview = 0;

	view_list = dmproject -> views;
	for (view_entry = 0; view_list[view_entry] != NULL; ++view_entry) {
	    if (strcmp (FUNCTIONAL, view_list[view_entry][0].point) == 0) {
                exist_funcview = 1;
	    }
	}
	if (!exist_funcview) {
	    cirFlag = 1;    /* circuit view only mode, for old projects */
        }
    }
#endif

    if (ofile) {
	switch (language) {
	    case SLS:
		sprintf (ofname, "%s.sls", network);
		break;
	    case SPICE:
		if (dialect == ESPICE)
		    sprintf (ofname, "%s.esp", network);
		else
		    sprintf (ofname, "%s.spc", network);
		break;
	    case SIMON:
		sprintf (ofname, "%s.sim", network);
		break;
	    case EDIF:
		sprintf (ofname, "%s.edif", network);
		break;
	}
	OPENW (fp_out, ofname);
    }
    else {
	fp_out = stdout;
    }

    tog_prExt = 0;
    tog_use0 = 0;

    switch (language) {
	case SLS:
	    tog_range = 1;
	    tog_irange = 1;
	    tog_nodnbr = 0;
	    tog_comma = 1;
	    tog_pnod = 0;
	    tog_nnod = 0;
	    tog_nobrack = 0;
	    tog_prExt = !tog_noPrExt;
	    break;
	case SPICE:
	    if (eldo) 
		usenames = 1;
	    tog_range = 0;
	    tog_irange = 0;
	    if (usenames)
		tog_nodnbr = 0;
	    else
		tog_nodnbr = 1;
	    tog_comma = 0;
	    tog_nobrack = 1;
	    if (tog_gnd0 || tog_vss0 || node0[0] != '\0') {
		tog_use0 = 1;
	    }
	    break;
	case SIMON:
	    tog_range = 0;
	    tog_irange = 0;
	    tog_nodnbr = 0;
	    tog_comma = 1;
	    tog_nobrack = 1;
	    break;
	case EDIF:
	    if (tog_arrayExpand) {
		tog_range = 0;
		tog_irange = 0;
	        tog_nobrack = 1;
	    }
	    else {
		tog_range = 1;
		tog_irange = 1;
	        tog_nobrack = 0;
	    }
	    tog_nodnbr = 0;
	    tog_comma = 0;
	    tog_pnod = 0;
	    tog_nnod = 0;
	    noUnconnect = 0;  /* not implemented for EDIF */
	    break;
    }

    /* This is not the current strategy. Instead, global nets 
       are handled by database input tools (e.g. sls_mkdb).
    if (language == SPICE || language == SLS && globconv) {
	readGlobalNets ();
    }
    else
    */
    globNets_cnt = 0;

    initDevs ();

    initFuncs ();

    if (language == SPICE) {
	oprint (0, network);
	oprint (0, "\n");
    }
    if (language == SIMON) {
	oprint (0, "\n");
	oprint (0, "/data net");
	oprint (0, "\n");
    }
    if (language == EDIF) {
        oprint (0, "(EDIF EDIFFILENAME\n");
        oprint (0, "(EDIFVersion 2 0 0)\n");
        oprint (0, "(EDIFLevel 0)\n");
        oprint (0, "(keywordMap\n");
        oprint (0, "(keywordLevel 0))\n");
        oprint (0, "(status\n");
        oprint (0, "(written\n");
	time (&t);
	tstruct = localtime (&t);
	sprintf (edifline, "(timeStamp 19%d %d %d %d %d %d)\n", 
		 tstruct -> tm_year , tstruct -> tm_mon+1, 
		 tstruct -> tm_mday, tstruct -> tm_hour, 
		 tstruct -> tm_min, tstruct -> tm_sec);
        oprint (0, edifline);
#ifdef ESE
        oprint (0, "(author \"ESE Electronic Systems Engineering\")\n");
	sprintf (edifline, "(program \"%s %s  11:21:28\") \n", 
		 argv0, TOOLVERSION);
        oprint (0, edifline);
#else
        oprint (0, "(author \"Dimes Design and Test Centre\")\n");
	sprintf (edifline, "(program \"%s 4.23  11:21:28\") \n", argv0);
        oprint (0, edifline);
#endif
        oprint (0, "))\n");
    }


    if (xtree) {
	cl = cirTree (network);

        if (language == SPICE && (choosebulk || incl_model))
            interDevs ();

	if (language == EDIF) {
	    printDevs ();
	}

	if (tog_prExt) {
	    prExt ();
	}

	if (language == EDIF) {
	    oprint (0, "(library LIBRARYNAME\n");
	    oprint (0, "(ediflevel 0)\n");
	    oprint (0, "(technology\n");
	    oprint (0, "(numberDefinition))\n");
	}

	while (cl != NULL) {
	    if (verbose) {
		fprintf (stderr, "Extracting %s\n", cl -> name);
	    }
	    if (cl -> next == NULL)
		xnetwork (cl -> name, cl -> proj, cl -> imported,
			  cl -> orig_name, 0, listnames);
	    else
		xnetwork (cl -> name, cl -> proj, cl -> imported,
			  cl -> orig_name, 1, listnames);
	    cl = cl -> next;
	}
    }
    else {
	cl = locateTopCell (network);

        if (language == SPICE && (choosebulk || incl_model)) {
            scanInst (cl -> orig_name, 1, cl -> proj);
            interDevs ();
        }

	if (language == EDIF) {
            scanInst (cl -> orig_name, 1, cl -> proj);
	    printDevs ();
	}

	if (tog_prExt) {
            scanInst (cl -> orig_name, 1, cl -> proj);
	    prExt ();
	}

	if (language == EDIF) {
	    oprint (0, "(library LIBRARYNAME\n");
	    oprint (0, "(ediflevel 0)\n");
	    oprint (0, "(technology\n");
	    oprint (0, "(numberDefinition))\n");
	}

	if (verbose) {
	    fprintf (stderr, "Extracting %s\n", network);
	}

	xnetwork (cl -> name, cl -> proj, cl -> imported,
		  cl -> orig_name, 0, listnames);
    }

    if (language == EDIF) {
	oprint (0, ")");
    }

    if (language != EDIF) {
	prImpFunc ();
        prImpNetw ();  /* should actually be placed before xnetwork;
			  but then it is not (yet) working correctly */
	prImpDev ();
    }

    if (language == SIMON) {
	oprint (0, "\n");
	oprint (0, "/*");
	oprint (0, "\n");
    }

    if (language == EDIF) {
	oprint (0, ")");
    }

    oprint (0, "\n");  /* to empty the buffer */

    if (language == EDIF)
        fprintf (fp_out, "\n");

    endDevs ();

    if (dmproject) dmCloseProject (dmproject, COMPLETE);
    dmQuit ();

    return (0);
}

readGlobalNets ()
{
    FILE *fp;
    int cnt;
    int i;
    char *fn;
    char buf[128];

    fp = fopen (GLOBNETFILE, "r");
    if (fp == NULL) {
        fn = (char *)dmGetMetaDesignData (PROCPATH, dmproject, GLOBNETFILE);
	fp = fopen (fn, "r");
    }

    if (fp) {

	cnt = 0;
	while (fscanf (fp, "%s", buf) > 0) {
	    cnt++;
	}
	rewind (fp);

	PALLOC (globNets, cnt, char *);
	PALLOC (globNetsCheck, cnt, int);
	PALLOC (globConA, cnt, char *);
	PALLOC (globConB, cnt, char *);

	cnt = 0;
	while (fscanf (fp, "%s", buf) > 0) {
	    for (i = 0; i < globNets_cnt; i++) {
		if (strcmp (globNets[i], buf) == 0)
		    break;   /* double specification of this global net */
	    }
	    if (i == globNets_cnt) {
		PALLOC (globNets[cnt], strlen (buf) + 1, char);
		strcpy (globNets[cnt], buf);
		cnt++;
	    }
	}
	globNets_cnt = cnt;

	fclose (fp);
    }
    else {
	globNets_cnt = 0;
    }
}

fatalErr (s1, s2) 
char *s1, *s2;
{
    fprintf (stderr, "%s: ", argv0);

    if (s1 && *s1 != '\0') {
	fprintf (stderr, "%s", s1);
    }

    if (s2 && *s2 != '\0') {
	fprintf (stderr, " %s", s2);
    }

    fprintf (stderr, "\n");

    die ();
}

initIntrup ()
{
    int int_hdl ();

    if (signal (SIGINT, SIG_IGN) != SIG_IGN)   
        signal (SIGINT, int_hdl);
        /* only when value was not SIG_IGN, a jump must be done to int_hdl */
    if (signal (SIGQUIT, SIG_IGN) != SIG_IGN)
        signal (SIGQUIT, int_hdl);
        /* only when value was not SIG_IGN, a jump must be done to int_hdl */
    signal (SIGTERM, int_hdl);
    signal (SIGILL, int_hdl);
    signal (SIGFPE, int_hdl);
#ifdef SIGBUS /* [ps] */
    signal (SIGBUS, int_hdl);
#endif
    signal (SIGSEGV, int_hdl);
}

int_hdl (sig)   /* interrupt handler */
int sig;
{
    switch (sig) {
        case SIGILL :
            fprintf (stderr, "Illegal instruction\n");
            break;
        case SIGFPE :
            fprintf (stderr, "Floating point exception\n");
            break;
#ifdef SIGBUS /* [ps] */
        case SIGBUS :
            fprintf (stderr, "Bus error\n");
            break;
#endif
        case SIGSEGV :
            fprintf (stderr, "Segmentation violation\n");
            break;
        default :
            break;
    }

    die ();
}

dmError (s)
char *s;
{
    dmPerror (s);
    die ();
}

die () 
{
    if (dmproject) dmCloseProject (dmproject, COMPLETE);
    dmQuit ();
    exit (1);
}
