/*
 * Copyright (c) 2001-2012 Tony Bybell.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

#include <config.h>
#include "lxt_write.h"

/*
 * in-place sort to keep chained facs from migrating...
 */
static void wave_mergesort(struct lt_symbol **a, struct lt_symbol **b, int lo, int hi)
{
int i, j, k;

if (lo<hi)
	{
        int mid=(lo+hi)/2;

        wave_mergesort(a, b, lo, mid);
        wave_mergesort(a, b, mid+1, hi);

    	i=0; j=lo;
    	while (j<=mid)
		{
        	b[i++]=a[j++];
		}

    	i=0; k=lo;
    	while ((k<j)&&(j<=hi))
		{
        	if (strcmp(b[i]->name, a[j]->name) <= 0)
			{
            		a[k++]=b[i++];
			}
			else
			{
	            	a[k++]=a[j++];
			}
		}

    	while (k<j)
		{
        	a[k++]=b[i++];
		}
	}
}

static void wave_msort(struct lt_symbol **a, int num)
{
struct lt_symbol **b = malloc(((num/2)+1) * sizeof(struct lt_symbol *));

wave_mergesort(a, b, 0, num-1);

free(b);
}

/************************ splay ************************/

static int dslxt_success;

static dslxt_Tree * dslxt_splay (char *i, dslxt_Tree * t) {
/* Simple top down splay, not requiring i to be in the tree t.  */
/* What it does is described above.                             */
    dslxt_Tree N, *l, *r, *y;
    int dir;

    dslxt_success = 0;

    if (t == NULL) return t;
    N.left = N.right = NULL;
    l = r = &N;

    for (;;) {
	dir = strcmp(i, t->item);
	if (dir < 0) {
	    if (t->left == NULL) break;
	    if (strcmp(i, t->left->item)<0) {
		y = t->left;                           /* rotate right */
		t->left = y->right;
		y->right = t;
		t = y;
		if (t->left == NULL) break;
	    }
	    r->left = t;                               /* link right */
	    r = t;
	    t = t->left;
	} else if (dir > 0) {
	    if (t->right == NULL) break;
	    if (strcmp(i, t->right->item)>0) {
		y = t->right;                          /* rotate left */
		t->right = y->left;
		y->left = t;
		t = y;
		if (t->right == NULL) break;
	    }
	    l->right = t;                              /* link left */
	    l = t;
	    t = t->right;
	} else {
	    dslxt_success=1;
	    break;
	}
    }
    l->right = t->left;                                /* assemble */
    r->left = t->right;
    t->left = N.right;
    t->right = N.left;
    return t;
}


static dslxt_Tree * dslxt_insert(char *i, dslxt_Tree * t, unsigned int val) {
/* Insert i into the tree t, unless it's already there.    */
/* Return a pointer to the resulting tree.                 */
    dslxt_Tree * n;
    int dir;

    n = (dslxt_Tree *) calloc (1, sizeof (dslxt_Tree));
    if (n == NULL) {
	fprintf(stderr, "dslxt_insert: ran out of memory, exiting.\n");
	exit(255);
    }
    n->item = i;
    n->val  = val;
    if (t == NULL) {
	n->left = n->right = NULL;
	return n;
    }
    t = dslxt_splay(i,t);
    dir = strcmp(i,t->item);
    if (dir<0) {
	n->left = t->left;
	n->right = t;
	t->left = NULL;
	return n;
    } else if (dir>0) {
	n->right = t->right;
	n->left = t;
	t->right = NULL;
	return n;
    } else { /* We get here if it's already in the tree */
             /* Don't add it again                      */
	free(n);
	return t;
    }
}

#if 0
/* unused for now but delete is here for completeness   */
static dslxt_Tree * dslxt_delete(char *i, dslxt_Tree * t) {
/* Deletes i from the tree if it's there.               */
/* Return a pointer to the resulting tree.              */
    dslxt_Tree * x;
    if (t==NULL) return NULL;
    t = dslxt_splay(i,t);
    if (!strcmp(i, t->item)) {               /* found it */
	if (t->left == NULL) {
	    x = t->right;
	} else {
	    x = dslxt_splay(i, t->left);
	    x->right = t->right;
	}
	free(t);
	return x;
    }
    return t;                         /* It wasn't there */
}
#endif

/************************ splay ************************/

/*
 * functions which emit various big endian
 * data to a file
 */
static int lt_emit_u8(struct lt_trace *lt, int value)
{
unsigned char buf[1];
int nmemb;

buf[0] = value & 0xff;
nmemb=fwrite(buf, sizeof(char), 1, lt->handle);
lt->position+=nmemb;
return(nmemb);
}


static int lt_emit_u16(struct lt_trace *lt, int value)
{
unsigned char buf[2];
int nmemb;

buf[0] = (value>>8) & 0xff;
buf[1] = value & 0xff;
nmemb = fwrite(buf, sizeof(char), 2, lt->handle);
lt->position+=nmemb;
return(nmemb);
}


static int lt_emit_u24(struct lt_trace *lt, int value)
{
unsigned char buf[3];
int nmemb;

buf[0] = (value>>16) & 0xff;
buf[1] = (value>>8) & 0xff;
buf[2] = value & 0xff;
nmemb=fwrite(buf, sizeof(char), 3, lt->handle);
lt->position+=nmemb;
return(nmemb);
}


static int lt_emit_u32(struct lt_trace *lt, int value)
{
unsigned char buf[4];
int nmemb;

buf[0] = (value>>24) & 0xff;
buf[1] = (value>>16) & 0xff;
buf[2] = (value>>8) & 0xff;
buf[3] = value & 0xff;
nmemb=fwrite(buf, sizeof(char), 4, lt->handle);
lt->position+=nmemb;
return(nmemb);
}


static int lt_emit_u64(struct lt_trace *lt, int valueh, int valuel)
{
int rc;

if((rc=lt_emit_u32(lt, valueh)))
	{
	rc=lt_emit_u32(lt, valuel);
	}

return(rc);
}


static int lt_emit_double(struct lt_trace *lt, double value)
{
int nmemb;

nmemb=fwrite(&value, sizeof(char), sizeof(double)/sizeof(char), lt->handle);
lt->position+=nmemb;
return(nmemb);
}


static int lt_emit_string(struct lt_trace *lt, char *value)
{
int rc=1;
do
	{
        rc&=lt_emit_u8(lt, *value);
        } while(*(value++));
return(rc);
}


/*
 * gzfunctions which emit various big endian
 * data to a file.  (lt->position needs to be
 * fixed up on gzclose so the tables don't
 * get out of sync!)
 */
static int lt_emit_u8z(struct lt_trace *lt, int value)
{
unsigned char buf[1];
int nmemb;

buf[0] = value & 0xff;
nmemb=gzwrite(lt->zhandle, buf, 1);
lt->zpackcount++;
lt->position++;
return(nmemb);
}


static int lt_emit_u16z(struct lt_trace *lt, int value)
{
unsigned char buf[2];
int nmemb;

buf[0] = (value>>8) & 0xff;
buf[1] = value & 0xff;
nmemb = gzwrite(lt->zhandle, buf, 2);
lt->zpackcount+=2;
lt->position+=2;
return(nmemb);
}


static int lt_emit_u24z(struct lt_trace *lt, int value)
{
unsigned char buf[3];
int nmemb;

buf[0] = (value>>16) & 0xff;
buf[1] = (value>>8) & 0xff;
buf[2] = value & 0xff;
nmemb=gzwrite(lt->zhandle, buf, 3);
lt->zpackcount+=3;
lt->position+=3;
return(nmemb);
}


static int lt_emit_u32z(struct lt_trace *lt, int value)
{
unsigned char buf[4];
int nmemb;

buf[0] = (value>>24) & 0xff;
buf[1] = (value>>16) & 0xff;
buf[2] = (value>>8) & 0xff;
buf[3] = value & 0xff;
nmemb=gzwrite(lt->zhandle, buf, 4);

lt->zpackcount+=4;
lt->position+=4;
return(nmemb);
}


static int lt_emit_u64z(struct lt_trace *lt, int valueh, int valuel)
{
int rc;

if((rc=lt_emit_u32z(lt, valueh)))
	{
	rc=lt_emit_u32z(lt, valuel);
	}

return(rc);
}


static int lt_emit_doublez(struct lt_trace *lt, double value)
{
int nmemb;

nmemb=gzwrite(lt->zhandle, &value, sizeof(double)/sizeof(char));
lt->zpackcount+=(sizeof(double)/sizeof(char));
lt->position+=(sizeof(double)/sizeof(char));;
return(nmemb);
}


static int lt_emit_stringz(struct lt_trace *lt, char *value)
{
int rc=1;
do
	{
        rc&=lt_emit_u8z(lt, *value);
        } while(*(value++));
return(rc);
}

/*
 * bz2functions which emit various big endian
 * data to a file.  (lt->position needs to be
 * fixed up on BZ2_bzclose so the tables don't
 * get out of sync!)
 */
static int lt_emit_u8bz(struct lt_trace *lt, int value)
{
unsigned char buf[1];
int nmemb;

buf[0] = value & 0xff;
nmemb=BZ2_bzwrite(lt->zhandle, buf, 1);
lt->zpackcount++;
lt->position++;
return(nmemb);
}


static int lt_emit_u16bz(struct lt_trace *lt, int value)
{
unsigned char buf[2];
int nmemb;

buf[0] = (value>>8) & 0xff;
buf[1] = value & 0xff;
nmemb = BZ2_bzwrite(lt->zhandle, buf, 2);
lt->zpackcount+=2;
lt->position+=2;
return(nmemb);
}


static int lt_emit_u24bz(struct lt_trace *lt, int value)
{
unsigned char buf[3];
int nmemb;

buf[0] = (value>>16) & 0xff;
buf[1] = (value>>8) & 0xff;
buf[2] = value & 0xff;
nmemb=BZ2_bzwrite(lt->zhandle, buf, 3);
lt->zpackcount+=3;
lt->position+=3;
return(nmemb);
}


static int lt_emit_u32bz(struct lt_trace *lt, int value)
{
unsigned char buf[4];
int nmemb;

buf[0] = (value>>24) & 0xff;
buf[1] = (value>>16) & 0xff;
buf[2] = (value>>8) & 0xff;
buf[3] = value & 0xff;
nmemb=BZ2_bzwrite(lt->zhandle, buf, 4);

lt->zpackcount+=4;
lt->position+=4;
return(nmemb);
}


static int lt_emit_u64bz(struct lt_trace *lt, int valueh, int valuel)
{
int rc;

if((rc=lt_emit_u32bz(lt, valueh)))
	{
	rc=lt_emit_u32bz(lt, valuel);
	}

return(rc);
}


static int lt_emit_doublebz(struct lt_trace *lt, double value)
{
int nmemb;

nmemb=BZ2_bzwrite(lt->zhandle, &value, sizeof(double)/sizeof(char));
lt->zpackcount+=(sizeof(double)/sizeof(char));
lt->position+=(sizeof(double)/sizeof(char));;
return(nmemb);
}


static int lt_emit_stringbz(struct lt_trace *lt, char *value)
{
int rc=1;
do
	{
        rc&=lt_emit_u8bz(lt, *value);
        } while(*(value++));
return(rc);
}


/*
 * switch between compression modes above
 */
static void lt_set_zmode(struct lt_trace *lt, int mode)
{
switch(mode)
	{
	case LT_ZMODE_NONE:
	lt->lt_emit_u8 = lt_emit_u8;
	lt->lt_emit_u16 = lt_emit_u16;
	lt->lt_emit_u24 = lt_emit_u24;
	lt->lt_emit_u32 = lt_emit_u32;
	lt->lt_emit_u64 = lt_emit_u64;
	lt->lt_emit_double = lt_emit_double;
	lt->lt_emit_string = lt_emit_string;
	break;

	case LT_ZMODE_GZIP:
	lt->lt_emit_u8 = lt_emit_u8z;
	lt->lt_emit_u16 = lt_emit_u16z;
	lt->lt_emit_u24 = lt_emit_u24z;
	lt->lt_emit_u32 = lt_emit_u32z;
	lt->lt_emit_u64 = lt_emit_u64z;
	lt->lt_emit_double = lt_emit_doublez;
	lt->lt_emit_string = lt_emit_stringz;
	break;

	case LT_ZMODE_BZIP2:
	lt->lt_emit_u8 = lt_emit_u8bz;
	lt->lt_emit_u16 = lt_emit_u16bz;
	lt->lt_emit_u24 = lt_emit_u24bz;
	lt->lt_emit_u32 = lt_emit_u32bz;
	lt->lt_emit_u64 = lt_emit_u64bz;
	lt->lt_emit_double = lt_emit_doublebz;
	lt->lt_emit_string = lt_emit_stringbz;
	break;
	}
}


/*
 * hash/symtable manipulation
 */
static int lt_hash(const char *s)
{
const char *p;
char ch;
unsigned int h=0, h2=0, pos=0, g;
for(p=s;*p;p++)
        {
	ch=*p;
	h2<<=3;
	h2-=((unsigned int)ch+(pos++));		/* this handles stranded vectors quite well.. */

        h=(h<<4)+ch;
        if((g=h&0xf0000000))
                {
                h=h^(g>>24);
                h=h^g;
                }
        }

h^=h2;						/* combine the two hashes */
return(h%LT_SYMPRIME);
}


static struct lt_symbol *lt_symadd(struct lt_trace *lt, const char *name, int hv)
{
struct lt_symbol *s;

s=(struct lt_symbol *)calloc(1,sizeof(struct lt_symbol));
strcpy(s->name=(char *)malloc((s->namlen=strlen(name))+1),name);
s->next=lt->sym[hv];
lt->sym[hv]=s;
return(s);
}


static struct lt_symbol *lt_symfind(struct lt_trace *lt, const char *s)
{
int hv;
struct lt_symbol *temp;

hv=lt_hash(s);
if(!(temp=lt->sym[hv])) return(NULL); /* no hash entry, add here wanted to add */

while(temp)
        {
        if(!strcmp(temp->name,s))
                {
                return(temp); /* in table already */
                }
        if(!temp->next) break;
        temp=temp->next;
        }

return(NULL); /* not found, add here if you want to add*/
}


/*
 * compress facs to a prefix count + string + 0x00
 */
static void lt_compress_fac(struct lt_trace *lt, char *str)
{
int i;
int len = strlen(str);
int minlen = (len<lt->compress_fac_len) ? len : lt->compress_fac_len;

if(minlen>65535) minlen=65535;    /* keep in printable range--most hierarchies won't be this big anyway */

if(lt->compress_fac_str)
        {
        for(i=0;i<minlen;i++)
                {
                if(lt->compress_fac_str[i]!=str[i]) break;
                }
	lt_emit_u16z(lt, i);
	lt_emit_stringz(lt, str+i);
        free(lt->compress_fac_str);
        }
        else
        {
	lt_emit_u16z(lt, 0);
	lt_emit_stringz(lt, str);
        }

lt->compress_fac_str = (char *) malloc((lt->compress_fac_len=len)+1);
strcpy(lt->compress_fac_str, str);
}


static void strip_brack(struct lt_symbol *s)
{
char *lastch = s->name+s->namlen - 1;
if(*lastch!=']') return;
if(s->namlen<3) return;
lastch--;
while(lastch!=s->name)
	{
	if(*lastch=='.')
		{
		return;	/* MTI SV [0.3] notation for implicit vars */
		}

	if(*lastch=='[')
		{
		*lastch=0x00;
		return;
		}
	lastch--;
	}
return;
}


static void lt_emitfacs(struct lt_trace *lt)
{
int i;

if((lt)&&(lt->numfacs))
	{
	struct lt_symbol *s = lt->symchain;
	char is_interlaced_trace = (lt->sorted_facs==NULL);

	if(!lt->sorted_facs)
		{
		if((lt->sorted_facs = (struct lt_symbol **)calloc(lt->numfacs, sizeof(struct lt_symbol *))))
			{
			if(lt->do_strip_brackets)
			for(i=0;i<lt->numfacs;i++)
				{
				lt->sorted_facs[lt->numfacs - i - 1] = s;	/* facs were chained backwards so reverse to restore bitslicing */
				strip_brack(s);
				s=s->symchain;
				}
			else
			for(i=0;i<lt->numfacs;i++)
				{
				lt->sorted_facs[lt->numfacs - i - 1] = s;	/* facs were chained backwards so reverse to restore bitslicing*/
				s=s->symchain;
				}
			wave_msort(lt->sorted_facs, lt->numfacs);

			for(i=0;i<lt->numfacs;i++)
				{
				lt->sorted_facs[i]->facnum = i;
				}
			}
		}

	if(lt->sorted_facs)
		{
		lt->facname_offset=lt->position;

		lt_emit_u32(lt, lt->numfacs);		/* uncompressed */
		lt_emit_u32(lt, lt->numfacbytes);	/* uncompressed */
		fflush(lt->handle);
		lt->zfacname_size = lt->position;
		lt->zhandle = gzdopen(dup(fileno(lt->handle)), "wb9");

		lt->zpackcount = 0;
		for(i=0;i<lt->numfacs;i++)
			{
		 	lt_compress_fac(lt, lt->sorted_facs[i]->name);
			}
		free(lt->compress_fac_str); lt->compress_fac_str=NULL;
		lt->compress_fac_len=0;
		lt->zfacname_predec_size = lt->zpackcount;

		gzclose(lt->zhandle);
		fseeko(lt->handle, 0L, SEEK_END);
		lt->position=ftello(lt->handle);
		lt->zfacname_size = lt->position - lt->zfacname_size;

		lt->zhandle = gzdopen(dup(fileno(lt->handle)), "wb9");

		lt->facgeometry_offset = lt->position;
		for(i=0;i<lt->numfacs;i++)
			{
			if((lt->sorted_facs[i]->flags&LT_SYM_F_ALIAS)==0)
				{
				lt_emit_u32z(lt, lt->sorted_facs[i]->rows);
				lt_emit_u32z(lt, lt->sorted_facs[i]->msb);
				lt_emit_u32z(lt, lt->sorted_facs[i]->lsb);
				lt_emit_u32z(lt, lt->sorted_facs[i]->flags);
				}
				else
				{
				lt_emit_u32z(lt, lt->sorted_facs[i]->aliased_to->facnum);
				lt_emit_u32z(lt, lt->sorted_facs[i]->msb);
				lt_emit_u32z(lt, lt->sorted_facs[i]->lsb);
				lt_emit_u32z(lt, LT_SYM_F_ALIAS);
				}
			}

		gzclose(lt->zhandle);
		fseeko(lt->handle, 0L, SEEK_END);
		lt->position=ftello(lt->handle);
		lt->zfacgeometry_size = lt->position - lt->facgeometry_offset;

		if(is_interlaced_trace)
			{
			lt->zhandle = gzdopen(dup(fileno(lt->handle)), "wb9");

			lt->sync_table_offset = lt->position;
			for(i=0;i<lt->numfacs;i++)
				{
				lt_emit_u32z(lt, lt->sorted_facs[i]->last_change);
				}

			gzclose(lt->zhandle); lt->zhandle = NULL;
			fseeko(lt->handle, 0L, SEEK_END);
			lt->position=ftello(lt->handle);
			lt->zsync_table_size = lt->position - lt->sync_table_offset;
			}
		}
	}
}


/*
 * initialize the trace and get back an lt context
 */
struct lt_trace *lt_init(const char *name)
{
struct lt_trace *lt=(struct lt_trace *)calloc(1, sizeof(struct lt_trace));

if(!(lt->handle=fopen(name, "wb")))
	{
	free(lt);
	lt=NULL;
	}
	else
	{
	lt_emit_u16(lt, LT_HDRID);
	lt_emit_u16(lt, LT_VERSION);
	lt->change_field_offset = lt->position;
	lt->initial_value = -1;				/* if a user sets this it will have a different POSITIVE val */
	lt->timescale = -256;				/* will be in range of -128<=x<=127 if set */

	lt_set_zmode(lt, LT_ZMODE_NONE);

	lt->mintime=ULLDescriptor(1);
	lt->maxtime=ULLDescriptor(0);
	}

return(lt);
}

/*
 * clock flushing..
 */
static void lt_flushclock(struct lt_trace *lt, struct lt_symbol *s)
{
unsigned int last_change_delta = lt->position - s->last_change - 2;
unsigned int start_position = lt->position;
int tag;
int numbytes, numbytes_trans;
int numtrans = s->clk_numtrans - LT_CLKPACK - 1;

if(numtrans<0)
	{
	/* it never got around to caching */
	fprintf(stderr, "Possible Problem with %s with %d?\n", s->name, s->clk_numtrans);
	return;
	}

if(numtrans >= 256*65536)
	{
	numbytes_trans = 3;
	}
else
if(numtrans >= 65536)
	{
	numbytes_trans = 2;
	}
else
if(numtrans >= 256)
	{
	numbytes_trans = 1;
	}
else
	{
	numbytes_trans = 0;
	}

if(!lt->numfacs_bytes)
	{
	if(last_change_delta >= 256*65536)
		{
		numbytes = 3;
		}
	else
	if(last_change_delta >= 65536)
		{
		numbytes = 2;
		}
	else
	if(last_change_delta >= 256)
		{
		numbytes = 1;
		}
	else
		{
		numbytes = 0;
		}

	tag = (numbytes<<4) + 0xC + numbytes_trans;	/* yields xC..xF */

	lt->lt_emit_u8(lt, tag);
	switch(numbytes&3)
		{
		case 0: lt->lt_emit_u8(lt, last_change_delta); break;
		case 1: lt->lt_emit_u16(lt, last_change_delta); break;
		case 2: lt->lt_emit_u24(lt, last_change_delta); break;
		case 3: lt->lt_emit_u32(lt, last_change_delta); break;
		}
	}
	else
	{
	tag = 0xC + numbytes_trans;	/* yields C..F */

	switch(lt->numfacs_bytes)
		{
		case 1: lt->lt_emit_u8(lt, s->facnum); break;
		case 2: lt->lt_emit_u16(lt, s->facnum); break;
		case 3: lt->lt_emit_u24(lt, s->facnum); break;
		case 4: lt->lt_emit_u32(lt, s->facnum); break;
		}
	lt->lt_emit_u8(lt, tag);
	}

s->last_change = start_position;

/* s->clk_prevval		CAN BE INFERRED! */
/* s->clk_prevtrans		CAN BE INFERRED! */
/* s->clk_delta 		CAN BE INFERRED! */

switch(numbytes_trans&3)
	{
	case 0: lt->lt_emit_u8(lt, numtrans); break;
	case 1: lt->lt_emit_u16(lt, numtrans); break;
	case 2: lt->lt_emit_u24(lt, numtrans); break;
	case 3: lt->lt_emit_u32(lt, numtrans); break;
	}

/* printf("Clock finish for '%s' at %lld ending with '%c' for %d repeats over a switch delta of %d\n",
	s->name, lt->timeval, s->clk_prevval, s->clk_numtrans - LT_CLKPACK, s->clk_delta); */
s->clk_prevtrans = ULLDescriptor(~0);
s->clk_numtrans = 0;
}

static void lt_flushclock_m(struct lt_trace *lt, struct lt_symbol *s)
{
unsigned int last_change_delta = lt->position - s->last_change - 2;
unsigned int start_position = lt->position;
int tag;
int numbytes, numbytes_trans;
int numtrans = s->clk_numtrans - LT_CLKPACK_M - 1;

if(numtrans<0)
	{
	/* it never got around to caching */
	fprintf(stderr, "Possible Problem with %s with %d?\n", s->name, s->clk_numtrans);
	return;
	}

if(numtrans >= 256*65536)
	{
	numbytes_trans = 3;
	}
else
if(numtrans >= 65536)
	{
	numbytes_trans = 2;
	}
else
if(numtrans >= 256)
	{
	numbytes_trans = 1;
	}
else
	{
	numbytes_trans = 0;
	}

if(!lt->numfacs_bytes)
	{
	if(last_change_delta >= 256*65536)
		{
		numbytes = 3;
		}
	else
	if(last_change_delta >= 65536)
		{
		numbytes = 2;
		}
	else
	if(last_change_delta >= 256)
		{
		numbytes = 1;
		}
	else
	{
	numbytes = 0;
	}

	tag = (numbytes<<4) + 0xC + numbytes_trans;	/* yields xC..xF */

	lt->lt_emit_u8(lt, tag);
	switch(numbytes&3)
		{
		case 0: lt->lt_emit_u8(lt, last_change_delta); break;
		case 1: lt->lt_emit_u16(lt, last_change_delta); break;
		case 2: lt->lt_emit_u24(lt, last_change_delta); break;
		case 3: lt->lt_emit_u32(lt, last_change_delta); break;
		}
	}
	else
	{
	tag = 0xC + numbytes_trans;	/* yields C..F */

	switch(lt->numfacs_bytes)
		{
		case 1: lt->lt_emit_u8(lt, s->facnum); break;
		case 2: lt->lt_emit_u16(lt, s->facnum); break;
		case 3: lt->lt_emit_u24(lt, s->facnum); break;
		case 4: lt->lt_emit_u32(lt, s->facnum); break;
		}
	lt->lt_emit_u8(lt, tag);
	}


s->last_change = start_position;

/* s->clk_prevval		CAN BE INFERRED! */
/* s->clk_prevtrans		CAN BE INFERRED! */
/* s->clk_delta 		CAN BE INFERRED! */

switch(numbytes_trans&3)
	{
	case 0: lt->lt_emit_u8(lt, numtrans); break;
	case 1: lt->lt_emit_u16(lt, numtrans); break;
	case 2: lt->lt_emit_u24(lt, numtrans); break;
	case 3: lt->lt_emit_u32(lt, numtrans); break;
	}

/* printf("Clock finish for '%s' at %lld ending with '%08x' for %d repeats over a switch delta of %lld\n",
	s->name, lt->timeval, s->clk_prevval, s->clk_numtrans - LT_CLKPACK_M, s->clk_delta); */
s->clk_prevtrans = ULLDescriptor(~0);
s->clk_numtrans = 0;
}


/*
 * recurse through dictionary
 */
static void lt_recurse_dictionary(struct lt_trace *lt, dslxt_Tree *ds)
{
if(ds->left) lt_recurse_dictionary(lt, ds->left);
lt->sorted_dict[ds->val] = ds;
if(ds->right) lt_recurse_dictionary(lt, ds->right);
}

static void lt_recurse_dictionary_free(struct lt_trace *lt, dslxt_Tree *ds)
{
dslxt_Tree *lft = ds->left;
dslxt_Tree *rgh = ds->right;

if(lft) lt_recurse_dictionary_free(lt, lft);
free(ds->item); free(ds);
if(rgh) lt_recurse_dictionary_free(lt, rgh);
}

static int lt_dictval_compare(const void *v1, const void *v2)
{
const dslxt_Tree *s1 = *(const dslxt_Tree * const *)v1;
const dslxt_Tree *s2 = *(const dslxt_Tree * const *)v2;

if(s1->val > s2->val) return(1); else return(-1);	/* they're *never* equal */
}

static void lt_finalize_dictionary(struct lt_trace *lt)
{
unsigned int i;

lt->sorted_dict = calloc(lt->num_dict_entries, sizeof(dslxt_Tree *));

lt->dictionary_offset=lt->position;

lt_emit_u32(lt, lt->num_dict_entries);		/* uncompressed */
lt_emit_u32(lt, lt->dict_string_mem_required - lt->num_dict_entries);	/* uncompressed : minus because leading '1' is implied so its stripped */
lt_emit_u32(lt, lt->dict16_offset);		/* uncompressed */
lt_emit_u32(lt, lt->dict24_offset);		/* uncompressed */
lt_emit_u32(lt, lt->dict32_offset);		/* uncompressed */
lt_emit_u32(lt, lt->mindictwidth);		/* uncompressed */
fflush(lt->handle);

#if 0
fprintf(stderr, "*** dictionary_offset = %08x\n", lt->dictionary_offset);
fprintf(stderr, "*** num_dict_entries = %d\n", lt->num_dict_entries);
#endif

lt->zdictionary_size = lt->position;
lt->zhandle = gzdopen(dup(fileno(lt->handle)), "wb9");

lt_recurse_dictionary(lt, lt->dict);
qsort((void *)lt->sorted_dict, lt->num_dict_entries, sizeof(struct dsTree **), lt_dictval_compare);

for(i=0;i<lt->num_dict_entries;i++)
	{
	dslxt_Tree *ds = lt->sorted_dict[i];
	/* fprintf(stderr, "%8d) '%s'\n", ds->val, ds->item); */
	lt_emit_stringz(lt, ds->item+1);
	}

gzclose(lt->zhandle);
fseeko(lt->handle, 0L, SEEK_END);
lt->position=ftello(lt->handle);
lt->zdictionary_size = lt->position - lt->zdictionary_size;

free(lt->sorted_dict); lt->sorted_dict = NULL;

lt_recurse_dictionary_free(lt, lt->dict);
lt->dict = NULL;
}


/*
 * close out the trace and fixate it
 */
void lt_close(struct lt_trace *lt)
{
lxttime_t lasttime=ULLDescriptor(0);
int lastposition=0;
char is64=0;

if(lt)
	{
	struct lt_symbol *s = lt->symchain;

	if(lt->clock_compress)
	while(s)
		{
               if(s->clk_prevtrans!=ULLDescriptor(~0))
                        {
                        int len = ((s->flags)&LT_SYM_F_INTEGER) ? 32 : s->len;
                        if(len>1)
                                {
                                if(s->clk_numtrans > LT_CLKPACK_M) lt_flushclock_m(lt, s);
                                }
                                else
                                {
                                if(s->clk_numtrans > LT_CLKPACK) lt_flushclock(lt, s);
                                }
                        }

                s=s->symchain;
		}

	lt_set_dumpon(lt);	/* in case it was turned off */

	if(lt->zmode!=LT_ZMODE_NONE)
		{
		lt->chg_table_size = lt->position - lt->change_field_offset;

		switch(lt->zmode)
			{
			case LT_ZMODE_GZIP: 	gzclose(lt->zhandle); break;
			case LT_ZMODE_BZIP2:	BZ2_bzclose(lt->zhandle); break;
			}
		lt->zhandle = NULL;
		fseeko(lt->handle, 0L, SEEK_END);
		lt->position=ftello(lt->handle);

		lt_set_zmode(lt, LT_ZMODE_NONE);
		lt->zchg_table_size = lt->position - lt->change_field_offset;
		}

	lt_emitfacs(lt);
	if(lt->dict) lt_finalize_dictionary(lt);

	free(lt->timebuff);
	lt->timebuff=NULL;

	if(lt->timehead)
		{
		struct lt_timetrail *t=lt->timehead;
		struct lt_timetrail *t2;

		lt->time_table_offset = lt->position;

		lt_emit_u32(lt, lt->timechangecount);	/* this is uncompressed! */

		fflush(lt->handle);
		lt->zhandle = gzdopen(dup(fileno(lt->handle)), "wb9");
		lt->ztime_table_size = lt->position;

		is64=(lt->maxtime > ULLDescriptor(0xFFFFFFFF));

		if(is64)
			{
			lt_emit_u64z(lt, (int)((lt->mintime)>>32), (int)lt->mintime);
			lt_emit_u64z(lt, (int)((lt->maxtime)>>32), (int)lt->maxtime);
			}
			else
			{
			lt_emit_u32z(lt, (int)lt->mintime);
			lt_emit_u32z(lt, (int)lt->maxtime);
			}

		while(t)
			{
			lt_emit_u32z(lt, t->position - lastposition); lastposition = t->position;
			t=t->next;
			}

		t=lt->timehead;
		if(is64)
			{
			while(t)
				{
				lxttime_t delta = t->timeval - lasttime;
				lt_emit_u64z(lt, (int)(delta>>32), (int)delta); lasttime = t->timeval;

				t2=t->next;
				free(t);
				t=t2;
				}
			}
		else
			{
			while(t)
				{
				lt_emit_u32z(lt, (int)(t->timeval - lasttime)); lasttime = t->timeval;

				t2=t->next;
				free(t);
				t=t2;
				}

			lt->timehead = lt->timecurr = NULL;
			}

		gzclose(lt->zhandle); lt->zhandle = NULL;
		fseeko(lt->handle, 0L, SEEK_END);
		lt->position=ftello(lt->handle);
		lt->ztime_table_size = lt->position - lt->ztime_table_size;
		}

	if(lt->initial_value>=0)
		{
		lt->initial_value_offset = lt->position;
		lt_emit_u8(lt, lt->initial_value);
		}

	if((lt->timescale>-129)&&(lt->timescale<128))
		{
		lt->timescale_offset = lt->position;
		lt_emit_u8(lt, lt->timescale);
		}

	if(lt->double_used)
		{
		lt->double_test_offset = lt->position;
		lt_emit_double(lt, 3.14159);
		}

	if(lt->dumpoffcount)
		{
		struct lt_timetrail *ltt = lt->dumpoffhead;
		struct lt_timetrail *ltt2;

		lt->exclude_offset = lt->position;
		lt_emit_u32(lt, lt->dumpoffcount);

		while(ltt)
			{
			lt_emit_u64(lt, (int)((ltt->timeval)>>32), (int)ltt->timeval);
			ltt2 = ltt;
			ltt=ltt->next;
			free(ltt2);
			}

		lt->dumpoffhead = lt->dumpoffcurr = NULL;
		lt->dumpoffcount = 0;
		}

	if(lt->timezero)
		{
		lt->timezero_offset = lt->position;
		lt_emit_u64(lt, (int)((lt->timezero)>>32), (int)lt->timezero);
		}

	/* prefix */
	lt_emit_u8(lt, LT_SECTION_END);

	/* Version 1 */
	if(lt->change_field_offset) { lt_emit_u32(lt, lt->change_field_offset); lt_emit_u8(lt, LT_SECTION_CHG); lt->change_field_offset = 0; }
	if(lt->sync_table_offset) { lt_emit_u32(lt, lt->sync_table_offset); lt_emit_u8(lt, LT_SECTION_SYNC_TABLE); lt->sync_table_offset = 0; }
	if(lt->facname_offset) { lt_emit_u32(lt, lt->facname_offset); lt_emit_u8(lt, LT_SECTION_FACNAME); lt->facname_offset = 0; }
	if(lt->facgeometry_offset) { lt_emit_u32(lt, lt->facgeometry_offset); lt_emit_u8(lt, LT_SECTION_FACNAME_GEOMETRY); lt->facgeometry_offset = 0; }
	if(lt->timescale_offset) { lt_emit_u32(lt, lt->timescale_offset); lt_emit_u8(lt, LT_SECTION_TIMESCALE); lt->timescale_offset = 0; }
	if(lt->time_table_offset) { lt_emit_u32(lt, lt->time_table_offset); lt_emit_u8(lt, is64 ? LT_SECTION_TIME_TABLE64 : LT_SECTION_TIME_TABLE); lt->time_table_offset = 0; }
	if(lt->initial_value_offset) { lt_emit_u32(lt, lt->initial_value_offset); lt_emit_u8(lt, LT_SECTION_INITIAL_VALUE); lt->initial_value_offset = 0; }
	if(lt->double_test_offset) { lt_emit_u32(lt, lt->double_test_offset); lt_emit_u8(lt, LT_SECTION_DOUBLE_TEST); lt->double_test_offset = 0; }

	/* Version 2 adds */
	if(lt->zfacname_predec_size) { lt_emit_u32(lt, lt->zfacname_predec_size); lt_emit_u8(lt, LT_SECTION_ZFACNAME_PREDEC_SIZE); lt->zfacname_predec_size = 0; }
	if(lt->zfacname_size) { lt_emit_u32(lt, lt->zfacname_size); lt_emit_u8(lt, LT_SECTION_ZFACNAME_SIZE); lt->zfacname_size = 0; }
	if(lt->zfacgeometry_size) { lt_emit_u32(lt, lt->zfacgeometry_size); lt_emit_u8(lt, LT_SECTION_ZFACNAME_GEOMETRY_SIZE); lt->zfacgeometry_size = 0; }
	if(lt->zsync_table_size) { lt_emit_u32(lt, lt->zsync_table_size); lt_emit_u8(lt, LT_SECTION_ZSYNC_SIZE); lt->zsync_table_size = 0; }
	if(lt->ztime_table_size) { lt_emit_u32(lt, lt->ztime_table_size); lt_emit_u8(lt, LT_SECTION_ZTIME_TABLE_SIZE); lt->ztime_table_size = 0; }
	if(lt->chg_table_size) { lt_emit_u32(lt, lt->chg_table_size); lt_emit_u8(lt, LT_SECTION_ZCHG_PREDEC_SIZE); lt->chg_table_size = 0; }
	if(lt->zchg_table_size) { lt_emit_u32(lt, lt->zchg_table_size); lt_emit_u8(lt, LT_SECTION_ZCHG_SIZE); lt->zchg_table_size = 0; }

	/* Version 4 adds */
	if(lt->dictionary_offset) { lt_emit_u32(lt, lt->dictionary_offset); lt_emit_u8(lt, LT_SECTION_ZDICTIONARY); lt->dictionary_offset = 0; }
	if(lt->zdictionary_size) { lt_emit_u32(lt, lt->zdictionary_size); lt_emit_u8(lt, LT_SECTION_ZDICTIONARY_SIZE); lt->zdictionary_size = 0; }

	/* Version 5 adds */
	if(lt->exclude_offset) { lt_emit_u32(lt, lt->exclude_offset); lt_emit_u8(lt, LT_SECTION_EXCLUDE_TABLE); lt->exclude_offset = 0; }

	/* Version 6 adds */
	if(lt->timezero_offset) { lt_emit_u32(lt, lt->timezero_offset); lt_emit_u8(lt, LT_SECTION_TIMEZERO); lt->timezero_offset = 0; }

	/* suffix */
	lt_emit_u8(lt, LT_TRLID);

	if(lt->symchain)
		{
		struct lt_symbol *sc = lt->symchain;
		struct lt_symbol *s2;

		while(sc)
			{
			free(sc->name);
			s2=sc->symchain;
			free(sc);
			sc=s2;
			}
		}

	free(lt->sorted_facs);
	fclose(lt->handle);
	free(lt);
	}

}


/*
 * maint function for finding a symbol if it exists
 */
struct lt_symbol *lt_symbol_find(struct lt_trace *lt, const char *name)
{
struct lt_symbol *s=NULL;

if((lt)&&(name)) s=lt_symfind(lt, name);
return(s);
}


/*
 * add a trace (if it doesn't exist already)
 */
struct lt_symbol *lt_symbol_add(struct lt_trace *lt, const char *name, unsigned int rows, int msb, int lsb, int flags)
{
struct lt_symbol *s;
int len;
int flagcnt;

if((!lt)||(lt->sorted_facs)) return(NULL);

flagcnt = ((flags&LT_SYM_F_INTEGER)!=0) + ((flags&LT_SYM_F_DOUBLE)!=0) + ((flags&LT_SYM_F_STRING)!=0);

if((flagcnt>1)||(!lt)||(!name)||(lt_symfind(lt, name))) return (NULL);

if(flags&LT_SYM_F_DOUBLE) lt->double_used = 1;

s=lt_symadd(lt, name, lt_hash(name));
s->rows = rows;
s->flags = flags&(~LT_SYM_F_ALIAS);	/* aliasing makes no sense here.. */

if(!flagcnt)
	{
	s->msb = msb;
	s->lsb = lsb;
	s->len = (msb<lsb) ? (lsb-msb+1) : (msb-lsb+1);

	if((s->len==1)&&(s->rows==0)) s->clk_prevtrans = ULLDescriptor(~0);
	}

s->symchain = lt->symchain;
lt->symchain = s;

lt->numfacs++;

if((len=strlen(name)) > lt->longestname) lt->longestname = len;
lt->numfacbytes += (len+1);

return(s);
}

/*
 * add an alias trace (if it doesn't exist already and orig is found)
 */
struct lt_symbol *lt_symbol_alias(struct lt_trace *lt, const char *existing_name, const char *alias, int msb, int lsb)
{
struct lt_symbol *s, *sa;
int len;
int bitlen;
int flagcnt;

if((!lt)||(!existing_name)||(!alias)||(!(s=lt_symfind(lt, existing_name)))||(lt_symfind(lt, alias))) return (NULL);

if(lt->sorted_facs) return(NULL);

while(s->aliased_to)	/* find root alias */
	{
	s=s->aliased_to;
	}

flagcnt = ((s->flags&LT_SYM_F_INTEGER)!=0) + ((s->flags&LT_SYM_F_DOUBLE)!=0) + ((s->flags&LT_SYM_F_STRING)!=0);
bitlen = (msb<lsb) ? (lsb-msb+1) : (msb-lsb+1);
if((!flagcnt)&&(bitlen!=s->len)) return(NULL);

sa=lt_symadd(lt, alias, lt_hash(alias));
sa->flags = LT_SYM_F_ALIAS;	/* only point this can get set */
sa->aliased_to = s;

if(!flagcnt)
	{
	sa->msb = msb;
	sa->lsb = lsb;
	sa->len = bitlen;
	}

sa->symchain = lt->symchain;
lt->symchain = sa;
lt->numfacs++;
if((len=strlen(alias)) > lt->longestname) lt->longestname = len;
lt->numfacbytes += (len+1);

return(sa);
}


/*
 * set current time
 */
int lt_inc_time_by_delta(struct lt_trace *lt, unsigned int timeval)
{
return(lt_set_time64(lt, lt->maxtime + (lxttime_t)timeval));
}

int lt_set_time(struct lt_trace *lt, unsigned int timeval)
{
return(lt_set_time64(lt, (lxttime_t)timeval));
}

int lt_inc_time_by_delta64(struct lt_trace *lt, lxttime_t timeval)
{
return(lt_set_time64(lt, lt->maxtime + timeval));
}

int lt_set_time64(struct lt_trace *lt, lxttime_t timeval)
{
int rc=0;

if(lt)
	{
	struct lt_timetrail *trl=(struct lt_timetrail *)calloc(1, sizeof(struct lt_timetrail));
	if(trl)
		{
		trl->timeval = timeval;
		trl->position = lt->position;

		if((lt->timecurr)||(lt->timebuff))
			{
			if(((timeval>lt->mintime)&&(timeval>lt->maxtime))||((lt->mintime==ULLDescriptor(1))&&(lt->maxtime==ULLDescriptor(0))))
				{
				lt->maxtime = timeval;
				}
				else
				{
				free(trl);
				goto bail;
				}
			}
			else
			{
			lt->mintime = lt->maxtime = timeval;
			}

		free(lt->timebuff);
		lt->timebuff = trl;
		lt->timeval = timeval;
		rc=1;
		}
	}

bail:
return(rc);
}


/*
 * sets trace timescale as 10**x seconds
 */
void lt_set_timescale(struct lt_trace *lt, int timescale)
{
if(lt)
	{
	lt->timescale = timescale;
	}
}


/*
 * sets clock compression heuristic
 */
void lt_set_clock_compress(struct lt_trace *lt)
{
if(lt)
	{
	lt->clock_compress = 1;
	}
}


/*
 * sets change dump compression
 */
void lt_set_chg_compress(struct lt_trace *lt)
{
if(lt)
	{
	if((lt->zmode==LT_ZMODE_NONE)&&(!lt->emitted))
		{
		lt_set_zmode(lt, lt->zmode = LT_ZMODE_GZIP);
		fflush(lt->handle);
		lt->zhandle = gzdopen(dup(fileno(lt->handle)), "wb9");
		}
	}
}


/*
 * sets change dictionary compression
 */
void lt_set_dict_compress(struct lt_trace *lt, unsigned int minwidth)
{
if((lt)&&(!lt->emitted))
	{
	lt->dictmode = 1;

	if(minwidth>1)
		{
		lt->mindictwidth = minwidth;
		}
	}
}

/*
 * sets change interlace
 */
void lt_set_no_interlace(struct lt_trace *lt)
{
if((lt)&&(!lt->emitted)&&(!lt->sorted_facs))
	{
	if(lt->zmode==LT_ZMODE_NONE)		/* this mode implies BZIP2 compression! */
		{
		lt_set_zmode(lt, lt->zmode = LT_ZMODE_BZIP2);
		fflush(lt->handle);
		lt->zhandle = BZ2_bzdopen(dup(fileno(lt->handle)), "wb9");
		}

	if((lt->sorted_facs = (struct lt_symbol **)calloc(lt->numfacs, sizeof(struct lt_symbol *))))
		{
		struct lt_symbol *s = lt->symchain;
		int i;

		if(lt->do_strip_brackets)
		for(i=0;i<lt->numfacs;i++)
			{
			lt->sorted_facs[lt->numfacs - i - 1] = s;	/* facs were chained backwards so reverse to restore bitslicing */
			strip_brack(s);
			s=s->symchain;
			}
		else
		for(i=0;i<lt->numfacs;i++)
			{
			lt->sorted_facs[lt->numfacs - i - 1] = s;	/* facs were chained backwards so reverse to restore bitslicing */
			s=s->symchain;
			}
		wave_msort(lt->sorted_facs, lt->numfacs);

		for(i=0;i<lt->numfacs;i++)
			{
			lt->sorted_facs[i]->facnum = i;
			}

		if(lt->numfacs >= 256*65536)
			{
			lt->numfacs_bytes = 4;
			}
		else
		if(lt->numfacs >= 65536)
			{
			lt->numfacs_bytes = 3;
			}
		else
		if(lt->numfacs >= 256)
			{
			lt->numfacs_bytes = 2;
			}
		else
			{
			lt->numfacs_bytes = 1;
			}
		}
	}
}


/*
 * sets trace initial value
 */
void lt_set_initial_value(struct lt_trace *lt, char value)
{
if(lt)
	{
	int tag;
	switch(value)
		{
		case '0':	tag = 0; break;
		case '1':	tag = 1; break;
		case 'Z':
		case 'z':	tag = 2; break;
		case 'X':
		case 'x':	tag = 3; break;
		case 'H':
		case 'h':	tag = 4; break;
		case 'U':
		case 'u':	tag = 5; break;
		case 'W':
		case 'w':	tag = 6; break;
		case 'L':
		case 'l':	tag = 0x7; break;
		case '-':	tag = 0x8; break;
		default:	tag = -1;  break;
		}
	lt->initial_value = tag;
	}
}


/*
 * Sets bracket stripping (useful for VCD conversions of
 * bitblasted nets)
 */
void lt_symbol_bracket_stripping(struct lt_trace *lt, int doit)
{
if(lt)
	{
	lt->do_strip_brackets = (doit!=0);
	}
}


/*
 * emission for trace values..
 */
static int lt_optimask[]=
{
0x00000000,

0x00000001,
0x00000003,
0x00000007,
0x0000000f,

0x0000001f,
0x0000003f,
0x0000007f,
0x000000ff,

0x000001ff,
0x000003ff,
0x000007ff,
0x00000fff,

0x00001fff,
0x00003fff,
0x00007fff,
0x0000ffff,

0x0001ffff,
0x0003ffff,
0x0007ffff,
0x000fffff,

0x001fffff,
0x003fffff,
0x007fffff,
0x00ffffff,

0x01ffffff,
0x03ffffff,
0x07ffffff,
0x0fffffff,

0x1fffffff,
0x3fffffff,
0x7fffffff,
0xffffffff
};


static char *lt_expand_integer_to_bits(int len, int value)
{
static char s[33];
char *p = s;
int i;

len--;

for(i=0;i<=len;i++)
	{
	*(p++) = '0' | ((value & (1<<(len-i)))!=0);
	}
*p = 0;

return(s);
}


int lt_emit_value_int(struct lt_trace *lt, struct lt_symbol *s, unsigned int row, int value)
{
int rc=0;

if((!lt)||(!s)) return(rc);

if(!lt->emitted) lt->emitted = 1;

while(s->aliased_to)	/* find root alias if exists */
	{
	s=s->aliased_to;
	}

if(!(s->flags&(LT_SYM_F_DOUBLE|LT_SYM_F_STRING)))
	{
	int numbytes;				/* number of bytes to store value minus one */
	unsigned int len = ((s->flags)&LT_SYM_F_INTEGER) ? 32 : s->len;
	unsigned int last_change_delta;

	if((lt->clock_compress)&&(s->rows==0))
	{
	if((len>1)&&(len<=32))
		{
		int ivalue = value;
		int delta1, delta2;
		s->clk_mask <<= 1;
		s->clk_mask |= 1;

		if(     ((s->clk_mask&0x1f)==0x1f) &&
			( (delta1=(ivalue         - s->clk_prevval1) & lt_optimask[s->len]) == ((s->clk_prevval1 - s->clk_prevval3) & lt_optimask[s->len]) ) &&
			( (delta2=(s->clk_prevval - s->clk_prevval2) & lt_optimask[s->len]) == ((s->clk_prevval2 - s->clk_prevval4) & lt_optimask[s->len]) ) &&
			( (delta1==delta2) || ((!delta1)&&(!delta2)) )
			)
			{
			if(s->clk_prevtrans==ULLDescriptor(~0))
				{
				s->clk_prevtrans = lt->timeval;
				s->clk_numtrans = 0;
				}
			else
			if(s->clk_numtrans == 0)
				{
				s->clk_delta = lt->timeval - s->clk_prevtrans;
				s->clk_prevtrans = lt->timeval;
				s->clk_numtrans++;
				}
			else
				{
				if(s->clk_delta == (lt->timeval - s->clk_prevtrans))
					{
					s->clk_numtrans++;
					s->clk_prevtrans = lt->timeval;
					if(s->clk_numtrans > LT_CLKPACK_M)
						{
						s->clk_prevval4 = s->clk_prevval3;
						s->clk_prevval3 = s->clk_prevval2;
						s->clk_prevval2 = s->clk_prevval1;
						s->clk_prevval1 = s->clk_prevval;
						s->clk_prevval  = ivalue;

						/* printf("Clock value '%08x' for '%s' at %lld (#%d)\n", ivalue, s->name, lt->timeval, s->clk_numtrans); */
						return(1);
						}
					}
					else
					{
					if(s->clk_numtrans > LT_CLKPACK_M)
						{
						lt_flushclock_m(lt, s);
						/* flush clock then continue below! */
						}
						else
						{
						s->clk_prevtrans=ULLDescriptor(~0);
						}
					}
				}

			}
			else
			{
			if(s->clk_numtrans > LT_CLKPACK_M)
				{
				lt_flushclock_m(lt, s);
				/* flush clock then continue below! */
				}
				else
				{
				s->clk_prevtrans=ULLDescriptor(~0);
				}
			}

		s->clk_prevval4 = s->clk_prevval3;
		s->clk_prevval3 = s->clk_prevval2;
		s->clk_prevval2 = s->clk_prevval1;
		s->clk_prevval1 = s->clk_prevval;
		s->clk_prevval  = ivalue;
		}
	else
	if(len==1) /* possible clock handling */
		{
		int ivalue = value&1;

		if(((s->clk_prevval == '1') && (ivalue==0)) || ((s->clk_prevval == '0') && (ivalue==1)))
			{
			if(s->clk_prevtrans==ULLDescriptor(~0))
				{
				s->clk_prevtrans = lt->timeval;
				s->clk_numtrans = 0;
				}
			else
			if(s->clk_numtrans == 0)
				{
				s->clk_delta = lt->timeval - s->clk_prevtrans;
				s->clk_prevtrans = lt->timeval;
				s->clk_numtrans++;
				}
			else
				{
				if(s->clk_delta == (lt->timeval - s->clk_prevtrans))
					{
					s->clk_numtrans++;
					s->clk_prevtrans = lt->timeval;
					if(s->clk_numtrans > LT_CLKPACK)
						{
						s->clk_prevval = ivalue + '0';

						/* printf("Clock value '%d' for '%s' at %d (#%d)\n", ivalue, s->name, lt->timeval, s->clk_numtrans); */
						return(1);
						}
					}
					else
					{
					if(s->clk_numtrans > LT_CLKPACK)
						{
						lt_flushclock(lt, s);
						/* flush clock then continue below! */
						}
						else
						{
						s->clk_prevtrans=ULLDescriptor(~0);
						}
					}
				}

			}
			else
			{
			if(s->clk_numtrans > LT_CLKPACK)
				{
				lt_flushclock(lt, s);
				/* flush clock then continue below! */
				}
				else
				{
				s->clk_prevtrans=ULLDescriptor(~0);
				}
			}

		s->clk_prevval = ivalue + '0';
		}
	}

	/* normal trace handling */

	last_change_delta = lt->position - s->last_change - 2;

	if(last_change_delta >= 256*65536)
		{
		numbytes = 3;
		}
	else
	if(last_change_delta >= 65536)
		{
		numbytes = 2;
		}
	else
	if(last_change_delta >= 256)
		{
		numbytes = 1;
		}
	else
		{
		numbytes = 0;
		}

	if(len<=32)
		{
		int start_position = lt->position;
		int tag;
		int optimized0 = ((value&lt_optimask[len])==0);
		int optimized1 = ((value&lt_optimask[len])==lt_optimask[len]);
		int optimized  = optimized0|optimized1;

		if(!lt->numfacs_bytes)
			{
			if(optimized)
				{
				tag = (numbytes<<4) | (3+optimized1);	/* for x3 and x4 cases */
				}
				else
				{
				tag = (numbytes<<4);
				}

			lt->lt_emit_u8(lt, tag);
			switch(numbytes&3)
				{
				case 0: lt->lt_emit_u8(lt, last_change_delta); break;
				case 1: lt->lt_emit_u16(lt, last_change_delta); break;
				case 2: lt->lt_emit_u24(lt, last_change_delta); break;
				case 3: lt->lt_emit_u32(lt, last_change_delta); break;
				}
			}
			else
			{
			switch(lt->numfacs_bytes)
				{
				case 1: lt->lt_emit_u8(lt, s->facnum); break;
				case 2: lt->lt_emit_u16(lt, s->facnum); break;
				case 3: lt->lt_emit_u24(lt, s->facnum); break;
				case 4: lt->lt_emit_u32(lt, s->facnum); break;
				}
			lt->lt_emit_u8(lt, optimized ? (3+optimized1) : 0);
			}

		s->last_change = start_position;

		if(s->rows>0)
			{
			if(s->rows >= 256*65536)
				{
				numbytes = 3;
				}
			else
			if(s->rows >= 65536)
				{
				numbytes = 2;
				}
			else
			if(s->rows >= 256)
				{
				numbytes = 1;
				}
			else
				{
				numbytes = 0;
				}

			switch(numbytes&3)
				{
				case 0: lt->lt_emit_u8(lt, row); break;
				case 1: lt->lt_emit_u16(lt, row); break;
				case 2: lt->lt_emit_u24(lt, row); break;
				case 3: lt->lt_emit_u32(lt, row); break;
				}
			}

		if(!optimized)
			{
			if((lt->dictmode)&&(len>lt->mindictwidth))
				{
				char *vpnt_orig = lt_expand_integer_to_bits(len, value);
				char *vpnt = vpnt_orig;

				while ( (*vpnt == '0') && (*(vpnt+1)) ) vpnt++;

				lt->dict = dslxt_splay (vpnt, lt->dict);
				if(!dslxt_success)
					{
					unsigned int vlen = strlen(vpnt)+1;
					char *vcopy = (char *)malloc(vlen);

					strcpy(vcopy, vpnt);
					lt->dict_string_mem_required += vlen;
					lt->dict = dslxt_insert(vcopy, lt->dict, lt->num_dict_entries);

					if(!lt->dict16_offset)
						{
						if(lt->num_dict_entries==256) lt->dict16_offset = lt->position;
						}
					else
					if(!lt->dict24_offset)
						{
						if(lt->num_dict_entries==65536) lt->dict24_offset = lt->position;
						}
					else
					if(!lt->dict32_offset)
						{
						if(lt->num_dict_entries==(256*65536)) lt->dict32_offset = lt->position;
						}

					lt->num_dict_entries++;
					}

				if(lt->dict24_offset)
					{
					if(lt->dict32_offset)
						{
						lt->lt_emit_u32(lt, lt->dict->val);
						}
						else
						{
						lt->lt_emit_u24(lt, lt->dict->val);
						}
					}
				else
					{
					if(lt->dict16_offset)
						{
						lt->lt_emit_u16(lt, lt->dict->val);
						}
						else
						{
						lt->lt_emit_u8(lt, lt->dict->val);
						}
					}
				}
			else
			if(len<9)
				{
				value <<= (8-len);
				rc=lt->lt_emit_u8(lt, value);
				}
			else
			if(len<17)
				{
				value <<= (16-len);
				rc=lt->lt_emit_u16(lt, value);
				}
			else
			if(len<25)
				{
				value <<= (24-len);
				rc=lt->lt_emit_u24(lt, value);
				}
			else
				{
				value <<= (32-len);
				rc=lt->lt_emit_u32(lt, value);
				}
			}
		}

	if(lt->timebuff)
		{
		lt->timechangecount++;
		if(lt->timecurr)
			{
			lt->timecurr->next = lt->timebuff;
			lt->timecurr = lt->timebuff;
			}
			else
			{
			lt->timehead = lt->timecurr = lt->timebuff;
			}

		lt->timebuff=NULL;
		}
	}

return(rc);
}


int lt_emit_value_double(struct lt_trace *lt, struct lt_symbol *s, unsigned int row, double value)
{
int rc=0;
int start_position;
int tag;

if((!lt)||(!s)) return(rc);

if(!lt->emitted) lt->emitted = 1;

while(s->aliased_to)	/* find root alias if exists */
	{
	s=s->aliased_to;
	}

if((s->flags)&LT_SYM_F_DOUBLE)
	{
	int numbytes;				/* number of bytes to store value minus one */
	unsigned int last_change_delta = lt->position - s->last_change - 2;

	if(!lt->numfacs_bytes)
		{
		if(last_change_delta >= 256*65536)
			{
			numbytes = 3;
			}
		else
		if(last_change_delta >= 65536)
			{
			numbytes = 2;
			}
		else
		if(last_change_delta >= 256)
			{
			numbytes = 1;
			}
		else
			{
			numbytes = 0;
			}

		start_position = lt->position;
		s->last_change = start_position;

		tag = (numbytes<<4);
		lt->lt_emit_u8(lt, tag);
		switch(numbytes&3)
			{
			case 0: lt->lt_emit_u8(lt, last_change_delta); break;
			case 1: lt->lt_emit_u16(lt, last_change_delta); break;
			case 2: lt->lt_emit_u24(lt, last_change_delta); break;
			case 3: lt->lt_emit_u32(lt, last_change_delta); break;
			}
		}
		else
		{
		switch(lt->numfacs_bytes)
			{
			case 1: lt->lt_emit_u8(lt, s->facnum); break;
			case 2: lt->lt_emit_u16(lt, s->facnum); break;
			case 3: lt->lt_emit_u24(lt, s->facnum); break;
			case 4: lt->lt_emit_u32(lt, s->facnum); break;
			}
		}

	if(s->rows>0)
		{
		if(s->rows >= 256*65536)
			{
			numbytes = 3;
			}
		else
		if(s->rows >= 65536)
			{
			numbytes = 2;
			}
		else
		if(s->rows >= 256)
			{
			numbytes = 1;
			}
		else
			{
			numbytes = 0;
			}

		switch(numbytes&3)
			{
			case 0: lt->lt_emit_u8(lt, row); break;
			case 1: lt->lt_emit_u16(lt, row); break;
			case 2: lt->lt_emit_u24(lt, row); break;
			case 3: lt->lt_emit_u32(lt, row); break;
			}
		}

	rc=lt->lt_emit_double(lt, value);

	if(lt->timebuff)
		{
		lt->timechangecount++;
		if(lt->timecurr)
			{
			lt->timecurr->next = lt->timebuff;
			lt->timecurr = lt->timebuff;
			}
			else
			{
			lt->timehead = lt->timecurr = lt->timebuff;
			}

		lt->timebuff=NULL;
		}
	}

return(rc);
}


int lt_emit_value_string(struct lt_trace *lt, struct lt_symbol *s, unsigned int row, char *value)
{
int rc=0;
int start_position;
int tag;

if((!lt)||(!s)||(!value)) return(rc);

if(!lt->emitted) lt->emitted = 1;

while(s->aliased_to)	/* find root alias if exists */
	{
	s=s->aliased_to;
	}

if((s->flags)&LT_SYM_F_STRING)
	{
	int numbytes;				/* number of bytes to store value minus one */
	unsigned int last_change_delta = lt->position - s->last_change - 2;

	if(!lt->numfacs_bytes)
		{
		if(last_change_delta >= 256*65536)
			{
			numbytes = 3;
			}
		else
		if(last_change_delta >= 65536)
			{
			numbytes = 2;
			}
		else
		if(last_change_delta >= 256)
			{
			numbytes = 1;
			}
		else
			{
			numbytes = 0;
			}

		start_position = lt->position;
		s->last_change = start_position;

		tag = (numbytes<<4);
		lt->lt_emit_u8(lt, tag);
		switch(numbytes&3)
			{
			case 0: lt->lt_emit_u8(lt, last_change_delta); break;
			case 1: lt->lt_emit_u16(lt, last_change_delta); break;
			case 2: lt->lt_emit_u24(lt, last_change_delta); break;
			case 3: lt->lt_emit_u32(lt, last_change_delta); break;
			}
		}
		else
		{
		switch(lt->numfacs_bytes)
			{
			case 1: lt->lt_emit_u8(lt, s->facnum); break;
			case 2: lt->lt_emit_u16(lt, s->facnum); break;
			case 3: lt->lt_emit_u24(lt, s->facnum); break;
			case 4: lt->lt_emit_u32(lt, s->facnum); break;
			}
		}

	if(s->rows>0)
		{
		if(s->rows >= 256*65536)
			{
			numbytes = 3;
			}
		else
		if(s->rows >= 65536)
			{
			numbytes = 2;
			}
		else
		if(s->rows >= 256)
			{
			numbytes = 1;
			}
		else
			{
			numbytes = 0;
			}

		switch(numbytes&3)
			{
			case 0: lt->lt_emit_u8(lt, row); break;
			case 1: lt->lt_emit_u16(lt, row); break;
			case 2: lt->lt_emit_u24(lt, row); break;
			case 3: lt->lt_emit_u32(lt, row); break;
			}
		}

	rc=lt->lt_emit_string(lt, value);

	if(lt->timebuff)
		{
		lt->timechangecount++;
		if(lt->timecurr)
			{
			lt->timecurr->next = lt->timebuff;
			lt->timecurr = lt->timebuff;
			}
			else
			{
			lt->timehead = lt->timecurr = lt->timebuff;
			}

		lt->timebuff=NULL;
		}
	}

return(rc);
}


int lt_emit_value_bit_string(struct lt_trace *lt, struct lt_symbol *s, unsigned int row, char *value)
{
int rc=0;
int start_position;
int tag, tagadd;

if((!lt)||(!s)||(!value)||(!*value)) return(rc);

if(!lt->emitted) lt->emitted = 1;

while(s->aliased_to)	/* find root alias if exists */
	{
	s=s->aliased_to;
	}

if(!(s->flags&(LT_SYM_F_DOUBLE|LT_SYM_F_STRING)))
	{
	int numbytes;				/* number of bytes to store value minus one */
	char *pnt;
	int mvl=0;
	char ch;
	char prevch;
	unsigned int last_change_delta;

	unsigned int len = ((s->flags)&LT_SYM_F_INTEGER) ? 32 : s->len;

	if((lt->clock_compress)&&(s->rows==0))
	{
	if((len>1)&&(len<=32))
		{
		int legal = 0;
		int ivalue = 0;
		unsigned int i;
		char *pntv = value;
		int delta1, delta2;

		for(i=0;i<len;i++)
			{
			if((*pntv!='0')&&(*pntv!='1'))
				{
				if((!*pntv)&&(i>0))
					{
					pntv--;
					}
					else
					{
					legal = 0;
					break;
					}
				}

			ivalue = (((unsigned int)ivalue) << 1);
			ivalue |= (*pntv & 1);
			legal = 1;
			pntv++;
			}
		s->clk_mask <<= 1;
		s->clk_mask |= legal;

		if(     ((s->clk_mask&0x1f)==0x1f) &&
			( (delta1=(ivalue         - s->clk_prevval1) & lt_optimask[s->len]) == ((s->clk_prevval1 - s->clk_prevval3) & lt_optimask[s->len]) ) &&
			( (delta2=(s->clk_prevval - s->clk_prevval2) & lt_optimask[s->len]) == ((s->clk_prevval2 - s->clk_prevval4) & lt_optimask[s->len]) ) &&
			( (delta1==delta2) || ((!delta1)&&(!delta2)) )
			)
			{
			if(s->clk_prevtrans==ULLDescriptor(~0))
				{
				s->clk_prevtrans = lt->timeval;
				s->clk_numtrans = 0;
				}
			else
			if(s->clk_numtrans == 0)
				{
				s->clk_delta = lt->timeval - s->clk_prevtrans;
				s->clk_prevtrans = lt->timeval;
				s->clk_numtrans++;
				}
			else
				{
				if(s->clk_delta == (lt->timeval - s->clk_prevtrans))
					{
					s->clk_numtrans++;
					s->clk_prevtrans = lt->timeval;
					if(s->clk_numtrans > LT_CLKPACK_M)
						{
						s->clk_prevval4 = s->clk_prevval3;
						s->clk_prevval3 = s->clk_prevval2;
						s->clk_prevval2 = s->clk_prevval1;
						s->clk_prevval1 = s->clk_prevval;
						s->clk_prevval  = ivalue;

						/* printf("Clock value '%08x' for '%s' [len=%d] at %lld (#%d)\n",
							ivalue, s->name, len, lt->timeval, s->clk_numtrans); */
						return(1);
						}
					}
					else
					{
					if(s->clk_numtrans > LT_CLKPACK_M)
						{
						lt_flushclock_m(lt, s);
						/* flush clock then continue below! */
						}
						else
						{
						s->clk_prevtrans=ULLDescriptor(~0);
						}
					}
				}

			}
			else
			{
			if(s->clk_numtrans > LT_CLKPACK_M)
				{
				lt_flushclock_m(lt, s);
				/* flush clock then continue below! */
				}
				else
				{
				s->clk_prevtrans=ULLDescriptor(~0);
				}
			}

		s->clk_prevval4 = s->clk_prevval3;
		s->clk_prevval3 = s->clk_prevval2;
		s->clk_prevval2 = s->clk_prevval1;
		s->clk_prevval1 = s->clk_prevval;
		s->clk_prevval  = ivalue;
		}
	else
	if(len==1) /* possible clock handling */
		{
		if(((s->clk_prevval == '1') && (value[0]=='0')) || ((s->clk_prevval == '0') && (value[0]=='1')))
			{
			if(s->clk_prevtrans==ULLDescriptor(~0))
				{
				s->clk_prevtrans = lt->timeval;
				s->clk_numtrans = 0;
				}
			else
			if(s->clk_numtrans == 0)
				{
				s->clk_delta = lt->timeval - s->clk_prevtrans;
				s->clk_prevtrans = lt->timeval;
				s->clk_numtrans++;
				}
			else
				{
				if(s->clk_delta == (lt->timeval - s->clk_prevtrans))
					{
					s->clk_numtrans++;
					s->clk_prevtrans = lt->timeval;
					if(s->clk_numtrans > LT_CLKPACK)
						{
						s->clk_prevval = value[0];

						/* printf("Clock value '%c' for '%s' at %lld (#%d)\n", value[0], s->name, lt->timeval, s->clk_numtrans); */
						return(1);
						}
					}
					else
					{
					if(s->clk_numtrans > LT_CLKPACK)
						{
						lt_flushclock(lt, s);
						/* flush clock then continue below! */
						}
						else
						{
						s->clk_prevtrans=ULLDescriptor(~0);
						}
					}
				}

			}
			else
			{
			if(s->clk_numtrans > LT_CLKPACK)
				{
				lt_flushclock(lt, s);
				/* flush clock then continue below! */
				}
				else
				{
				s->clk_prevtrans=ULLDescriptor(~0);
				}
			}

		s->clk_prevval = value[0];
		}
	}

	/* normal trace handling */

	last_change_delta = lt->position - s->last_change - 2;

	if(last_change_delta >= 256*65536)
		{
		numbytes = 3;
		}
	else
	if(last_change_delta >= 65536)
		{
		numbytes = 2;
		}
	else
	if(last_change_delta >= 256)
		{
		numbytes = 1;
		}
	else
		{
		numbytes = 0;
		}

	pnt = value;
	prevch = *pnt;
	while((ch=*(pnt++)))
		{
		switch(ch)
			{
			case '0':
			case '1':	mvl|=LT_MVL_2; break;
			case 'Z':
			case 'z':
			case 'X':
			case 'x':	mvl|=LT_MVL_4; break;
			default:	mvl|=LT_MVL_9; break;
			}

		if(prevch!=ch) prevch = 0;
		}

	switch(prevch)
		{
		case 0x00:	tagadd = 0; break;
		case '0':	tagadd = 3; break;
		case '1':	tagadd = 4; break;
		case 'Z':
		case 'z':	tagadd = 5; break;
		case 'X':
		case 'x':	tagadd = 6; break;
		case 'H':
		case 'h':	tagadd = 7; break;
		case 'U':
		case 'u':	tagadd = 8; break;
		case 'W':
		case 'w':	tagadd = 9; break;
		case 'L':
		case 'l':	tagadd = 0xa; break;
		default:	tagadd = 0xb; break;
		}

	if(mvl)
		{
		start_position = lt->position;

		if(!lt->numfacs_bytes)
			{
			if(tagadd)
				{
				tag = (numbytes<<4) + tagadd;
				}
				else
				{
				tag = (numbytes<<4) + ((mvl&LT_MVL_9)? 2 : ((mvl&LT_MVL_4)? 1 : 0));
				}
			lt->lt_emit_u8(lt, tag);
			switch(numbytes&3)
				{
				case 0: lt->lt_emit_u8(lt, last_change_delta); break;
				case 1: lt->lt_emit_u16(lt, last_change_delta); break;
				case 2: lt->lt_emit_u24(lt, last_change_delta); break;
				case 3: lt->lt_emit_u32(lt, last_change_delta); break;
				}
			}
			else
			{
			switch(lt->numfacs_bytes)
				{
				case 1: lt->lt_emit_u8(lt, s->facnum); break;
				case 2: lt->lt_emit_u16(lt, s->facnum); break;
				case 3: lt->lt_emit_u24(lt, s->facnum); break;
				case 4: lt->lt_emit_u32(lt, s->facnum); break;
				}
			if(tagadd)
				{
				lt->lt_emit_u8(lt, tagadd);
				}
				else
				{
				lt->lt_emit_u8(lt, (mvl&LT_MVL_9)? 2 : ((mvl&LT_MVL_4)? 1 : 0) );
				}
			}

		s->last_change = start_position;

		if(s->rows>0)
			{
			if(s->rows >= 256*65536)
				{
				numbytes = 3;
				}
			else
			if(s->rows >= 65536)
				{
				numbytes = 2;
				}
			else
			if(s->rows >= 256)
				{
				numbytes = 1;
				}
			else
				{
				numbytes = 0;
				}

			switch(numbytes&3)
				{
				case 0: lt->lt_emit_u8(lt, row); break;
				case 1: lt->lt_emit_u16(lt, row); break;
				case 2: lt->lt_emit_u24(lt, row); break;
				case 3: lt->lt_emit_u32(lt, row); break;
				}
			}

		if(!tagadd)
			{
			unsigned int len2 = ((s->flags)&LT_SYM_F_INTEGER) ? 32 : s->len;
			if((mvl & (LT_MVL_2|LT_MVL_4|LT_MVL_9)) == LT_MVL_2)
				{
				unsigned int i;
				int bitpos = 7;
				int outval = 0;
				int thisval= 0;

				pnt = value;

				if((lt->dictmode)&&(len2>lt->mindictwidth))
					{
					char *vpnt = value;
					while ( (*vpnt == '0') && (*(vpnt+1)) ) vpnt++;

					lt->dict = dslxt_splay (vpnt, lt->dict);
					if(!dslxt_success)
						{
						unsigned int vlen = strlen(vpnt)+1;
						char *vcopy = (char *)malloc(vlen);

						strcpy(vcopy, vpnt);
						lt->dict_string_mem_required += vlen;
						lt->dict = dslxt_insert(vcopy, lt->dict, lt->num_dict_entries);

						if(!lt->dict16_offset)
							{
							if(lt->num_dict_entries==256) lt->dict16_offset = lt->position;
							}
						else
						if(!lt->dict24_offset)
							{
							if(lt->num_dict_entries==65536) lt->dict24_offset = lt->position;
							}
						else
						if(!lt->dict32_offset)
							{
							if(lt->num_dict_entries==(256*65536)) lt->dict32_offset = lt->position;
							}

						lt->num_dict_entries++;
						}

					if(lt->dict24_offset)
						{
						if(lt->dict32_offset)
							{
							lt->lt_emit_u32(lt, lt->dict->val);
							}
							else
							{
							lt->lt_emit_u24(lt, lt->dict->val);
							}
						}
					else
						{
						if(lt->dict16_offset)
							{
							lt->lt_emit_u16(lt, lt->dict->val);
							}
							else
							{
							lt->lt_emit_u8(lt, lt->dict->val);
							}
						}
					}
				else
				for(i=0;i<len2;i++)
					{
					if(*pnt)
						{
						thisval = (*pnt=='1');
						pnt++;
						}
					outval |= (thisval<<bitpos);
					bitpos--;
					if((bitpos==-1)||(i==len2-1))
						{
						lt->lt_emit_u8(lt, outval);
						outval = 0;
						bitpos = 7;
						}
					}
				}
			else
			if((mvl & (LT_MVL_4|LT_MVL_9)) == LT_MVL_4)
				{
				unsigned int i;
				int bitpos = 6;
				int outval = 0;
				int thisval= 0;

				pnt = value;

				for(i=0;i<len2;i++)
					{
					if(*pnt)
						{
						switch(*pnt)
							{
							case '0':	thisval = 0; break;
							case '1':	thisval = 1; break;
							case 'X':
							case 'x':	thisval = 3; break;
							default:	thisval = 2; break;
							}
						pnt++;
						}
					outval |= (thisval<<bitpos);
					bitpos-=2;
					if((bitpos==-2)||(i==len2-1))
						{
						lt->lt_emit_u8(lt, outval);
						outval = 0;
						bitpos = 6;
						}
					}
				}
			else
			/* if(mvl & LT_MVL_9) */
				{
				unsigned int i;
				int bitpos = 4;
				int outval = 0;
				int thisval= 0;

				pnt = value;

				for(i=0;i<len2;i++)
					{
					if(*pnt)
						{
						switch(*pnt)
							{
							case '0':	thisval = 0; break;
							case '1':	thisval = 1; break;
							case 'Z':
							case 'z':	thisval = 2; break;
							case 'X':
							case 'x':	thisval = 3; break;
							case 'H':
							case 'h':	thisval = 4; break;
							case 'U':
							case 'u':	thisval = 5; break;
							case 'W':
							case 'w':	thisval = 6; break;
							case 'L':
							case 'l':	thisval = 7; break;
							default:	thisval = 8; break;
							}
						pnt++;
						}
					outval |= (thisval<<bitpos);
					bitpos-=4;
					if((bitpos==-4)||(i==len2-1))
						{
						lt->lt_emit_u8(lt, outval);
						outval = 0;
						bitpos = 4;
						}
					}
				}
			}

		rc=1;
		}

	if(lt->timebuff)
		{
		lt->timechangecount++;
		if(lt->timecurr)
			{
			lt->timecurr->next = lt->timebuff;
			lt->timecurr = lt->timebuff;
			}
			else
			{
			lt->timehead = lt->timecurr = lt->timebuff;
			}

		lt->timebuff=NULL;
		}
	}

return(rc);
}


/*
 * blackout functions
 */
void lt_set_dumpoff(struct lt_trace *lt)
{
if((lt)&&(!lt->dumpoff_active))
	{
	struct lt_timetrail *ltt = calloc(1, sizeof(struct lt_timetrail));

	ltt->timeval = lt->timeval;
	if(lt->dumpoffhead)
		{
		lt->dumpoffcurr->next = ltt;
		lt->dumpoffcurr = ltt;
		}
		else
		{
		lt->dumpoffhead = lt->dumpoffcurr = ltt;
		}

	lt->dumpoff_active = 1;
	lt->dumpoffcount++;
	}
}

void lt_set_dumpon(struct lt_trace *lt)
{
if((lt)&&(lt->dumpoff_active))
	{
	struct lt_timetrail *ltt = calloc(1, sizeof(struct lt_timetrail));

	ltt->timeval = lt->timeval;

	lt->dumpoffcurr->next = ltt;
	lt->dumpoffcurr = ltt;

	lt->dumpoff_active = 0;
	}
}

void lt_set_timezero(struct lt_trace *lt, lxtotime_t timeval)
{
if(lt)
	{
	lt->timezero = timeval;
	}
}

