static char *SccsId = "@(#)main.c 4.5 (TU-Delft) 11/24/92";
/**********************************************************

Name/Version      : mplot/4.5

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

Author            : N.P. van der Meijs
Creation date     : 15-Mar-1988
Modified by       :
Modification date :


        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 <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "dmincl.h"
#include "config.h"
#include "plot.h"
#include "aux/aux.h"

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

int order[100];
int restroke[100];

bool_t optVerbose  = FALSE;
bool_t optAlsoSymb = FALSE;
bool_t optTransparent = FALSE;
bool_t optFullTransparent = FALSE;
bool_t optInfo     = FALSE;
bool_t optBbox     = FALSE;
bool_t optPlotTerm = FALSE;
bool_t optNoExpand = FALSE;
char * maskNot     = NULL;
char * maskOnly    = NULL;

private char * strfind  ();
private void expand ();
private void run ();
private bool_t existDmStream ();

main (argc, argv)
int     argc;
char  **argv;
{
    extern int    optind;
    extern char * optarg;
    extern char * argv0;
    extern char * strrchr ();

    int     c, errflg = 0;
    char  * version = WORKING;	/* default version */
#   ifdef EPSPLOT
    char  * procsuffix = NULL, * procfile = NULL;
#   endif /* EPSPLOT */

    argv0 = strrchr (argv[0], '/') ? strrchr (argv[0], '/') + 1 : argv[0];

    catchSignals ();

 /* evaluate all flags and filenames */

#   ifndef EPSPLOT
    while ((c = getopt (argc, argv, "to:n:vie")) != EOF) {
	switch (c) {
	    case 'n': maskNot     = optarg;  break;
	    case 'o': maskOnly    = optarg;  break;
	    case 'v': optVerbose  = TRUE;    break;
	    case 'i': optInfo     = TRUE;    break;
	    case 't': optPlotTerm = TRUE;    break;
	    case 'e': optNoExpand = TRUE;    break;
	    case '?': errflg++;              break;
	}
    }

    if (errflg || optind != argc - 1) {
	printf (
	    "Usage: %s [-ivt] [-n masklist] [-o masklist] cellname\n",
	    argv0);
	exit (1);
    }

#   else /* EPSPLOT */

    while ((c = getopt (argc, argv, "FTbsrtl:w:h:o:n:vip:P:e")) != EOF) {
	switch (c) {
	    case 'n': maskNot     = optarg;  break;
	    case 'o': maskOnly    = optarg;  break;
	    case 'v': optVerbose  = TRUE;    break;
	    case 's': optAlsoSymb = TRUE;    break;
	    case 'i': optInfo     = TRUE;    break;
	    case 'b': optBbox     = TRUE;    break;
	    case 't': optPlotTerm = TRUE;    break;
	    case 'T': optTransparent = TRUE;    break;
	    case 'F': optFullTransparent = TRUE;    break;
	    case 'w': plotSetDrawWidth (optarg); break;
	    case 'h': plotSetDrawHeight (optarg); break;
	    case 'l': plotSetLambda (optarg); break;
	    case 'r': plotSetRotation ();    break;
	    case 'p': procsuffix  = optarg;  break;
	    case 'P': procfile    = optarg;  break;
	    case 'e': optNoExpand = TRUE;    break;
	    case '?': errflg++;              break;
	}
    }

    if (errflg || optind != argc - 1) {
	printf ("\
Usage: %s [-ivt] (-p procsuffix | -P procfile)\n\
       [-n masklist] [-o masklist] [-w drawwidth] [-h drawheight]\n\
       [-l lambda] [-r] cellname\n", argv0);
	exit (1);
    }
#   endif /* EPSPLOT */

    if (optInfo) mstat (M_INIT, 0);
    if (optVerbose) verboseSetMode (TRUE);

    dmInit (argv0);

    dmproject = dmOpenProject (DEFAULT_PROJECT, DEFAULT_MODE);

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

    for (c = 0; c < process -> nomasks; c++) {
	order[c] = c;
	restroke[c] = -1;
    }

#   ifdef EPSPLOT
    doEpsTechnology (dmproject, procsuffix, procfile, order, restroke);
#   endif /* EPSPLOT */

    while (optind <= argc -1)
	docell (argv[optind++], version);

    dmCloseProject (dmproject, COMPLETE);

    dmQuit ();

    if (optInfo) mstat (M_PRINT, stdout);

    exit (0);
}


static
docell (cellname, version)	/* plot a cell */
char * cellname,
     * version;
{
    int i;
    int j;
    int pass;
    int num_passes = 1;

#   ifdef EPSPLOT
    num_passes = 3;
#   endif


    verbose ("cell %s\n", cellname);

    if (!optNoExpand) expand (cellname);

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

    plotInit (cellKey);

    for (pass = 1; pass <= num_passes; pass++) {
	plotPass (pass);
	verbose ("pass %d\n", pass);

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

	    if (pass == 1) i = order[j];
	    else           i = restroke[j];

	    if (i < 0)
		continue;

	    if (pass == 1
	    || (pass == 2 && optFullTransparent == TRUE)
	    || (pass == 2 && optTransparent == TRUE
			  && process -> mask_type[i] == DM_INTCON_MASK)) {
		if (!optAlsoSymb
		&&  process -> mask_type[i] == DM_SYMB_MASK) {
		    verbose ("skip %s\n", process -> mask_name[i]);
		    continue;	/* skip symbolic layers */
		}

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

		domask (process -> mask_name[i], process -> PLOT[i] -> code);
	    }

	    if (pass == 2 || pass == 3 || num_passes == 1) {
		if (optPlotTerm
		&&  process -> mask_type[i] == DM_INTCON_MASK) {
		    doterm (process -> mask_name[i], process -> mask_no[i],
			    process -> PLOT[i] -> code);
		}
	    }
	}

	if (pass == 2 || pass == 3) {
	    if (optBbox) plotBbox ();
	    doAnnotations ();
	}

    }

    plotEnd ();

    dmCheckIn (cellKey, COMPLETE);
}


static
domask (maskname, color)	/* plot mask maskname with color */
char * maskname;
int    color;
{
    verbose ("mask %s\n", maskname);

    plotMask (maskname, color);

    openInput (cellKey, maskname);

    scan ();

    closeInput ();
}

/* plot terminals in mask maskname with color */
static
doterm (maskname, maskno, color)
char * maskname;
int    maskno;
int    color;
{
    DM_STREAM * stream = NULL;

    plotMask (mprintf ("t_%s", maskname), color);

    stream = dmOpenStream (cellKey, "term", "r");

    while (dmGetDesignData (stream, GEO_TERM) > 0) {

	if (maskno != gterm.layer_no)
	    continue; /* wrong layer (oops) */

	if (gterm.nx == 0 && gterm.ny == 0) {
	    plotTerminal (gterm.xl, gterm.xr, gterm.yb, gterm.yt,
		gterm.term_name);
	}

	else {
	    int i, j;
	    char name[100];
	    for (i = 0; i <= gterm.nx; i++) {
		for (j = 0; j <= gterm.ny; j++) {
		    if (gterm.nx == 0 && gterm.ny != 0) 
			 sprintf (name, "%s[%d]", gterm.term_name, j + 1);
		    else if (gterm.nx != 0 && gterm.ny == 0)
			 sprintf (name, "%s[%d]", gterm.term_name, i + 1);
		    else
			 sprintf (name, "%s[%d,%d]", gterm.term_name,
			     i + 1, j + 1);
		    plotTerminal (
			gterm.xl + i * gterm.dx, gterm.xr + i * gterm.dx,
			gterm.yb + j * gterm.dy, gterm.yt + j * gterm.dy,
			name);
		}
	    }
	}
    }

    dmCloseStream (stream, COMPLETE);
}


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

void die ()				/* clean-up and stop */
{
    dmQuit ();
    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);
}

doAnnotations ()
{
# ifdef EPSPLOT
    DM_STREAM * dmfp;
    int type;
    long int x1, y1, x2, y2;
    long int x, y;
    int mode;
    int orient;
    char text[1024];
    struct stat statBuf;

    verbose ("annotations\n");

    if (dmStat (cellKey, "annotations", &statBuf) == -1) {
	return -1;
    }
    if (!(dmfp = dmOpenStream (cellKey, "annotations", "r"))) {
        return (-1);
    }

    while (dmScanf (dmfp, "%d", &type) == 1) {

	switch (type) {
	    case LINE:
		dmScanf (dmfp, "%ld %ld %ld %ld %d\n",
			&x1, &y1, &x2, &y2, &mode);
		plotLine (x1, y1, x2, y2, mode);
		break;

	    case TXT:
                /* Need ~-quoted strings, because they can contain spaces. */
                dmScanf (dmfp, "%d %d %d ~%[^~]~\n",
			&x, &y,
			&orient, text);
		plotText (x, y, orient, text);
		break;
        }
    }
    dmCloseStream (dmfp, COMPLETE);
    return (0);
# endif /* EPSPLOT */
}

# ifdef ESE
# define MKBOX    "mkboxl"
# define MKGLN    "mkgln"
# else
# define MKBOX    "makeboxl"
# define MKGLN    "makegln"
# endif /* ESE */

private void expand (cellname)
char * cellname;
{
    bool_t ppNeeded = FALSE;

    DM_CELL * cellKey = dmCheckOut 
	(dmproject, cellname, WORKING, DONTCARE, LAYOUT, READONLY);
    
    if (existDmStream (cellKey, "spec") == FALSE) {
	Debug (fprintf (stderr, "no previous exp or hierarchical\n"));
	ppNeeded = TRUE;
    }
    else if (compareGlnDate (cellKey, "box", cellKey) <= 0) {
	Debug (fprintf (stderr, "no gln file or box file is newer\n"))
	ppNeeded = TRUE;
    }

    if (ppNeeded) {
	verbose ("preprocessing %s...", cellname);

	dmCheckIn (cellKey, COMPLETE);

	run (MKBOX, cellname);
	run (MKGLN, cellname);

	verbose ("done\n");
    }
    else
	dmCheckIn (cellKey, COMPLETE);


    return;
}

private void run (command, arg)
char * command;
char * arg;
{
    extern char icdpath[];
    char path[1000];
    sprintf (path, "%s/bin/%s", icdpath, command);
    Debug (fprintf (stderr, "%s %s\n", path, arg));
    if (_dmRun (path, arg, NULL)) {
	say ("error in '%s %s'", command, arg);
	die ();
    }
}

/* returns TRUE if stream exist.
*/
private bool_t existDmStream (key, streamName)
DM_CELL * key;
char * streamName;
{
    struct stat buf;
    return (dmStat (key, streamName, &buf) == 0 ? TRUE : FALSE);
}

int compareGlnDate (key1, stream1, key2)
DM_CELL * key1, * key2;
char * stream1;
{
    extern char * strsave ();
    static char * stream2 = NULL;

    if (stream2 == NULL) {
	int i;
	for (i = 0; i < process -> nomasks; i++) {
	    if (process -> mask_type[i] == DM_INTCON_MASK)
		break;
	}
	ASSERT (i < process -> nomasks);

        stream2 = strsave (mprintf ("%s_gln", process -> mask_name[i]));
    }


    return (compareDmStreamDate (key1, stream1, key2, stream2));
}

/* returns < 0 if stream2 older then stream 1, and stream1 exists
 *
 * If stream 2 does not exist: -2
 * If stream 2 exists:         -1
 */
int compareDmStreamDate (key1, stream1, key2, stream2)
DM_CELL * key1, * key2;
char * stream1, * stream2;
{
    struct stat buf1, buf2;

    if (dmStat (key1, stream1, &buf1) != 0) return ( 2);
    if (dmStat (key2, stream2, &buf2) != 0) return (-2);

    if (buf1.st_mtime < buf2.st_mtime) return ( 1);
    if (buf1.st_mtime > buf2.st_mtime) return (-1);

    return (0);
}
