static char *SccsId = "@(#)main.c 3.20 (TU-Delft) 03/26/91";
/**********************************************************

Name/Version      : dbclean/3.20

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

Author(s)         : S. de Graaf
Creation date     : 03-Feb-1987
Modified by       : S. de Graaf
Modification date : 10-Mar-1987
Modification date : 19-May-1988


        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-1988, All rights reserved
**********************************************************/
#include "stdio.h"
#include "signal.h"
#include "malloc.h"
#include "string.h"
#include "sys/types.h"
#include "sys/stat.h"
#ifdef ESE
#include "eseOption.h"
#include "tversion.h"
#endif

#ifdef SYSV
#include "ndir.h"
#else
#include "sys/dir.h"
#endif

#include "dmincl.h"

#define P_E fprintf(stderr,

struct stat st_buf;

DM_PROJECT *project;	/* project access key */
DM_CELL    *cellkey;	/* cell access key */
char    buf[256];	/* temp. string buffer */

int     eflag;	/* exclusive cells in "exp_dat" file */
int     lflag;	/* only "layout" view */
int     cflag;	/* only "circuit" view */
int     allflag;	/* do all cells of specified viewtypes */
int     fflag;	/* only "floorplan" view */
int     vflag;	/* verbose */
int     Vflag;	/* Verbose */
char ** viewlist = NULL;

char  **specml;

#ifndef ESE
char   *argv0 = "dbclean";	/* program name */
char   *use_msg =		/* command line */
"\nUsage: %s [-elcfvV] [cell ...]\n\n";
#else
char   *argv0 = "cleancell";      /* program name */
char   *use_msg =               /* command line */
"\nUsage: %s [options] [cell ...]\n\n";
#endif

#ifdef ESE
OptionSpec optionSpecs[] = {
    { "", NO, eseHelp, (void *) optionSpecs,
            "usage:     cleancell [options] [cell ...]\nOptions (may be abbreviated) are:"},
    { "%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" },
    { "%etext", NO, eseText, (void *) NULL,
            "    -%etext:               print the '(int) & etext' number" },
    { "%layout", NO, eseTurnOn, (void *) & lflag,
            "    -%layout:              process only the layout view" },
    { "%circuit", NO, eseTurnOn, (void *) & cflag,
            "    -%circuit:             process only the circuit view" },
    { "all", NO, eseTurnOn, (void *) & allflag,
            "    -all:                  clean all cells of specified viewtypes" },
    { "view", YES, eseListArguments, (void *) & viewlist,
            "    -view viewtypes:       clean only cells of specified viewtypes" },

    { "verbose", NO, eseTurnOn, (void *) & vflag,
            "    -verbose:              print run-time information" },
    { "%Verbose", NO, eseTurnOn, (void *) & Vflag,
            "    -%Verbose:             print run-time info and report streams removed" },
    { (char *) 0, (char) 0, (IFP) 0, (void *) 0, (char *) 0 },
};
#endif

main (argc, argv)
int   argc;
char *argv[];
{
    int     sig_handler (); /* signal handler */
    char   *p;
    int     iarg;	    /* argument number */
    int     usage = 0;

#ifndef ESE
    for (iarg = 1; iarg < argc && argv[iarg][0] == '-'; ++iarg) {
	p = &argv[iarg][1];
	while (*p != '\0') {
	    switch (*p++) {
		case 'e': 
		    ++eflag;
		    break;
		case 'l': 
		    ++lflag;
		    break;
		case 'c': 
		    ++cflag;
		    break;
		case 'f': 
		    ++fflag;
		    break;
		case 'V': 
		    ++Vflag;
		case 'v': 
		    ++vflag;
		    break;
		default: 
		    ++usage;
		    P_E "%s: -%c: unknown option\n", argv0, *(p - 1));
		    break;
	    }
	}
    }


#else 
    specml = (char **) calloc (argc, sizeof (char *));
    if (eseOptionHandler (argc, argv, optionSpecs, argc, specml) > 0)
        exit (1);
    
    if (!allflag && !specml[0]) {
	P_E "You must specify -all or cell ...\n");
	usage++;
    }
	
    if (Vflag)
        vflag++;

    if (!viewlist) {
	P_E "You must specify at least one viewtype with the '-view' option.\n");
	usage++;
    }
    else {
	for ( ; * viewlist; viewlist++) {
	    if (viewlist[0][0] == 'l') {
		lflag = 1;
	    }
	    else if (viewlist[0][0] == 'c') {
		cflag = 1;
	    }
	    else {
		P_E "-view: '%s' does not exist", viewlist[0]);
		usage++;
	    }
	}
    }
#endif

    if (usage) {
	P_E use_msg, argv0);
	exit (1);
    }


    if (signal (SIGINT, SIG_IGN) != SIG_IGN)
	signal (SIGINT, sig_handler);
#ifndef MSDOS
    signal (SIGQUIT, SIG_IGN);
    signal (SIGTERM, sig_handler);
    signal (SIGHUP, SIG_IGN); /* ignore hangup signal */
#endif

    dmInit (argv0);
    project = dmOpenProject (DEFAULT_PROJECT, DEFAULT_MODE);

#ifndef ESE
    if (argc > iarg) { /* cell argument(s) specified */
	specml = &argv[iarg];
	++eflag;
    }
#endif

    if (!lflag && !cflag && !fflag) {
	++lflag;
	++cflag;
#ifndef ESE
	++fflag;
#endif
    }

    chdir (project -> dmpath);
    (void) unlink ("procesdata1");
    (void) unlink ("procesdata2");
    (void) unlink ("stretchdata");
    (void) unlink ("maskdata");
    (void) unlink ("nbooldata");

    if (lflag) clean_layout_view ();
    if (cflag) clean_circuit_view ();
    if (fflag) clean_floorplan_view ();

    if (vflag) P_E "%s: -- program finished --\n", argv0);

    dmQuit ();
    exit (0);
}

struct mo_elmt {
    char mo[DM_MAXNAME+1];
    struct mo_elmt *next;
};

struct mo_elmt *emlist;

clean_layout_view ()
{
    register char **ml;
    register struct mo_elmt *p;
    FILE *fp;

    if (eflag) {
	if (fp = fopen ("exp_dat", "r")) {
	    while (fscanf (fp, "%s", buf) != EOF) {
		p = (struct mo_elmt *)malloc (sizeof (struct mo_elmt));
		if (!p) errexit (4, "");
		strcpy (p -> mo, buf);
		p -> next = emlist;
		emlist = p;
	    }
	    fclose (fp);
	}
    }

    if (dmGetMetaDesignData (EXISTVIEW, project, LAYOUT)) {
#ifndef ESE
	if (specml)
#else
        if (specml[0] != NULL)
#endif
	    ml = specml;
	else
	    ml = (char **) dmGetMetaDesignData (CELLLIST, project, LAYOUT);

	if (ml)
	    while (*ml) unlink_2nd_files (*ml++);
    }
    else {
	errexit (-3, "layout");
    }

    if (!eflag) (void) unlink ("exp_dat");
}

unlink_2nd_files (cell)
char *cell;
{
    DIR  *dirp;
#ifdef MSDOS
    direct *e, dp;
#else
    register struct direct *dp;
#endif

    register struct mo_elmt *p;
    DM_STREAM *fp, *fp_new;

    sprintf (buf, "layout/%s", cell);
    if (vflag) P_E "-> %s\n", buf);

    if (p = emlist) {
	do {
	    if (strcmp (cell, p -> mo) == 0) {
		errexit (-9, cell);
		return;
	    }
	}
	while (p = p -> next);
    }

    if (stat (buf, &st_buf) == -1) {
	errexit (-5, buf);
	return;
    }

#ifdef MSDOS
    if (!(dirp = opendir (buf, D_READ))) {
	errexit (-6, buf);
	return;
    }

    chdir (buf);

    while (e = readdir (dirp, &dp)) {
	if (strcmp (dp.d_name, ".") == 0
		|| strcmp (dp.d_name, "..") == 0)
	    continue;

	if (strcmp (dp.d_name, "box") == 0
		|| strcmp (dp.d_name, "info") == 0
		|| strcmp (dp.d_name, "mc") == 0
		|| strcmp (dp.d_name, "nor") == 0
		|| strcmp (dp.d_name, "term") == 0)
	    continue;

	do_unlink (dp.d_name);
    }
#else
    if (!(dirp = opendir (buf))) {
	errexit (-6, buf);
	return;
    }

    chdir (buf);

    while (dp = readdir (dirp)) {
	if (dp -> d_ino == 0)
	    continue;		/* empty slot */

	if (strcmp (dp -> d_name, ".") == 0
		|| strcmp (dp -> d_name, "..") == 0)
	    continue;

	if (strcmp (dp -> d_name, "box") == 0
		|| strcmp (dp -> d_name, "info") == 0
		|| strcmp (dp -> d_name, "mc") == 0
		|| strcmp (dp -> d_name, "nor") == 0
		|| strcmp (dp -> d_name, "term") == 0)
	    continue;

	do_unlink (dp -> d_name);
    }
#endif

    closedir (dirp);

    cellkey = dmCheckOut (project, cell, ACTUAL, DONTCARE, LAYOUT, ATTACH);
    fp = dmOpenStream (cellkey, "info", "r");
    fp_new = dmOpenStream (cellkey, "info_new", "w");
    dmGetDesignData (fp, GEO_INFO);
    dmPutDesignData (fp_new, GEO_INFO);
    dmGetDesignData (fp, GEO_INFO);
    dmPutDesignData (fp_new, GEO_INFO);
    dmGetDesignData (fp, GEO_INFO);
    dmPutDesignData (fp_new, GEO_INFO);
    dmCloseStream (fp, QUIT);
    dmCloseStream (fp_new, QUIT);

    if (unlink ("info"))
	errexit (-7, "info");
    else
	if (link ("info_new", "info"))
	    errexit (8, cell);
	else
	    if (unlink ("info_new"))
		errexit (-7, "info_new");

    dmCheckIn (cellkey, COMPLETE);
    chdir (project -> dmpath);
}

do_unlink (file)
char *file;
{
    if (Vflag) P_E "unlink: %s\n", file);
    (void) unlink (file);
}

clean_circuit_view ()
{
    register char **ml;

    if (dmGetMetaDesignData (EXISTVIEW, project, CIRCUIT)) {
#ifndef ESE
	if (specml)
#else
        if (specml[0] != NULL)
#endif
	    ml = specml;
	else
	    ml = (char **) dmGetMetaDesignData (CELLLIST, project, CIRCUIT);

	if (ml) {
	    while (*ml) {
		sprintf (buf, "circuit/%s", *ml);
		if (vflag) P_E "-> %s\n", buf);
		if (stat (buf, &st_buf) == -1) {
		    errexit (-5, buf);
		}
		else {
		    sprintf (buf, "circuit/%s/sls.b", *ml);
		    (void) unlink (buf);
		}
		++ml;
	    }
	}
    }
    else {
	errexit (-3, "circuit");
    }
}

clean_floorplan_view ()
{
    register char **ml;

    if (dmGetMetaDesignData (EXISTVIEW, project, FLOORPLAN)) {
#ifndef ESE
	if (specml)
#else
        if (specml[0] != NULL)
#endif
	    ml = specml;
	else
	    ml = (char **) dmGetMetaDesignData (CELLLIST, project, FLOORPLAN);

	if (ml) {
	    while (*ml) {
#ifdef MSDOS
		sprintf (buf, "floorpln/%s", *ml);
#else
		sprintf (buf, "floorplan/%s", *ml);
#endif
		if (vflag) P_E "-> %s\n", buf);
		if (stat (buf, &st_buf) == -1) {
		    errexit (-5, buf);
		}
		++ml;
	    }
	}
    }
    else {
	errexit (-3, "floorplan");
    }
}

sig_handler (sig) /* signal handler */
int sig;
{
    signal (sig, SIG_IGN); /* ignore signal */
    sprintf (buf, "%d", sig);
    P_E "\n");
    errexit (1, buf);
}

char *err_list[] = {
/* 0 */    "%s",
/* 1 */    "interrupted due to signal: %s",
/* 2 */    "error in DMI function",
/* 3 */    "warning: %s: view does not exist",
/* 4 */    "cannot alloc core",
/* 5 */    "warning: %s: cannot stat",
/* 6 */    "warning: %s: cannot open dir",
/* 7 */    "warning: %s: cannot unlink",
/* 8 */    "error: %s: cannot link \"info\" to \"info_new\"",
/* 9 */    "warning: %s: cell in \"exp_dat\", not processed",
/* 10 */   "error: but cannot find error message"
};

errexit (errno, s)
int     errno;
char   *s;
{
    int i;

    i = (errno < 0) ? -errno : errno;
    if (i > 10) i = 10;

    P_E "%s: ", argv0);
    P_E err_list[i], s);
    P_E "\n");

    if (errno >= 0) {
	P_E "\n%s: -- program aborted --\n", argv0);
	dmQuit ();
	exit (1);
    }
}

dmError (s)
char *s;
{
    P_E "%s: ", argv0);
    dmPerror (s);
    errexit (2, "");
}

#ifdef MSDOS
link (s,t)
char *s, *t;
{
	FILE *fp1, *fp2;
	int c;
	fp1 = fopen (s, "r");
	fp2 = fopen (t, "w");
	if (fp1 == NULL || fp2 == NULL) return (1);

	while ( (c=fgetc(fp1)) != EOF)
		fputc (c,fp2);

	fclose (fp1);
	fclose (fp2);
	return (0);
}
#endif
