/* branch.c  94.11.20
 * Copyright 1983-1992   Albert Davis
 * accesses branch array.
 */
#include "ecah.h"
#include "branch.h"
#include "error.h"
#include "declare.h"
/*--------------------------------------------------------------------------*/
	branch_t *firstbranch_dev(void);
	branch_t *firstbranch_all(void);
	branch_t *nextbranch_dev(const branch_t*);
	branch_t *nextbranch_all(const branch_t*);
	branch_t *lastbranch_dev(void);
	branch_t *lastbranch_all(void);
	branch_t *insertbranch(branch_t*);
	int	 deletebranch(branch_t**);
	int	 unlinkbranch(branch_t*);
static	void	 freelist(generic_t**);
/*--------------------------------------------------------------------------*/
extern const char e_int[];
static branch_t ends = {(generic_t*)NULL, sizeof(branch_t),
    (functions_t*)NULL, &ends, &ends, &ends, &ends, /*more*/};
/*--------------------------------------------------------------------------*/
/* firstbranch_dev: return pointer to first device in the parts list
 *		       pointer to ends if empty list, or no devices
 */
branch_t *firstbranch_dev(void)
{
 branch_t *x;
 for (x = ends.next;  exists(x) && !isdevice(x);  x = x->next)
    /* skip */;
 return x;
}
/*--------------------------------------------------------------------------*/
/* firstbranch_all: return pointer to first item in the parts list
 *		       pointer to ends if empty list
 */
branch_t *firstbranch_all(void)
{
 return ends.next;
}
/*--------------------------------------------------------------------------*/
/* nextbranch_dev: return pointer to next non-comment branch in list
 */
branch_t *nextbranch_dev(const branch_t *x)
{
 branch_t *y;
 if (!x)
    return &ends;
 while (y = x->next,  !isdevice(y))
    x = y;;
 return y;
}
/*--------------------------------------------------------------------------*/
/* nextbranch_all: return pointer to next line in netlist (incl comments)
 *			  pointer to ends if at end of list or null arg
 */
branch_t *nextbranch_all(const branch_t *x)
{
 return (x) ? x->next : &ends;
}
/*--------------------------------------------------------------------------*/
/* lastbranch_dev: return pointer to last device in the parts list
 *		      pointer to ends if empty list, or no devices
 */
branch_t *lastbranch_dev(void)
{
 branch_t *x;
 for (x = ends.prev;  exists(x) && !isdevice(x);  x = x->prev)
    /* skip */;
 return x;
}
/*--------------------------------------------------------------------------*/
/* lastbranch_all: return pointer to last item in the parts list
 *		      pointer to ends if empty list
 */
branch_t *lastbranch_all(void)
{
 return ends.prev;
}
/*--------------------------------------------------------------------------*/
/* insertbranch: insert a branch into the parts list
 * either pre or post inserts, depending....
 *   specify after, inserts after that one (post)
 *   specify before, inserts before that one (pre)
 *   specify both (bad.  don't do it) after wins.
 *   specify neither, makes self link, for a new list.
 * then set up same-type links
 *   if one of the links is done, fill in the others
 *   else make same type point to self
 * actually inserts the branch passed in into the list.  no copies.
 * links are never null, after this returns
 * returns pointer to actual new element
 */
branch_t *insertbranch(branch_t *brh)
{
 if (brh->prev  &&  brh->next)
    error(bERROR, e_int, "bad branch link");
 else if (brh->prev)
    brh->next = brh->prev->next;
 else if (brh->next)
    brh->prev = brh->next->prev;
 else /* make self link */
    brh->prev = brh->next = brh;

 brh->next->prev = brh->prev->next = brh;

 if (brh->stprev  &&  brh->stnext){
    if (brh->stprev != brh  ||  brh->stnext != brh)
       error(bERROR, e_int, "bad st link");
 }else if (brh->stprev){
    brh->stnext = brh->stprev->stnext;
 }else if (brh->stnext){
    brh->stprev = brh->stnext->stprev;
 }else{ /* make self link */
    brh->stprev = brh->stnext = brh;
 }

 brh->stnext->stprev = brh->stprev->stnext = brh;
 return brh;
}    
/*--------------------------------------------------------------------------*/
/* deletebranch: delete a branch from parts list
 * frees its memory
 * returns count actually deleted (either 1 or 0)
 * updates pointers, first, last, etc.
 * so list is consistent on return
 */
int deletebranch(branch_t **brh)
{
 int count = unlinkbranch(*brh);
 freelist((generic_t**)brh);
 return count;
}
/*--------------------------------------------------------------------------*/
/* unlinkbranch: unlink a branch from parts list
 * doesn't free memory, just unlinks it
 * returns count actually unlinked (either 1 or 0)
 * updates pointers, first, last, etc.
 * so list is consistent on return
 */
int unlinkbranch(branch_t *brh)
{
 if (exists(brh)){
    brh->next->prev = brh->prev;
    brh->prev->next = brh->next;
    brh->stnext->stprev = brh->stprev;
    brh->stprev->stnext = brh->stnext;
    return 1;
 }else{
    return 0;
 }
}
/*--------------------------------------------------------------------------*/
/* freelist: free a (singly linked) list of structures   (recursive)
 * struct generic is an attempt to tame type clashes
 */
static void freelist(generic_t **x)
{
 if (x  &&  *x  &&  (*x)->x  &&  (*x)->x != (*x)->x->x)
    freelist(&((*x)->x));
 qfree((void**)x);
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
