static char *SccsId = "@(#)cirTree.c 4.10 (TU-Delft) 07/28/92";
/**********************************************************

Name/Version      : xsls/4.10

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 "incl.h"

extern DM_PROJECT *dmproject;

extern int alsoImport;
extern int cirFlag;

struct cir *beg_extl = NULL;

static struct cir *beg_cirl; 
static struct cir *end_cirl; 
static int len_cirl;

/* cirTree returns a pointer to an array of character-pointers
   pointing to the names of cells that are in the hierarchical 
   tree of the cell specified.  The order will be 'depth first',
   and the last pointer will contain NULL.
*/

struct cir *cirTree (name)
char *name;
{
    struct cir *top_cirl;
    int findChildren ();
    struct cir *locateTopCell ();

    beg_cirl = end_cirl = NULL;
    len_cirl = 0;

    top_cirl = locateTopCell (name);

    if (findChildren (top_cirl -> orig_name, 1, 
	top_cirl -> proj, top_cirl -> imported) != 0)
	return (NULL);

    /* add root cell */

    if (beg_cirl == NULL) {
	beg_cirl = top_cirl;
	end_cirl = beg_cirl;
    }
    else {
	end_cirl -> next = top_cirl;
	end_cirl = end_cirl -> next;
    }

    return (beg_cirl);
}

int findChildren (name, isroot, proj, fatherImported)
char *name;
int isroot;
DM_PROJECT *proj;
int fatherImported;
{
    DM_CELL *dkey;
    DM_STREAM *dsp;
#if NCF_RELEASE >= 400
    DM_STREAM *dsp_sim_mc;
    struct stat fsbuf;
#endif
    struct cir *beg_childl;
    struct cir *end_childl;
    struct cir *cl;
    struct cir *cl2;
    struct cir *help;
    struct cir *new_cirl;
    char *localname;
    int is_f;
    int findChildren ();
    struct model_info *findDev ();


    if ((dkey = dmCheckOut (proj, name, 
			    isroot ? WORKING : ACTUAL, 
			    DONTCARE, CIRCUIT, READONLY)) == NULL) {
        return (-1);
    }

    beg_childl = end_childl = NULL;

    if ((dsp = dmOpenStream (dkey, "mc", "r")) == NULL) {
	return (-1);
    }

#if NCF_RELEASE >= 400
    if (!cirFlag && dmStat(dkey, "sim_mc", &fsbuf) == 0)
        dsp_sim_mc = dmOpenStream (dkey, "sim_mc", "r");
    else
        dsp_sim_mc = NULL;
#endif

    while (dmGetDesignData (dsp, CIR_MC) > 0) {
#if NCF_RELEASE >= 400
        is_f = 0;
        if (dsp_sim_mc) {
            dmGetDesignData (dsp_sim_mc, CIR_SIM);
            if (strcmp (csim.inst_name, cmc.inst_name)) {
                fatalErr ("Error in stream 'sim_mc'", NULL);
            }

            if (csim.flag == 'f' || csim.flag == 'b')
		is_f = 1;
        }
        else {
	    is_f = is_func (&cmc);
        }
#else
        is_f = is_func (&cmc);
#endif
	if (is_f || findDev (cmc.cell_name, (int)cmc.imported, proj, 0)) {
	    cmcClean (&cmc);
	    continue;
	}
	if (cmc.imported == IMPORTED && !alsoImport) {
	    reportExt (cmc.cell_name, (int)cmc.imported, proj);
	    cmcClean (&cmc);
	    continue;
	}
	cl = beg_childl;
	while (cl != NULL && strcmp (cl -> name, cmc.cell_name) != 0) {
	    cl = cl -> next;
	    /* search local list */
	}
	if (cl == NULL) {
	    /* not yet in local list, so add at the end
	       of the local list */
	    if (beg_childl == NULL) {
		PALLOC (beg_childl, 1, struct cir);
		end_childl = beg_childl;
	    }
	    else {
		PALLOC (end_childl -> next, 1, struct cir);
		end_childl = end_childl -> next;
	    }
	    strcpy (end_childl -> name, cmc.cell_name);
	    end_childl -> proj = NULL;
	    end_childl -> imported = cmc.imported;
		  /* Here, 'imported' indicates whether the calls within
		     'name' are to an imported cell */
	    end_childl -> next = NULL;
	}
	cmcClean (&cmc);
    }

    dmCloseStream (dsp, COMPLETE);
#if NCF_RELEASE >= 400
    if (dsp_sim_mc)
        dmCloseStream (dsp_sim_mc, COMPLETE);
#endif

    dmCheckIn (dkey, QUIT);

    cl = beg_childl; 
    while (cl != NULL) {

	cl2 = beg_cirl;
	while (cl2 != NULL && strcmp (cl2 -> name, cl -> name) != 0) {
	    cl2 = cl2 -> next;
	    /* search global list */
	}

	if (cl2 == NULL) {

	    /* not yet in global list */

            /* first, make new structure for global list and find project etc.
	    */

	    PALLOC (new_cirl, 1, struct cir);
	    strcpy (new_cirl -> name, cl -> name);
	    new_cirl -> proj = dmFindProjKey (cl -> imported, cl -> name, proj,
			                      &localname, CIRCUIT);
	    if (alsoImport && strcmp (new_cirl -> name, localname) != 0) {
		fatalErr (
		 "cannot handle aliases when also retrieving imported cells:", 
			  localname);
	    }
	    strcpy (new_cirl -> orig_name, localname);
	    new_cirl -> imported = (fatherImported || cl -> imported);
	    new_cirl -> next = NULL;

            /* second, handle possible children first 
	    */

	    if (findChildren (new_cirl -> name, 0, 
			      new_cirl -> proj, new_cirl -> imported) != 0) {
		return (-1);
	    }

	    /* third, add new structure at the end of the global list */

	    if (beg_cirl == NULL) {             
		beg_cirl = new_cirl;
		end_cirl = beg_cirl;
	    }
	    else {
		end_cirl -> next = new_cirl;
		end_cirl = end_cirl -> next;
	    }

	    len_cirl++;
	}
	else if (cl -> proj && cl -> proj != cl2 -> proj ) {
	    fatalErr ("cell is defined in two different projects:",
		      cl -> name);
	}

	help = cl;
	cl = cl -> next;
	FREE (help);
    }

    return (0);
}

struct cir *locateTopCell (name)
char *name;
{
    IMPCELL **impcelllist;
    int imported;
    char *localname;
    struct cir *new_cirl;

    imported = LOCAL;

    impcelllist = (IMPCELL **)dmGetMetaDesignData (IMPORTEDCELLLIST, 
						   dmproject, CIRCUIT);
    while (*impcelllist) {
	if (strcmp ((*impcelllist) -> alias, name) == 0) {
	    imported = IMPORTED;
	    break;
	}
	impcelllist++;
    }

    PALLOC (new_cirl, 1, struct cir);
    strcpy (new_cirl -> name, name);
    new_cirl -> proj = dmFindProjKey (imported, name, dmproject,
				      &localname, CIRCUIT);
    strcpy (new_cirl -> orig_name, localname);
    new_cirl -> imported = imported;
    new_cirl -> next = NULL;

    return (new_cirl);
}

scanInst (name, isroot, proj)  /* this routine scan the instances in order   */
char *name;               /* to see which devices are present and reads in   */
int isroot;               /* their description.                              */
DM_PROJECT *proj;         /* also, the subnetworks are stored in beg_extl.   */
{
    DM_CELL *dkey;
    DM_STREAM *dsp;

    if ((dkey = dmCheckOut (proj, name, isroot ? WORKING : ACTUAL, 
			    DONTCARE, CIRCUIT, READONLY)) == NULL) {
        return;
    }

    if ((dsp = dmOpenStream (dkey, "mc", "r")) == NULL) {
	return;
    }

    while (dmGetDesignData (dsp, CIR_MC) > 0) {
	if (is_func (&cmc) || findDev (cmc.cell_name,
				       (int)cmc.imported, proj, 0)) {
	    cmcClean (&cmc);
	    continue;
	}
	else
	    reportExt (cmc.cell_name, (int)cmc.imported, proj);
    }

    dmCloseStream (dsp, COMPLETE);

    dmCheckIn (dkey, QUIT);
}

int is_func (amc)      
struct cir_mc *amc;   
{
    char *a;
    int is = 0;
    int colon = 1;

    a = amc -> inst_attribute;
    if (a == NULL)
	return (0);  /* not a function */

    while (*a != '\0' && ! is) {
	if (colon) {
	    if (*a == 'f' && (*(a + 1) == ';' || *(a + 1) == '\0' 
                              || (*(a + 1) == '=' && *(a + 2) != '0')))
		is = 1;
	}
	if (*a == ';')
	    colon = 1;
	else
	    colon = 0;
	a++;
    }

    return (is);  /* returns whether or not it is a function */
}

reportExt (name, imported, father_proj)
char *name;
int imported;
DM_PROJECT *father_proj;
{
    struct cir *extl;
    char *localname;

    extl = beg_extl; 
    while (extl != NULL && strcmp (extl -> name, name) != 0) {
	extl = extl -> next;
    }

    if (extl == NULL) {
	PALLOC (extl, 1, struct cir);
	strcpy (extl -> name, name);
	extl -> imported = imported;
	extl -> proj = dmFindProjKey (imported, name,
				      father_proj, &localname, CIRCUIT);
	strcpy (extl -> orig_name, localname);
	extl -> next = beg_extl;
	beg_extl = extl;
    }
}

cmcClean (amc)
struct cir_mc *amc;
{
    FREE (amc -> inst_attribute);
    FREE (amc -> inst_lower);
    FREE (amc -> inst_upper);
}
