/*
 * Copyright (c) Tony Bybell 1999-2017.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 */

/* AIX may need this for alloca to work */
#if defined _AIX
  #pragma alloca
#endif

#include "globals.h"
#include <config.h>
#include "analyzer.h"
#include "symbol.h"
#include "lxt.h"
#include "lx2.h"
#include "lxt2_read.h"
#include "vcd.h"
#include "extload.h"
#include "debug.h"
#include "bsearch.h"
#include "strace.h"
#include "translate.h"
#include "ptranslate.h"
#include "ttranslate.h"
#include "main.h"
#include "menu.h"
#include "busy.h"
#include "hierpack.h"
#include <stdlib.h>

/*
 * attempt to match top vs bottom rather than emit <Vector>
 */
char *attempt_vecmatch_2(char *s1, char *s2)
{
char *s;
char *p1, *p2;
char *n1=NULL, *n2=NULL;
int n1len = 0, n2len = 0;
char *pfx = NULL;
int pfxlen = 0;
int pfxstate = 0;
char *sfx = NULL;
int sfxlen = 0;
int totlen;
int idx;

if(!strcmp(s1, s2)) { s = malloc_2(strlen(s1)+1); strcpy(s, s1); return(s); }

p1 = s1; p2 = s2;
while(*p1 && *p2)
	{
	if(pfxstate==0)
		{
		if(*p1 == *p2)
			{
			pfx = p1;
			pfxlen = p1 - s1 + 1;
			p1++;
			p2++;
			continue;
			}

		if(!pfx) return(NULL);

		if(isdigit((int)(unsigned char)*p1)&&isdigit((int)(unsigned char)*p2))
			{
			n1 = p1; n2 = p2;
			while(*p1)
				{
				if(isdigit((int)(unsigned char)*p1))
					{
					n1len++;
					}
					else
					{
					break;
					}
				p1++;
				}

			while(*p2)
				{
				if(isdigit((int)(unsigned char)*p2))
					{
					n2len++;
					}
					else
					{
					break;
					}
				p2++;
				}

			if(*p1 && *p2)
				{
				pfxstate = 1;
				sfx = p1;
				continue;
				}
				else
				{
				break;
				}
			}
		}

	if(pfxstate==1)
		{
		if(*p1 == *p2)
			{
			sfxlen++;
			p1++;
			p2++;
			continue;
			}
			else
			{
			return(NULL);
			}
		}

	return(NULL);
	}

if((*p1)||(*p2)) return(NULL);
if((!n1)||(!n2)) return(NULL); /* scan-build : null pointer on strcpy below */

while(pfxlen>1)	/* backup if matching a sequence like 20..24 where the 2 matches outside of the left bracket */
	{
	if(isdigit((int)(unsigned char)s1[pfxlen-1]))
		{
		pfxlen--;
		n1--; n1len++;
		n2--; n2len++;
		}
		else
		{
		break;
		}
	}

totlen = pfxlen + 1 + n1len + 1 + n2len + 1 + sfxlen + 1;
s = malloc_2(totlen);
memcpy(s, s1, pfxlen);
idx = pfxlen;
if(!(pfxlen && (s1[pfxlen-1]=='[')))
	{
	s[idx] = '[';
	idx++;
	}
memcpy(s+idx, n1, n1len);
idx += n1len;
s[idx] = ':';
idx++;
memcpy(s+idx, n2, n2len);
idx += n2len;
if((!sfx) || (*sfx != ']'))
	{
	s[idx] = ']';
	idx++;
	}

if(sfxlen) { memcpy(s+idx, sfx, sfxlen); idx+=sfxlen; }
s[idx] = 0;

return(s);
}


char *attempt_vecmatch(char *s1, char *s2)
{
char *pnt = NULL;

if(!s1 || !s2)
	{
	return(pnt);
	}
	else
	{
	int ns1_was_decompressed = HIER_DEPACK_ALLOC;
	char *ns1 = hier_decompress_flagged(s1, &ns1_was_decompressed);
	int ns2_was_decompressed = HIER_DEPACK_ALLOC;
	char *ns2 = hier_decompress_flagged(s2, &ns2_was_decompressed);

	if(*ns1 && *ns2)
		{
		pnt = attempt_vecmatch_2(ns1, ns2);
		}

	if(ns1_was_decompressed) free_2(ns1);
	if(ns2_was_decompressed) free_2(ns2);

	return(pnt);
	}
}


/*
 * mvlfac resolution
 */
void import_trace(nptr np)
{
set_window_busy(NULL);

if(GLOBALS->is_lxt)
	{
	import_lxt_trace(np);
	}
else
if(GLOBALS->extload) /*needs to be ahead of is_lx2 as now can be is_lx2 with FsdbReader */
	{
	import_extload_trace(np);
	}
else
if(GLOBALS->is_lx2)
	{
	import_lx2_trace(np);
	}
else
	{
	fprintf(stderr, "Internal error with mvlfac trace handling, exiting.\n");
	exit(255);
	}

set_window_idle(NULL);
}


/*
 * turn a Bits structure into a vector with deltas for faster displaying
 */
bvptr bits2vector(struct Bits *b)
{
int i;
int regions=0;
struct Node *n;
hptr *h;
vptr vhead=NULL, vcurr=NULL, vadd;
int numextrabytes;
TimeType mintime, lasttime=-1;
bvptr bitvec=NULL;
TimeType tshift, tmod;
int is_string;
int string_len;

if(!b) return(NULL);

h=(hptr *)calloc_2(b->nnbits, sizeof(hptr));

numextrabytes=b->nnbits;

for(i=0;i<b->nnbits;i++)
	{
	n=b->nodes[i];
	h[i]=&(n->head);
	}

while(h[0])	/* should never exit through this point the way we set up histents with trailers now */
	{
	mintime=MAX_HISTENT_TIME;

	vadd=(vptr)calloc_2(1,sizeof(struct VectorEnt)+numextrabytes);

	for(i=0;i<b->nnbits;i++) /* was 1...big mistake */
		{
		tshift = (b->attribs) ? b->attribs[i].shift : 0;

		if(h[i]->next)
			{
			if((h[i]->next->time >= 0) && (h[i]->next->time < MAX_HISTENT_TIME-2))
				{
				tmod = h[i]->next->time+tshift;
				if(tmod < 0) tmod = 0;
				if(tmod > MAX_HISTENT_TIME-2) tmod = MAX_HISTENT_TIME-2;
				}
				else
				{
				tmod = h[i]->next->time;	/* don't timeshift endcaps */
				}

			if(tmod < mintime)
				{
				mintime = tmod;
				}
			}
		}

	vadd->time=lasttime;
	lasttime=mintime;

	regions++;

	is_string = 1;
	string_len = 0;
	for(i=0;i<b->nnbits;i++)
                {
		if((h[i]->flags & HIST_STRING))
			{
			if(h[i]->time >= 0)
				{ 
				if(h[i]->v.h_vector)
					{
					if((GLOBALS->loaded_file_type == GHW_FILE) && (h[i]->v.h_vector[0] == '\'') && (h[i]->v.h_vector[1]) && (h[i]->v.h_vector[2] == '\''))
						{
						string_len++;
						}
						else
						{
						string_len += strlen(h[i]->v.h_vector);
						}
					}
				}
			}
			else
			{
			is_string = 0;
			break;
			}
		}

	if(is_string)
		{
		vadd->flags |= HIST_STRING;
		vadd=(vptr)realloc_2(vadd,sizeof(struct VectorEnt)+string_len+1);
		vadd->v[0] = 0;
		}

	for(i=0;i<b->nnbits;i++)
		{
		unsigned char enc;

		tshift = (b->attribs) ? b->attribs[i].shift : 0;

		if(!is_string)
			{
			if((b->attribs)&&(b->attribs[i].flags & TR_INVERT))
				{
				enc  = ((unsigned char)(h[i]->v.h_val));
				switch(enc)	/* don't remember if it's preconverted in all cases; being conservative is OK */
					{
					case AN_0: case '0':
						enc = AN_1; break;
	
					case AN_1: case '1':
						enc = AN_0; break;
	
					case AN_H: case 'h': case 'H':
						enc = AN_L; break;
	
					case AN_L: case 'l': case 'L':
						enc = AN_H; break;
	
					case 'x': case 'X':
						enc = AN_X; break;
	
					case 'z': case 'Z':
						enc = AN_Z; break;
	
					case 'u': case 'U':
						enc = AN_U; break;
	
					case 'w': case 'W':
						enc = AN_W; break;
	
					default:
						enc = enc & AN_MSK; break;
					}
				}
				else
				{
				enc  = ((unsigned char)(h[i]->v.h_val)) & AN_MSK;
				}

			vadd->v[i] = enc;
			}
			else
			{
			if(h[i]->time >= 0)
				{
				if(h[i]->v.h_vector)
					{
					if((GLOBALS->loaded_file_type == GHW_FILE) && (h[i]->v.h_vector[0] == '\'') && (h[i]->v.h_vector[1]) && (h[i]->v.h_vector[2] == '\''))
						{
						char ghw_str[2];
						ghw_str[0] = h[i]->v.h_vector[1];
						ghw_str[1] = 0;
						strcat((char *)vadd->v, ghw_str);
						}
						else
						{
						strcat((char *)vadd->v, h[i]->v.h_vector);
						}
					}			
				}
			}

		if(h[i]->next)
			{
			if((h[i]->next->time >= 0) && (h[i]->next->time < MAX_HISTENT_TIME-2))
				{
				tmod = h[i]->next->time+tshift;
				if(tmod < 0) tmod = 0;
				if(tmod > MAX_HISTENT_TIME-2) tmod = MAX_HISTENT_TIME-2;
				}
				else
				{
				tmod = h[i]->next->time;	/* don't timeshift endcaps */
				}

			if(tmod < mintime)
				{
				mintime = tmod;
				}

			if(tmod == mintime)
				{
				h[i]=h[i]->next;
				}
			}
		}

	if(vhead)
		{
		vcurr->next=vadd;
		vcurr=vadd;
		}
		else
		{
		vhead=vcurr=vadd;
		}

	if(mintime==MAX_HISTENT_TIME) break;	/* normal bail part */
	}

vadd=(vptr)calloc_2(1,sizeof(struct VectorEnt)+numextrabytes);
vadd->time=MAX_HISTENT_TIME;
for(i=0;i<numextrabytes;i++) vadd->v[i]=AN_U; /* formerly 0x55 */
if(vcurr) { vcurr->next=vadd; } /* scan-build */
regions++;

bitvec=(bvptr)calloc_2(1,sizeof(struct BitVector)+((regions)*sizeof(vptr))); /* ajb : found "regions" by manual inspection, changed to "regions-1" as array is already [1] */ /* C99, back to regions with [] */

strcpy(bitvec->bvname=(char *)malloc_2(strlen(b->name)+1),b->name);
bitvec->nbits=b->nnbits;
bitvec->numregions=regions;

vcurr=vhead;
for(i=0;i<regions;i++)
	{
	bitvec->vectors[i]=vcurr;
	if(vcurr) { vcurr=vcurr->next; } /* scan-build */
	}

return(bitvec);
}


/*
 * Make solitary traces from wildcarded signals...
 */
int maketraces(char *str, char *alias, int quick_return)
{
char *pnt, *wild;
char ch, wild_active=0;
int len;
int i;
int made=0;
unsigned int rows = 0;

pnt=str;
while((ch=*pnt))
	{
	if(ch=='*')
		{
		wild_active=1;
		break;
		}
	pnt++;
	}

if(!wild_active)	/* short circuit wildcard evaluation with bsearch */
	{
	struct symbol *s;
	nptr nexp;

	if(str[0]=='(')
		{
		for(i=1;;i++)
			{
			if(str[i]==0) return(0);
			if((str[i]==')')&&(str[i+1])) {i++; break; }
			}

		s=symfind(str+i, &rows);
		if(s)
			{
			nexp = ExtractNodeSingleBit(&s->n[rows], atoi(str+1));
			if(nexp)
				{
				AddNode(nexp, alias);
				return(~0);
				}
			}

		return(0);
		}
		else
		{
		if((s=symfind(str, &rows)))
			{
			AddNode(&s->n[rows],alias);
			return(~0);
			}
			else
			{
			/* in case its a 1-bit bit-blasted signal */
			char *str2;
                        int l = strlen(str);
			str2  = calloc_2(1,l+4);
			strcpy(str2, str);
			str2[l] = '[';
			str2[l+1] = '0';
			str2[l+2] = ']';
			str2[l+3] = 0;
			if((s=symfind(str2, &rows)))
			{
			AddNode(&s->n[rows],alias);
			return(~0);
			}
			else
			return(0);
			}
		}
	}

while(1)
{
pnt=str;
len=0;

while(1)
	{
	ch=*pnt++;
	if(isspace((int)(unsigned char)ch)||(!ch)) break;
	len++;
	}

if(len)
	{
	wild=(char *)calloc_2(1,len+1);
	memcpy(wild,str,len);
	wave_regex_compile(wild, WAVE_REGEX_WILD);

	for(i=0;i<GLOBALS->numfacs;i++)
		{
		if(wave_regex_match(GLOBALS->facs[i]->name, WAVE_REGEX_WILD))
			{
			AddNode(GLOBALS->facs[i]->n,NULL);
			made=~0;
			if(quick_return) break;
			}
		}

	free_2(wild);
	}

if(!ch) break;
str=pnt;
}
return(made);
}


/*
 * Create a vector from wildcarded signals...
 */
struct Bits *makevec(char *vec, char *str)
{
char *pnt, *pnt2, *wild=NULL;
char ch, ch2, wild_active;
int len, nodepnt=0;
int i;
struct Node *n[BITATTRIBUTES_MAX];
struct Bits *b=NULL;
unsigned int rows = 0;

while(1)
{
pnt=str;
len=0;

while(1)
	{
	ch=*pnt++;
	if(isspace((int)(unsigned char)ch)||(!ch)) break;
	len++;
	}

if(len)
	{
	wild=(char *)calloc_2(1,len+1);
	memcpy(wild,str,len);

	DEBUG(printf("WILD: %s\n",wild));

	wild_active=0;
	pnt2=wild;
	while((ch2=*pnt2))
		{
		if(ch2=='*')
			{
			wild_active=1;
			break;
			}
		pnt2++;
		}

	if(!wild_active)	/* short circuit wildcard evaluation with bsearch */
		{
		struct symbol *s;
		if(wild[0]=='(')
			{
			nptr nexp;

			for(i=1;;i++)
				{
				if(wild[i]==0) break;
				if((wild[i]==')')&&(wild[i+1]))
					{
					i++;
					s=symfind(wild+i, &rows);
					if(s)
						{
						nexp = ExtractNodeSingleBit(&s->n[rows], atoi(wild+1));
						if(nexp)
							{
							n[nodepnt++]=nexp;
							if(nodepnt==BITATTRIBUTES_MAX) { free_2(wild); goto ifnode; }
							}
						}
					else
                                              	{
                                                char *lp = strrchr(wild+i, '[');
                                                if(lp)
                                                        {
                                                        char *ns = malloc_2(strlen(wild+i) + 32);
                                                        char *colon = strchr(lp+1, ':');
                                                        int msi, lsi, bval, actual;
                                                        *lp = 0;

                                                        bval = atoi(wild+1);
                                                        if(colon)
                                                                {
                                                                msi = atoi(lp+1);
                                                                lsi = atoi(colon+1);

                                                                if(lsi > msi)
                                                                        {
                                                                        actual = msi + bval;
                                                                        }
                                                                        else
                                                                        {
                                                                        actual = msi - bval;
                                                                        }
                                                                }
                                                                else
                                                                {
                                                                actual = bval; /* punt */
                                                                }

                                                        sprintf(ns, "%s[%d]", wild+i, actual);
                                                        *lp = '[';

                                                        s=symfind(ns, &rows);
                                                        if(s)
                                                                {
								nexp =&s->n[rows];
								if(nexp)
									{
									n[nodepnt++]=nexp;
									if(nodepnt==BITATTRIBUTES_MAX) { free_2(wild); goto ifnode; }
									}
                                                                }

							free_2(ns);
                                                        }
						}
					break;
					}
				}
			}
			else
			{
			if((s=symfind(wild, &rows)))
				{
				n[nodepnt++]=&s->n[rows];
				if(nodepnt==BITATTRIBUTES_MAX) { free_2(wild); goto ifnode; }
				}
			}
		}
		else
		{
		wave_regex_compile(wild, WAVE_REGEX_WILD);
		for(i=GLOBALS->numfacs-1;i>=0;i--)	/* to keep vectors in little endian hi..lo order */
			{
			if(wave_regex_match(GLOBALS->facs[i]->name, WAVE_REGEX_WILD))
				{
				n[nodepnt++]=GLOBALS->facs[i]->n;
				if(nodepnt==BITATTRIBUTES_MAX) { free_2(wild); goto ifnode; }
				}
			}
		}
	free_2(wild);
	}

if(!ch) break;
str=pnt;
}

ifnode:
if(nodepnt)
	{
	b=(struct Bits *)calloc_2(1,sizeof(struct Bits)+(nodepnt)*sizeof(struct Node *));

	for(i=0;i<nodepnt;i++)
		{
		b->nodes[i]=n[i];
		if(n[i]->mv.mvlfac) import_trace(n[i]);
		}

	b->nnbits=nodepnt;
	strcpy(b->name=(char *)malloc_2(strlen(vec)+1),vec);
	}

return(b);
}

/*
 * Create an annotated (b->attribs) vector from stranded signals...
 */
struct Bits *makevec_annotated(char *vec, char *str)
{
char *pnt, *wild=NULL;
char ch;
int len, nodepnt=0;
int i;
struct Node *n[BITATTRIBUTES_MAX];
struct BitAttributes ba[BITATTRIBUTES_MAX];
struct Bits *b=NULL;
int state = 0;
unsigned int rows = 0;

memset(ba, 0, sizeof(ba)); /* scan-build */

while(1)
{
pnt=str;
len=0;

while(1)
	{
	ch=*pnt++;
	if(isspace((int)(unsigned char)ch)||(!ch)) break;
	len++;
	}

if(len)
	{
	wild=(char *)calloc_2(1,len+1);
	memcpy(wild,str,len);

	DEBUG(printf("WILD: %s\n",wild));

	if(state==1)
		{
		ba[nodepnt-1].shift = atoi_64(wild);
		state++;
		goto fw;
		}
	else
	if(state==2)
		{
		sscanf(wild, "%"TRACEFLAGSSCNFMT, &ba[nodepnt-1].flags);
		state = 0;
		goto fw;
		}

	state++;

	/* no wildcards for annotated! */
		{
		struct symbol *s;

		if(nodepnt==BITATTRIBUTES_MAX) { free_2(wild); goto ifnode; }

		if(wild[0]=='(')
			{
			nptr nexp;

			for(i=1;;i++)
				{
				if(wild[i]==0) break;
				if((wild[i]==')')&&(wild[i+1]))
					{
					i++;
					s=symfind(wild+i, &rows);
					if(s)
						{
						nexp = ExtractNodeSingleBit(&s->n[rows], atoi(wild+1));
						if(nexp)
							{
							n[nodepnt++]=nexp;
							if(nodepnt==BITATTRIBUTES_MAX) { free_2(wild); goto ifnode; }
							}
						}
					else
                                              	{
                                                char *lp = strrchr(wild+i, '[');
                                                if(lp)
                                                        {
                                                        char *ns = malloc_2(strlen(wild+i) + 32);
                                                        char *colon = strchr(lp+1, ':');
                                                        int msi, lsi, bval, actual;
                                                        *lp = 0;

                                                        bval = atoi(wild+1);
                                                        if(colon)
                                                                {
                                                                msi = atoi(lp+1);
                                                                lsi = atoi(colon+1);

                                                                if(lsi > msi)
                                                                        {
                                                                        actual = msi + bval;
                                                                        }
                                                                        else
                                                                        {
                                                                        actual = msi - bval;
                                                                        }
                                                                }
                                                                else
                                                                {
                                                                actual = bval; /* punt */
                                                                }

                                                        sprintf(ns, "%s[%d]", wild+i, actual);
                                                        *lp = '[';

                                                        s=symfind(ns, &rows);
                                                        if(s)
                                                                {
								nexp =&s->n[rows];
								if(nexp)
									{
									n[nodepnt++]=nexp;
									if(nodepnt==BITATTRIBUTES_MAX) { free_2(wild); goto ifnode; }
									}
                                                                }

							free_2(ns);
                                                        }
						}

					break;
					}
				}
			}
			else
			{
			if((s=symfind(wild, &rows)))
				{
				n[nodepnt++]=&s->n[rows];
				}
			}
		}

fw:	free_2(wild);
	}

if(!ch) break;
str=pnt;
}

ifnode:
if(nodepnt)
	{
	b=(struct Bits *)calloc_2(1,sizeof(struct Bits)+(nodepnt)*sizeof(struct Node *));

	b->attribs = calloc_2(nodepnt, sizeof(struct BitAttributes));

	for(i=0;i<nodepnt;i++)
		{
		b->nodes[i]=n[i];
		if(n[i]->mv.mvlfac) import_trace(n[i]);

		b->attribs[i].shift = ba[i].shift;
		b->attribs[i].flags = ba[i].flags;
		}

	b->nnbits=nodepnt;
	strcpy(b->name=(char *)malloc_2(strlen(vec)+1),vec);
	}

return(b);
}


/*
 * Create a vector from selected_status signals...
 */
struct Bits *makevec_selected(char *vec, int numrows, char direction)
{
int nodepnt=0;
int i;
struct Node *n[BITATTRIBUTES_MAX];
struct Bits *b=NULL;

if(!direction)
for(i=GLOBALS->numfacs-1;i>=0;i--)	/* to keep vectors in hi..lo order */
	{
	if(get_s_selected(GLOBALS->facs[i]))
		{
		n[nodepnt++]=GLOBALS->facs[i]->n;
		if((nodepnt==BITATTRIBUTES_MAX)||(numrows==nodepnt)) break;
		}
	}
else
for(i=0;i<GLOBALS->numfacs;i++)		/* to keep vectors in lo..hi order */
	{
	if(get_s_selected(GLOBALS->facs[i]))
		{
		n[nodepnt++]=GLOBALS->facs[i]->n;
		if((nodepnt==BITATTRIBUTES_MAX)||(numrows==nodepnt)) break;
		}
	}

if(nodepnt)
	{
	b=(struct Bits *)calloc_2(1,sizeof(struct Bits)+(nodepnt)*sizeof(struct Node *));

	for(i=0;i<nodepnt;i++)
		{
		b->nodes[i]=n[i];
		if(n[i]->mv.mvlfac) import_trace(n[i]);
		}

	b->nnbits=nodepnt;
	strcpy(b->name=(char *)malloc_2(strlen(vec)+1),vec);
	}

return(b);
}

/*
 * add vector made in previous function
 */
int add_vector_selected(char *alias, int numrows, char direction)
{
bvptr v=NULL;
bptr b=NULL;

if((b=makevec_selected(alias, numrows, direction)))
	{
        if((v=bits2vector(b)))
                {
                v->bits=b;      /* only needed for savefile function */
                AddVector(v, NULL);
                free_2(b->name);
                b->name=NULL;
                return(v!=NULL);
                }
                else
                {
                free_2(b->name);
		if(b->attribs) free_2(b->attribs);
                free_2(b);
                }
        }
return(v!=NULL);
}

/***********************************************************************************/

/*
 * Create a vector from a range of signals...currently the single
 * bit facility_name[x] case never gets hit, but may be used in the
 * future...
 */
struct Bits *makevec_chain(char *vec, struct symbol *sym, int len)
{
int nodepnt=0, nodepnt_rev;
int i;
struct Node **n;
struct Bits *b=NULL;
struct symbol *symhi = NULL, *symlo = NULL;
char hier_delimeter2;

if(!GLOBALS->vcd_explicit_zero_subscripts)	/* 0==yes, -1==no */
	{
	hier_delimeter2=GLOBALS->hier_delimeter;
	}
	else
	{
	hier_delimeter2='[';
	}

n=(struct Node **)wave_alloca(len*sizeof(struct Node *));
memset(n, 0, len*sizeof(struct Node *)); /* scan-build */

if(!GLOBALS->autocoalesce_reversal)		/* normal case for MTI */
	{
	symhi=sym;
	while(sym)
		{
		symlo=sym;
		n[nodepnt++]=sym->n;
		sym=sym->vec_chain;
		}
	}
	else				/* for verilog XL */
	{
	nodepnt_rev=len;
	symlo=sym;
	while(sym)
		{
		nodepnt++;
		symhi=sym;
		n[--nodepnt_rev]=sym->n;
		sym=sym->vec_chain;
		}
	}

if(nodepnt)
	{
	b=(struct Bits *)calloc_2(1,sizeof(struct Bits)+(nodepnt)*sizeof(struct Node *));

	for(i=0;i<nodepnt;i++)
		{
		b->nodes[i]=n[i];
		if(n[i]->mv.mvlfac) import_trace(n[i]);
		}

	b->nnbits=nodepnt;

	if(vec)
		{
		strcpy(b->name=(char *)malloc_2(strlen(vec)+1),vec);
		}
		else
		{
		char *s1, *s2;
		int s1_was_packed = HIER_DEPACK_ALLOC, s2_was_packed = HIER_DEPACK_ALLOC;
		int root1len=0, root2len=0;
		int l1, l2;

		s1=symhi->n->nname;
		s2=symlo->n->nname;

		if(GLOBALS->do_hier_compress)
			{
			s1 = hier_decompress_flagged(s1, &s1_was_packed);
			s2 = hier_decompress_flagged(s2, &s2_was_packed);
			}

		l1=strlen(s1);

		for(i=l1-1;i>=0;i--)
			{
			if(s1[i]==hier_delimeter2) { root1len=i+1; break; }
			}

		l2=strlen(s2);
		for(i=l2-1;i>=0;i--)
			{
			if(s2[i]==hier_delimeter2) { root2len=i+1; break; }
			}

		if((root1len!=root2len)||(!root1len)||(!root2len)||
			(strncasecmp(s1,s2,root1len)))
			{
			if(symlo!=symhi)
				{
				if(!b->attribs)
					{
					char *aname = attempt_vecmatch(s1, s2);
					if(aname) b->name = aname; else { strcpy(b->name=(char *)malloc_2(8+1),"<Vector>"); }
					}
					else
					{
					char *aname = attempt_vecmatch(s1, s2);
					if(aname) b->name = aname; else { strcpy(b->name=(char *)malloc_2(15+1),"<ComplexVector>"); }
					}
				}
				else
				{
				strcpy(b->name=(char *)malloc_2(l1+1),s1);
				}
			}
			else
			{
			int add1, add2, totallen;

			add1=l1-root1len; add2=l2-root2len;
			if(GLOBALS->vcd_explicit_zero_subscripts==-1)
				{
				add1--;
				add2--;
				}

			if(symlo!=symhi)
				{
				unsigned char fixup1 = 0, fixup2 = 0;

				totallen=
					root1len
					-1		/* zap HIER_DELIMETER */
					+1		/* add [              */
					+add1		/* left value	      */
					+1		/* add :	      */
					+add2		/* right value	      */
					+1		/* add ]	      */
					+1		/* add 0x00	      */
					;

				if(GLOBALS->vcd_explicit_zero_subscripts==-1)
					{
					fixup1=*(s1+l1-1); *(s1+l1-1)=0;
					fixup2=*(s2+l2-1); *(s2+l2-1)=0;
					}

				b->name=(char *)malloc_2(totallen);
				strncpy(b->name,s1,root1len-1);
				sprintf(b->name+root1len-1,"[%s:%s]",s1+root1len, s2+root2len);

				if(GLOBALS->vcd_explicit_zero_subscripts==-1)
					{
					*(s1+l1-1)=fixup1;
					*(s2+l2-1)=fixup2;
					}
				}
				else
				{
				unsigned char fixup1 = 0;

				totallen=
					root1len
					-1		/* zap HIER_DELIMETER */
					+1		/* add [              */
					+add1		/* left value	      */
					+1		/* add ]	      */
					+1		/* add 0x00	      */
					;

				if(GLOBALS->vcd_explicit_zero_subscripts==-1)
					{
					fixup1=*(s1+l1-1); *(s1+l1-1)=0;
					}

				b->name=(char *)malloc_2(totallen);
				strncpy(b->name,s1,root1len-1);
				sprintf(b->name+root1len-1,"[%s]",s1+root1len);

				if(GLOBALS->vcd_explicit_zero_subscripts==-1)
					{
					*(s1+l1-1)=fixup1;
					}
				}
			}

		if(GLOBALS->do_hier_compress)
			{
			if(s2_was_packed) free_2(s2);
			if(s1_was_packed) free_2(s1);
			}
		}
	}

return(b);
}

/*
 * add vector made in previous function
 */
int add_vector_chain(struct symbol *s, int len)
{
bvptr v=NULL;
bptr b=NULL;

if(len>1)
	{
	if((b=makevec_chain(NULL, s, len)))
		{
	        if((v=bits2vector(b)))
	                {
	                v->bits=b;      /* only needed for savefile function */
	                AddVector(v, NULL);
	                free_2(b->name);
	                b->name=NULL;
	                return(v!=NULL);
	                }
	                else
	                {
	                free_2(b->name);
			if(b->attribs) free_2(b->attribs);
	                free_2(b);
	                }
	        }
	return(v!=NULL);
	}
	else
	{
	return(AddNode(s->n,NULL));
	}
}

/***********************************************************************************/

/*
 * Create a vector from a range of signals...currently the single
 * bit facility_name[x] case never gets hit, but may be used in the
 * future...
 */
struct Bits *makevec_range(char *vec, int lo, int hi, char direction)
{
int nodepnt=0;
int i;
struct Node *n[BITATTRIBUTES_MAX];
struct Bits *b=NULL;

if(!direction)
for(i=hi;i>=lo;i--)	/* to keep vectors in hi..lo order */
	{
	n[nodepnt++]=GLOBALS->facs[i]->n;
	if(nodepnt==BITATTRIBUTES_MAX) break;
	}
else
for(i=lo;i<=hi;i++)	/* to keep vectors in lo..hi order */
	{
	n[nodepnt++]=GLOBALS->facs[i]->n;
	if(nodepnt==BITATTRIBUTES_MAX) break;
	}

if(nodepnt)
	{
	b=(struct Bits *)calloc_2(1,sizeof(struct Bits)+(nodepnt)*sizeof(struct Node *));

	for(i=0;i<nodepnt;i++)
		{
		b->nodes[i]=n[i];
		if(n[i]->mv.mvlfac) import_trace(n[i]);
		}

	b->nnbits=nodepnt;

	if(vec)
		{
		strcpy(b->name=(char *)malloc_2(strlen(vec)+1),vec);
		}
		else
		{
		char *s1, *s2;
		int s1_was_packed = HIER_DEPACK_ALLOC, s2_was_packed = HIER_DEPACK_ALLOC;
		int root1len=0, root2len=0;
		int l1, l2;

		if(!direction)
			{
			s1=GLOBALS->facs[hi]->n->nname;
			s2=GLOBALS->facs[lo]->n->nname;
			}
			else
			{
			s1=GLOBALS->facs[lo]->n->nname;
			s2=GLOBALS->facs[hi]->n->nname;
			}

		if(GLOBALS->do_hier_compress)
			{
			s1 = hier_decompress_flagged(s1, &s1_was_packed);
			s2 = hier_decompress_flagged(s2, &s2_was_packed);
			}

		l1=strlen(s1);

		for(i=l1-1;i>=0;i--)
			{
			if(s1[i]==GLOBALS->hier_delimeter) { root1len=i+1; break; }
			}

		l2=strlen(s2);
		for(i=l2-1;i>=0;i--)
			{
			if(s2[i]==GLOBALS->hier_delimeter) { root2len=i+1; break; }
			}

		if((root1len!=root2len)||(!root1len)||(!root2len)||
			(strncasecmp(s1,s2,root1len)))
			{
			if(lo!=hi)
				{
				if(!b->attribs)
					{
					char *aname = attempt_vecmatch(s1, s2);
					if(aname) b->name = aname; else { strcpy(b->name=(char *)malloc_2(8+1),"<Vector>"); }
					}
					else
					{
					char *aname = attempt_vecmatch(s1, s2);
					if(aname) b->name = aname; else { strcpy(b->name=(char *)malloc_2(15+1),"<ComplexVector>"); }
					}
				}
				else
				{
				strcpy(b->name=(char *)malloc_2(l1+1),s1);
				}
			}
			else
			{
			int add1, add2, totallen;

			add1=l1-root1len; add2=l2-root2len;

			if(lo!=hi)
				{
				totallen=
					root1len
					-1		/* zap HIER_DELIMETER */
					+1		/* add [              */
					+add1		/* left value	      */
					+1		/* add :	      */
					+add2		/* right value	      */
					+1		/* add ]	      */
					+1		/* add 0x00	      */
					;

				b->name=(char *)malloc_2(totallen);
				strncpy(b->name,s1,root1len-1);
				sprintf(b->name+root1len-1,"[%s:%s]",s1+root1len, s2+root2len);
				}
				else
				{
				totallen=
					root1len
					-1		/* zap HIER_DELIMETER */
					+1		/* add [              */
					+add1		/* left value	      */
					+1		/* add ]	      */
					+1		/* add 0x00	      */
					;

				b->name=(char *)malloc_2(totallen);
				strncpy(b->name,s1,root1len-1);
				sprintf(b->name+root1len-1,"[%s]",s1+root1len);
				}
			}
		if(GLOBALS->do_hier_compress)
			{
			if(s2_was_packed) free_2(s2);
			if(s1_was_packed) free_2(s1);
			}
		}
	}

return(b);
}

/*
 * add vector made in previous function
 */
int add_vector_range(char *alias, int lo, int hi, char direction)
{
bvptr v=NULL;
bptr b=NULL;

if(lo!=hi)
	{
	if((b=makevec_range(alias, lo, hi, direction)))
		{
	        if((v=bits2vector(b)))
	                {
	                v->bits=b;      /* only needed for savefile function */
	                AddVector(v, NULL);
	                free_2(b->name);
	                b->name=NULL;
	                return(v!=NULL);
	                }
	                else
	                {
	                free_2(b->name);
			if(b->attribs) free_2(b->attribs);
	                free_2(b);
	                }
	        }
	return(v!=NULL);
	}
	else
	{
	return(AddNode(GLOBALS->facs[lo]->n,NULL));
	}
}


/*
 * splits facility name into signal and bitnumber
 */
void facsplit(char *str, int *len, int *number)
{
char *ptr;
char *numptr=NULL;
char ch;

ptr=str;

while((ch=*ptr))
        {
        if((ch>='0')&&(ch<='9'))
                {
                if(!numptr) numptr=ptr;
                }
                else numptr=NULL;
        ptr++;
        }

if(numptr)
        {
        *number=atoi(numptr);
        *len=numptr-str;
        }
        else
        {
        *number=0;
        *len=ptr-str;
        }
}


/*
 * compares two facilities a la strcmp but preserves
 * numbers for comparisons
 *
 * there are two flavors..the slow and accurate to any
 * arbitrary number of digits version (first) and the
 * fast one good to 2**31-1.  we default to the faster
 * version since there's probably no real need to
 * process ints larger than two billion anyway...
 */

#ifdef WAVE_USE_SIGCMP_INFINITE_PRECISION
#if __STDC_VERSION__ < 199901L
inline
#endif
int sigcmp_2(char *s1, char *s2)
{
char *n1, *n2;
unsigned char c1, c2;
int len1, len2;

for(;;)
	{
	c1=(unsigned char)*s1;
	c2=(unsigned char)*s2;

	if((c1==0)&&(c2==0)) return(0);
	if((c1>='0')&&(c1<='9')&&(c2>='0')&&(c2<='9'))
		{
		n1=s1; n2=s2;
		len1=len2=0;

		do	{
			len1++;
			c1=(unsigned char)*(n1++);
			} while((c1>='0')&&(c1<='9'));
		if(!c1) n1--;

		do	{
			len2++;
			c2=(unsigned char)*(n2++);
			} while((c2>='0')&&(c2<='9'));
		if(!c2) n2--;

		do	{
			if(len1==len2)
				{
				c1=(unsigned char)*(s1++);
				len1--;
				c2=(unsigned char)*(s2++);
				len2--;
				}
			else
			if(len1<len2)
				{
				c1='0';
				c2=(unsigned char)*(s2++);
				len2--;
				}
			else
				{
				c1=(unsigned char)*(s1++);
				len1--;
				c2='0';
				}

			if(c1!=c2) return((int)c1-(int)c2);
			} while(len1);

		s1=n1; s2=n2;
		continue;
		}
		else
		{
		if(c1!=c2) return((int)c1-(int)c2);
		}

	s1++; s2++;
	}
}
#else
#if __STDC_VERSION__ < 199901L
inline
#endif
int sigcmp_2(char *s1, char *s2)
{
unsigned char c1, c2;
int u1, u2;

for(;;)
	{
	c1=(unsigned char)*(s1++);
	c2=(unsigned char)*(s2++);

	if(!(c1|c2)) return(0);	/* removes extra branch through logical or */
	if((c1<='9')&&(c2<='9')&&(c2>='0')&&(c1>='0'))
		{
		u1=(int)(c1&15);
		u2=(int)(c2&15);

		while(((c2=(unsigned char)*s2)>='0')&&(c2<='9'))
			{
			u2*=10;
			u2+=(unsigned int)(c2&15);
			s2++;
			}

		while(((c2=(unsigned char)*s1)>='0')&&(c2<='9'))
			{
			u1*=10;
			u1+=(unsigned int)(c2&15);
			s1++;
			}

		if(u1==u2) continue;
			else return((int)u1-(int)u2);
		}
		else
		{
		if(c1!=c2) return((int)c1-(int)c2);
		}
	}
}
#endif

int sigcmp(char *s1, char *s2)
{
int rc = sigcmp_2(s1, s2);
if(!rc)
	{
	rc = strcmp(s1, s2); /* to handle leading zero "0" vs "00" cases ... we provide a definite order so bsearch doesn't fail */
	}

return(rc);
}


#ifndef __linux__
/*
 * heapsort algorithm.  this typically outperforms quicksort.  note
 * that glibc will use a modified mergesort if memory is available, so
 * under linux use the stock qsort instead.
 */
static struct symbol **hp;
static void heapify(int i, int heap_size)
{
int l, r;
int largest;
struct symbol *t;
int maxele=heap_size/2-1;	/* points to where heapswaps don't matter anymore */

for(;;)
        {
        l=2*i+1;
        r=l+1;

        if((l<heap_size)&&(sigcmp(hp[l]->name,hp[i]->name)>0))
                {
                largest=l;
                }
                else
                {
                largest=i;
                }
        if((r<heap_size)&&(sigcmp(hp[r]->name,hp[largest]->name)>0))
                {
                largest=r;
                }

        if(i!=largest)
                {
                t=hp[i];
                hp[i]=hp[largest];
                hp[largest]=t;

                if(largest<=maxele)
                        {
                        i=largest;
                        }
                        else
                        {
                        break;
                        }
                }
                else
                {
                break;
                }
        }
}

void wave_heapsort(struct symbol **a, int num)
{
int i;
int indx=num-1;
struct symbol *t;

hp=a;

for(i=(num/2-1);i>0;i--)	/* build facs into having heap property */
        {
        heapify(i,num);
        }

for(;;)
	{
        if(indx) heapify(0,indx+1);
	DEBUG(printf("%s\n", a[0]->name));

	if(indx!=0)
		{
		t=a[0];			/* sort in place by doing a REVERSE sort and */
		a[0]=a[indx];		/* swapping the front and back of the tree.. */
		a[indx--]=t;
		}
		else
		{
		break;
		}
	}
}

#else

static int qssigcomp(const void *v1, const void *v2)
{
struct symbol *a1 = *((struct symbol **)v1);
struct symbol *a2 = *((struct symbol **)v2);
return(sigcmp(a1->name, a2->name));
}

void wave_heapsort(struct symbol **a, int num)
{
qsort(a, num, sizeof(struct symbol *), qssigcomp);
}

#endif

/*
 * Malloc/Create a name from a range of signals starting from vec_root...currently the single
 * bit facility_name[x] case never gets hit, but may be used in the
 * future...
 */
char *makename_chain(struct symbol *sym)
{
int i;
struct symbol *symhi = NULL, *symlo = NULL;
char hier_delimeter2;
char *name=NULL;
char *s1, *s2;
int s1_was_packed = HIER_DEPACK_ALLOC, s2_was_packed = HIER_DEPACK_ALLOC;
int root1len=0, root2len=0;
int l1, l2;

if(!sym)
	{
	fprintf(stderr, "Internal error '%s' line %d, exiting.\n", __FILE__, __LINE__);
	exit(255);
	}

if(!GLOBALS->vcd_explicit_zero_subscripts)	/* 0==yes, -1==no */
	{
	hier_delimeter2=GLOBALS->hier_delimeter;
	}
	else
	{
	hier_delimeter2='[';
	}

if(!GLOBALS->autocoalesce_reversal)		/* normal case for MTI */
	{
	symhi=sym;
	symlo=sym; /* scan-build */
	while(sym)
		{
		symlo=sym;
		sym=sym->vec_chain;
		}
	}
	else				/* for verilog XL */
	{
	symlo=sym;
	symhi=sym; /* scan-build */
	while(sym)
		{
		symhi=sym;
		sym=sym->vec_chain;
		}
	}


s1=hier_decompress_flagged(symhi->n->nname, &s1_was_packed);
s2=hier_decompress_flagged(symlo->n->nname, &s2_was_packed);

l1=strlen(s1);

for(i=l1-1;i>=0;i--)
	{
	if(s1[i]==hier_delimeter2) { root1len=i+1; break; }
	}

l2=strlen(s2);
for(i=l2-1;i>=0;i--)
	{
	if(s2[i]==hier_delimeter2) { root2len=i+1; break; }
	}

if((root1len!=root2len)||(!root1len)||(!root2len)||
	(strncasecmp(s1,s2,root1len)))
	{
	if(symlo!=symhi)
		{
		char *aname = attempt_vecmatch(s1, s2);
		if(aname) name = aname; else { strcpy(name=(char *)malloc_2(8+1),"<Vector>"); }
		}
		else
		{
		strcpy(name=(char *)malloc_2(l1+1),s1);
		}
	}
	else
	{
	int add1, add2, totallen;

	add1=l1-root1len; add2=l2-root2len;
	if(GLOBALS->vcd_explicit_zero_subscripts==-1)
		{
		add1--;
		add2--;
		}

	if(symlo!=symhi)
		{
		unsigned char fixup1 = 0, fixup2 = 0;

		totallen=
			root1len
			-1		/* zap HIER_DELIMETER */
			+1		/* add [              */
			+add1		/* left value	      */
			+1		/* add :	      */
			+add2		/* right value	      */
			+1		/* add ]	      */
			+1		/* add 0x00	      */
			;

		if(GLOBALS->vcd_explicit_zero_subscripts==-1)
			{
			fixup1=*(s1+l1-1); *(s1+l1-1)=0;
			fixup2=*(s2+l2-1); *(s2+l2-1)=0;
			}

		name=(char *)malloc_2(totallen);
		strncpy(name,s1,root1len-1);
		sprintf(name+root1len-1,"[%s:%s]",s1+root1len, s2+root2len);

		if(GLOBALS->vcd_explicit_zero_subscripts==-1)
			{
			*(s1+l1-1)=fixup1;
			*(s2+l2-1)=fixup2;
			}
		}
		else
		{
		unsigned char fixup1 = 0;

		totallen=
			root1len
			-1		/* zap HIER_DELIMETER */
			+1		/* add [              */
			+add1		/* left value	      */
			+1		/* add ]	      */
			+1		/* add 0x00	      */
			;

		if(GLOBALS->vcd_explicit_zero_subscripts==-1)
			{
			fixup1=*(s1+l1-1); *(s1+l1-1)=0;
			}

		name=(char *)malloc_2(totallen);
		strncpy(name,s1,root1len-1);
		sprintf(name+root1len-1,"[%s]",s1+root1len);

		if(GLOBALS->vcd_explicit_zero_subscripts==-1)
			{
			*(s1+l1-1)=fixup1;
			}
		}
	}

if(s1_was_packed) { free_2(s1); }
if(s2_was_packed) { free_2(s2); }

return(name);
}

/******************************************************************/

eptr ExpandNode(nptr n)
{
int width;
int msb, lsb, delta;
int actual;
hptr h, htemp;
int i, j;
nptr *narray;
char *nam;
int offset, len;
eptr rc=NULL;
exptr exp1;

int row_hi = 0, row_lo = 0, new_msi = 0, new_lsi = 0;
int row_delta = 0, bit_delta = 0;
int curr_row = 0, curr_bit = 0;
int is_2d = 0;

if(n->mv.mvlfac) import_trace(n);

if(!n->extvals)
	{
	DEBUG(fprintf(stderr, "Nothing to expand\n"));
	}
	else
	{
	char *namex;
	int was_packed = HIER_DEPACK_ALLOC;

	msb = n->msi;
	lsb = n->lsi;
	if(msb>lsb)
		{
		width = msb - lsb + 1;
		delta = -1;
		}
		else
		{
		width = lsb - msb + 1;
		delta = 1;
		}
	actual = msb;

	narray=(nptr *)malloc_2(width*sizeof(nptr));
	rc = malloc_2(sizeof(ExpandInfo));
	rc->narray = narray;
	rc->msb = msb;
	rc->lsb = lsb;
	rc->width = width;

	if(GLOBALS->do_hier_compress)
		{
		namex = hier_decompress_flagged(n->nname, &was_packed);
		}
		else
		{
		namex = n->nname;
		}

	offset = strlen(namex);
	for(i=offset-1;i>=0;i--)
		{
		if(namex[i]=='[') break;
		}
	if((i>-1) && strchr(namex+i+1, ':')) /* remove at '[' if this is a ranged signal */
		{
		offset=i;
		}

	if(i>3)
		{
		if(namex[i-1]==']')
			{
			int colon_seen = 0;
			j = i-2;
		        for(;j>=0;j--)
		                {
                		if(namex[j]=='[') break;
				if(namex[j]==':') colon_seen = 1;
                		}  

			if((j>-1)&&(colon_seen))
				{
				int items = sscanf(namex+j, "[%d:%d][%d:%d]", &row_hi, &row_lo, &new_msi, &new_lsi);
				if(items == 4)
					{
					/* printf(">> %d %d %d %d (items = %d)\n", row_hi, row_lo, new_msi, new_lsi, items); */

					row_delta = (row_hi > row_lo)   ? -1 : 1;
					bit_delta = (new_msi > new_lsi) ? -1 : 1;

					curr_row = row_hi;
					curr_bit = new_msi;

					is_2d = (((row_lo - row_hi) * row_delta) + 1) * (((new_lsi - new_msi) * bit_delta) + 1) == width;
					if(is_2d) offset = j;
					}
				}
			}
		}

	nam=(char *)wave_alloca(offset+20+30);
	memcpy(nam, namex, offset);

	if(was_packed)
		{
		free_2(namex);
		}

	if(!n->harray)         /* make quick array lookup for aet display--normally this is done in addnode */
	        {
		hptr histpnt;
		int histcount;
		hptr *harray;

	        histpnt=&(n->head);
	        histcount=0;

	        while(histpnt)
	                {
	                histcount++;
	                histpnt=histpnt->next;
	                }

	        n->numhist=histcount;

	        if(!(n->harray=harray=(hptr *)malloc_2(histcount*sizeof(hptr))))
	                {
	                fprintf( stderr, "Out of memory, can't add to analyzer\n");
	                return(NULL);
	                }

	        histpnt=&(n->head);
	        for(i=0;i<histcount;i++)
	                {
	                *harray=histpnt;
	                harray++;
	                histpnt=histpnt->next;
	                }
	        }

	h=&(n->head);
	while(h)
		{
		if(h->flags & (HIST_REAL|HIST_STRING)) return(NULL);
		h=h->next;
		}

	DEBUG(fprintf(stderr, "Expanding: (%d to %d) for %d bits over %d entries.\n", msb, lsb, width, n->numhist));

	for(i=0;i<width;i++)
		{
		narray[i] = (nptr)calloc_2(1, sizeof(struct Node));
		if(!is_2d)
			{
			sprintf(nam+offset, "[%d]", actual);
			}
			else
			{
			sprintf(nam+offset, "[%d][%d]", curr_row, curr_bit);
			if(curr_bit == new_lsi)
				{
				curr_bit = new_msi;
				curr_row += row_delta;
				}
				else
				{
				curr_bit += bit_delta;
				}
			}
#ifdef WAVE_ARRAY_SUPPORT
		if(n->array_height)
			{
			len = offset + strlen(nam+offset);
			sprintf(nam+len, "{%d}", n->this_row);
			}
#endif
		len = offset + strlen(nam+offset);
		narray[i]->nname = (char *)malloc_2(len+1);
		strcpy(narray[i]->nname, nam);

		exp1 = (exptr) calloc_2(1, sizeof(struct ExpandReferences));
		exp1->parent=n;							/* point to parent */
		exp1->parentbit=i;
		exp1->actual = actual;
		actual += delta;
		narray[i]->expansion = exp1;					/* can be safely deleted if expansion set like here */
		}

	for(i=0;i<n->numhist;i++)
		{
		h=n->harray[i];
		if((h->time<GLOBALS->min_time)||(h->time>GLOBALS->max_time))
			{
			for(j=0;j<width;j++)
				{
				if(narray[j]->curr)
					{
					htemp = (hptr) calloc_2(1, sizeof(struct HistEnt));
					htemp->v.h_val = AN_X;			/* 'x' */
					htemp->time = h->time;
					narray[j]->curr->next = htemp;
					narray[j]->curr = htemp;
					}
					else
					{
					narray[j]->head.v.h_val = AN_X;		/* 'x' */
					narray[j]->head.time  = h->time;
					narray[j]->curr = &(narray[j]->head);
					}

				narray[j]->numhist++;
				}
			}
			else
			{
			for(j=0;j<width;j++)
				{
				unsigned char val = h->v.h_vector[j];
				switch(val)
					{
					case '0':		val = AN_0; break;
					case '1':		val = AN_1; break;
					case 'x': case 'X':	val = AN_X; break;
					case 'z': case 'Z':	val = AN_Z; break;
					case 'h': case 'H':	val = AN_H; break;
					case 'l': case 'L':	val = AN_L; break;
					case 'u': case 'U':	val = AN_U; break;
					case 'w': case 'W':	val = AN_W; break;
					case '-':		val = AN_DASH; break;
					default:	break;			/* leave val alone as it's been converted already.. */
					}

				if(narray[j]->curr->v.h_val != val) 		/* curr will have been established already by 'x' at time: -1 */
					{
					htemp = (hptr) calloc_2(1, sizeof(struct HistEnt));
					htemp->v.h_val = val;
					htemp->time = h->time;
					narray[j]->curr->next = htemp;
					narray[j]->curr = htemp;
					narray[j]->numhist++;
					}
				}
			}
		}

	for(i=0;i<width;i++)
		{
		narray[i]->harray = (hptr *)calloc_2(narray[i]->numhist, sizeof(hptr));
		htemp = &(narray[i]->head);
		for(j=0;j<narray[i]->numhist;j++)
			{
			narray[i]->harray[j] = htemp;
			htemp = htemp->next;
			}
		}

	}

return(rc);
}

/******************************************************************/

nptr ExtractNodeSingleBit(nptr n, int bit)
{
int lft, rgh;
hptr h, htemp;
int i, j;
int actual;
nptr np;
char *nam;
int offset, len, width;
exptr exp1;

int row_hi = 0, row_lo = 0, new_msi = 0, new_lsi = 0;
int row_delta = 0, bit_delta = 0;
int curr_row = 0, curr_bit = 0;
int is_2d = 0;

if(n->mv.mvlfac) import_trace(n);

if(!n->extvals)
	{
	DEBUG(fprintf(stderr, "Nothing to expand\n"));
	return(NULL);
	}
	else
	{
	char *namex;
	int was_packed = HIER_DEPACK_ALLOC;

	if(n->lsi > n->msi)
		{
		width = n->lsi - n->msi + 1;
		rgh = n->lsi; lft = n->msi;
		actual = n->msi + bit;
		}
		else
		{
		width = n->msi - n->lsi + 1;
		rgh = n->msi; lft = n->lsi;
		actual = n->msi - bit;
		}

	if((actual>rgh)||(actual<lft))
		{
		DEBUG(fprintf(stderr, "Out of range\n"));
		return(NULL);
		}

	if(GLOBALS->do_hier_compress)
		{
		namex = hier_decompress_flagged(n->nname, &was_packed);
		}
		else
		{
		namex = n->nname;
		}

	offset = strlen(namex);
	for(i=offset-1;i>=0;i--)
		{
		if(namex[i]=='[') break;
		}
	if((i>-1) && strchr(namex+i+1, ':')) /* remove at '[' if this is a ranged signal */
		{
		offset=i;
		}

	if(i>3)
		{
		if(namex[i-1]==']')
			{
			int colon_seen = 0;
			j = i-2;
		        for(;j>=0;j--)
		                {
                		if(namex[j]=='[') break;
				if(namex[j]==':') colon_seen = 1;
                		}  

			if((j>-1)&&(colon_seen))
				{
				int items = sscanf(namex+j, "[%d:%d][%d:%d]", &row_hi, &row_lo, &new_msi, &new_lsi);
				if(items == 4)
					{
					/* printf("bit >> %d %d %d %d (items = %d)\n", row_hi, row_lo, new_msi, new_lsi, items); */

					row_delta = (row_hi > row_lo)   ? -1 : 1;
					bit_delta = (new_msi > new_lsi) ? -1 : 1;

					curr_row = row_hi;
					curr_bit = new_msi;

					is_2d = (((row_lo - row_hi) * row_delta) + 1) * (((new_lsi - new_msi) * bit_delta) + 1) == width;
					if(is_2d) offset = j;
					}
				}
			}
		}

	nam=(char *)wave_alloca(offset+20);
	memcpy(nam, namex, offset);

	if(was_packed)
		{
		free_2(namex);
		}

	if(!n->harray)         /* make quick array lookup for aet display--normally this is done in addnode */
	        {
		hptr histpnt;
		int histcount;
		hptr *harray;

	        histpnt=&(n->head);
	        histcount=0;

	        while(histpnt)
	                {
	                histcount++;
	                histpnt=histpnt->next;
	                }

	        n->numhist=histcount;

	        if(!(n->harray=harray=(hptr *)malloc_2(histcount*sizeof(hptr))))
	                {
	                DEBUG(fprintf( stderr, "Out of memory, can't add to analyzer\n"));
	                return(NULL);
	                }

	        histpnt=&(n->head);
	        for(i=0;i<histcount;i++)
	                {
	                *harray=histpnt;
	                harray++;
	                histpnt=histpnt->next;
	                }
	        }

	h=&(n->head);
	while(h)
		{
		if(h->flags & (HIST_REAL|HIST_STRING)) return(NULL);
		h=h->next;
		}

	DEBUG(fprintf(stderr, "Extracting: (%d to %d) for offset #%d over %d entries.\n", n->msi, n->lsi, bit, n->numhist));

	np = (nptr)calloc_2(1, sizeof(struct Node));


	if(!is_2d)
		{
		sprintf(nam+offset, "[%d]", actual);
		}
		else
		{
		for(i=0;i<bit;i++)
			{
			if(curr_bit == new_lsi)
				{
				curr_bit = new_msi;
				curr_row += row_delta;
				}
				else
				{
				curr_bit += bit_delta;
				}
			}
		sprintf(nam+offset, "[%d][%d]", curr_row, curr_bit);
		}

#ifdef WAVE_ARRAY_SUPPORT
        if(n->array_height)
        	{
                len = offset + strlen(nam+offset);
                sprintf(nam+len, "{%d}", n->this_row);
                }
#endif
	len = offset + strlen(nam+offset);


	np->nname = (char *)malloc_2(len+1);
	strcpy(np->nname, nam);

	exp1 = (exptr) calloc_2(1, sizeof(struct ExpandReferences));
	exp1->parent=n;							/* point to parent */
	exp1->parentbit=bit;
	exp1->actual=actual;						/* actual bitnum in [] */
	np->expansion = exp1;						/* can be safely deleted if expansion set like here */

	for(i=0;i<n->numhist;i++)
		{
		h=n->harray[i];
		if((h->time<GLOBALS->min_time)||(h->time>GLOBALS->max_time))
			{
			if(np->curr)
				{
				htemp = (hptr) calloc_2(1, sizeof(struct HistEnt));
				htemp->v.h_val = AN_X;			/* 'x' */
				htemp->time = h->time;
				np->curr->next = htemp;
				np->curr = htemp;
				}
				else
				{
				np->head.v.h_val = AN_X;		/* 'x' */
				np->head.time  = h->time;
				np->curr = &(np->head);
				}

			np->numhist++;
			}
			else
			{
			unsigned char val = h->v.h_vector[bit];
			switch(val)
				{
				case '0':		val = AN_0; break;
				case '1':		val = AN_1; break;
				case 'x': case 'X':	val = AN_X; break;
				case 'z': case 'Z':	val = AN_Z; break;
				case 'h': case 'H':	val = AN_H; break;
				case 'l': case 'L':	val = AN_L; break;
				case 'u': case 'U':	val = AN_U; break;
				case 'w': case 'W':	val = AN_W; break;
				case '-':		val = AN_DASH; break;
				default:	break;			/* leave val alone as it's been converted already.. */
				}

			if(np->curr->v.h_val != val) 		/* curr will have been established already by 'x' at time: -1 */
				{
				htemp = (hptr) calloc_2(1, sizeof(struct HistEnt));
				htemp->v.h_val = val;
				htemp->time = h->time;
				np->curr->next = htemp;
				np->curr = htemp;
				np->numhist++;
				}
			}
		}

	np->harray = (hptr *)calloc_2(np->numhist, sizeof(hptr));
	htemp = &(np->head);
	for(j=0;j<np->numhist;j++)
		{
		np->harray[j] = htemp;
		htemp = htemp->next;
		}

	return(np);
	}
}

/******************************************************************/

/*
 * this only frees nodes created via expansion in ExpandNode() functions above!
 */
void DeleteNode(nptr n)
{
int i;

if(n->expansion)
	{
	if(n->expansion->refcnt==0)
		{
		for(i=1;i<n->numhist;i++)	/* 1st is actually part of the Node! */
			{
			free_2(n->harray[i]);
			}
		free_2(n->harray);
		free_2(n->expansion);
		free_2(n->nname);
		free_2(n);
		}
		else
		{
		n->expansion->refcnt--;
		}
	}
}
