static char *SccsId = "@(#)main.c 4.11 (TU-Delft) 04/16/93";
/**********************************************************

Name/Version      : makegln/4.11

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

Author            : N.P. van der Meijs
Creation date     : 15-Mar-1988
Modified by       : S. de Graaf
Modification date : 20-Jul-1990


        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) 1988. All rights reserved.
**********************************************************/
#include "config.h"
#include <stdio.h>
#include <ctype.h>
#include "aux/aux.h"
#include "makegln.h"
#include "dmincl.h"
#ifdef ESE
#include "eseOption.h"
#include "tversion.h"
#endif


DM_CELL          * cellKey;
DM_PROCDATA      * process;
DM_PROJECT       * dmproject;

bool_t optVerbose  = FALSE;
bool_t optNoDelete = TRUE;
bool_t optCompress = TRUE;
bool_t optInfo     = FALSE;
bool_t optSortOnly = FALSE;
bool_t optNoOutput = FALSE;
bool_t optSpecial  = FALSE;
char * maskNot     = NULL;
char * maskOnly    = NULL;
char * maxMemString    = NULL;
char ** cellNames    = NULL;

int    optMaxMemory = 1024*1024;	/* Default 1 Mbyte */

static char * currentCell = NULL;

extern char * argv0;


#ifdef ESE
OptionSpec optionSpecs[] = {
    { "usage", NO, eseHelp, (void *) optionSpecs,
            "-usage:     mkgln [options] cell [...]\nOptions (may be abbreviated) are:"},
    { "%etext", NO, eseText, (void *) NULL,
            "    -%etext:              print the '(int) & etext' number" },
    { "%help", NO, eseHelpAll, (void *) optionSpecs,
            "    -%help:               print this list" },
    { "release", NO, esePrintString, (void *) TOOLVERSION,
            "    -release:             print the release number of this tool"},
    { "help", NO, eseHelp, (void *) optionSpecs,
            "    -help:                print this list" },
    { "%notmasks", YES, eseAssignArgument, (void *) & maskNot,
            "    -%notmasks  masklist:  do not process masks in comma-separated masklist" },
    { "%onlymasks", YES, eseAssignArgument, (void *) & maskOnly,
            "    -%onlymasks  masklist: process only the masks in comma-separated masklist" },
    { "%noretain", NO, eseTurnOff, (void *) & optNoDelete,
            "    -%noretain:           do not retain the _bxx files" },
    { "verbose", NO, eseTurnOn, (void *) & optVerbose,
            "    -verbose:             print run-time information" },
    { "%memory", YES, eseAssignArgument, (void *) & maxMemString, 
            "    -%memory:            set maximum size of the memory in Megabytes" },
    { "%info", NO, eseTurnOn, (void *) & optInfo, 
            "    -%info:              print statistics info and verbose info" },
    { (char *) 0, (char) 0, (IFP) 0, (void *) 0, (char *) 0 },
};
#endif

main (argc, argv)
int     argc;
char  **argv;
{
    extern int    optind;
    extern char * optarg;
    extern char * strrchr ();
    extern char * strfind ();
    extern double atof ();

    int     c, errflg = 0;
    double     maxMem = 0.0;	/* megabytes of sort buffer memory */
    char  * version = WORKING;	/* default version */
    char  * optstring;

#ifndef ESE
    argv0 = strrchr (argv[0], '/') ? strrchr (argv[0], '/') + 1 : argv[0];
#else
    argv0 = "mkgln";
#endif

    catchSignals ();

 /* evaluate all flags and filenames */

#ifndef ESE
    if (argc > 1 && argv[1][0] == '-' && argv[1][1] == '%')
	optstring = "%o:n:vDm:ciSN";
    else
	optstring = "o:n:vDm:c";

    while ((c = getopt (argc, argv, optstring)) != EOF) {
	switch (c) {
	    case 'n': maskNot     = optarg;  break;
	    case 'o': maskOnly    = optarg;  break;
	    case 'i': optInfo     = TRUE;    /* implies verbose */
	    case 'v': optVerbose  = TRUE;    break;
	    case 'c': optCompress = FALSE;   break;
	    case 'D': optNoDelete = FALSE;   break;
	    case 'm': maxMem = atof (optarg);break;
	    case 'S': optSortOnly = TRUE;    break;
	    case 'N': optNoOutput = TRUE;    break;
	    case '%': optSpecial  = TRUE;    break;
	    case '?': errflg++;              break;
	}
    }
    cellNames = argv + optind;
#else
    cellNames = (char **) calloc (argc, sizeof (char *));
    errflg = eseOptionHandler (argc, argv, optionSpecs, argc, cellNames);
    if (maxMemString) {
        maxMem = atof (maxMemString);
    }
    if (optInfo) {
	optVerbose = TRUE;
    }
#endif

    if (!*cellNames) {
	say ("No cellname(s) specified\n");
	errflg++;
    }

    if (maxMem < 0) {
	say ("Max memory must be > 0");
	errflg++;
    }

    if (errflg) {
#ifndef ESE
	printf (
	    "Usage: %s %s[-vDc] [-m maxmem] [-n masklist] [-o masklist] cell [...]\n",
	    argv0, optSpecial ? "[-%iSN] " : "");
#else
	printf (
	    "Usage: %s [options] cell [...]\n",
	    argv0);
#endif
	exit (1);
    }

    if (maxMem > 0)
	optMaxMemory = (int) 1024 * 1024 * maxMem;

    if (optVerbose) {
	verboseSetMode (TRUE);
	message ("%s ", argv0);
	for (c = 1; c < argc; c++) 
	    message ("%s ", argv[c]);
	message ("\n");

	message ("-v: verbose mode\n");
	if (maskNot)     message ("-n: skip masks %s\n", maskNot);
	if (maskOnly)    message ("-o: only masks %s\n", maskOnly);
	if (optInfo)     message ("-i: print statistics, implies -v\n");
	if (optSortOnly) message ("-S: sort edge only, no overlap removal\n");
	if (optNoOutput) message ("-N: no database gln file output\n");
	if (optNoDelete == FALSE)
		        message ("-D: remove _bxx files\n");
	if (optCompress == FALSE)
			 message ("-c: do not compress tmp file\n");

	if (maxMem > 0) {
	    char s[50];
	    sprintf (s, "%g", maxMem);
	    message ("-m %s: %d bytes of sort buffer core memory\n",
		     s, optMaxMemory);
	}
    }

    if (optInfo) {
	clockInit ();
	mstat (M_INIT, 0);
    }

    dmInit (argv0);

    dmproject = dmOpenProject (DEFAULT_PROJECT, DEFAULT_MODE);

    process = (DM_PROCDATA *) dmGetMetaDesignData (PROCESS, dmproject);

    ASSERT (*cellNames);

    while (* cellNames) {
	docell (* cellNames, version);
	cellNames++;
    }

    dmCloseProject (dmproject, COMPLETE);

    dmQuit ();

    if (optInfo) {
	clockPrintAll (stdout);
	clockPrintTime (stdout);
	scanPrintInfo (stdout);
	sortPrintInfo (stdout);
	outputPrintInfo (stdout);
	mstat (M_PRINT, stdout);
    }

    verbose ("%s --- Finished ---\n", argv0);

    exit (0);
}


int scale;

private
docell (cellname, version)	/* do a cell */
char * cellname,
     * version;
{
    int i;
    DM_STREAM * info3;

    tick (mprintf ("makegln %s", cellname));
    verbose ("cell %s, version %s\n", cellname, version);

    cellKey = dmCheckOut 
	(dmproject, cellname, version, DONTCARE, LAYOUT, ATTACH);
    
    currentCell = cellname;

    /* this is a %$!#$^@ hack to make sure that the
    correct design objects are used.
    Any comments or remarks? Please forward to P. v.d. Wolf */
    read_mcs (cellKey);

    info3 = dmOpenStream (cellKey, "info3", "r");
    dmGetDesignData (info3, GEO_INFO3);
    dmCloseStream (info3, COMPLETE);

    if (ginfo3.nr_samples != 0)
	scale = 1;
    else
	scale = SCALE;

    for (i = 0; i < process -> nomasks; i++) {

#if 0
	if (process -> mask_type[i] == DM_SYMB_MASK) /*!!!*/
	    continue;		/* skip symbolic layers */ /*!!!*/
#endif

	if ((maskNot != NULL)
	&&  (strfind (maskNot, process -> mask_name[i]) != NULL)) {
	    verbose ("skip %s\n", process -> mask_name[i]);
	    continue;
	}

	if ((maskOnly != NULL)
	&&  (strfind (maskOnly, process -> mask_name[i]) == NULL)) {
	    verbose ("skip %s\n", process -> mask_name[i]);
	    continue;
	}

	makegln (process -> mask_name [i], process -> mask_type [i], scale);
    }

    dmCheckIn (cellKey, COMPLETE);
    tock (mprintf ("makegln %s", cellname));

    currentCell = NULL;
}


private
makegln (maskname, masktype, scale)	/* do mask maskname of type masktype */
char * maskname;
int masktype;
int scale;
{
    verbose ("mask %s\n", maskname);

    tick ("readEdges");
    readEdges (cellKey, maskname, masktype, scale);
    tock ("readEdges");

    openOutput (cellKey, maskname);

    tick ("scan");
    scan ();
    tock ("scan");

    closeOutput ();
}

dmError (s)			/* ddm error handler */
char *s;
{
    fprintf (stderr, "%s: ddm error: ", argv0);
    dmPerror (s);
    die ();
}

void die ()				/* clean-up and stop */
{
    static int recursive = 0;

    if (recursive++ > 0) {
        char * s = "Emergency exit\n";
        write (fileno (stderr), s, strlen (s));
        exit (1);
    }

    outputCleanUp ();

#   ifndef DEBUG
#   if NCF_RELEASE < 400
    if (currentCell) {
	char buf[100];
	/*
	 * should only remove gln files
	 */
	say ("cleaning up %s (running dbclean)", currentCell);
	sprintf (buf, "%s/exp_dat", dmproject -> dmpath);
	unlink (buf);
#       ifndef ESE
        sprintf (buf, "dbclean -l %s\n", currentCell);
#       else /* ESE */
        sprintf (buf, "cleancell -view layout %s\n", currentCell);
#       endif /* ESE */
	system (buf);
    }
#   endif /* NCF_RELEASE < 400 */
#   endif DEBUG

    dmQuit ();

    if (optInfo) {
        clockPrintAll (stdout);
        clockPrintTime (stdout);
        scanPrintInfo (stdout);
        sortPrintInfo (stdout);
        outputPrintInfo (stdout);
        mstat (M_PRINT, stdout);
    }

    exit (1);
}

# define SEP " \t\n,"

private
char * strfind (s1, s2)
char * s1, * s2;
{
    char * p;
    char *buf;

    buf = strsave (s1);

    for (p = strtok (buf, SEP); p != NULL; p = strtok ((char *) NULL, SEP)) {
        if (strcmp (p, s2) == 0) {
            break; /* found */
        }
    }

    DISPOSE (buf);
    return (p);
}


read_mcs (key)
DM_CELL *key;
{
    DM_STREAM *fpmc;

	/* ueaghjaj garbage!!!! */

    if (!(fpmc = dmOpenStream (key, "mc", "r"))) {
	return (-1);
    }
    while (dmGetDesignData (fpmc, GEO_MC) > 0) {
	;
    }
    dmCloseStream (fpmc, COMPLETE);
    return (0);
}
