1 /*
2  * Copyright (c) Tony Bybell 1999-2016.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  */
9 
10 /* AIX may need this for alloca to work */
11 #if defined _AIX
12   #pragma alloca
13 #endif
14 
15 #include "globals.h"
16 #include <config.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include "symbol.h"
21 #include "lxt.h"
22 #include "debug.h"
23 #include "bsearch.h"
24 #include "strace.h"
25 #include "translate.h"
26 #include "ptranslate.h"
27 #include "ttranslate.h"
28 #include "hierpack.h"
29 #include "analyzer.h"
30 
31 #ifdef _MSC_VER
32 #define strcasecmp _stricmp
33 #endif
34 
35 void UpdateTraceSelection(Trptr t);
36 int traverse_vector_nodes(Trptr t);
37 
38 /*
39  * extract last n levels of hierarchy
40  */
hier_extract(char * pnt,int levels)41 char *hier_extract(char *pnt, int levels)
42 {
43 int i, len;
44 char ch, *pnt2, *esc;
45 char only_nums_so_far=1;
46 
47 if(!pnt) return(NULL);
48 
49 len=strlen(pnt);
50 if(!len) return(pnt);
51 
52 if(levels<1) levels=1;
53 if((!GLOBALS->hier_ignore_escapes) &&(esc=strchr(pnt, '\\')))
54 	{
55 	return((levels==1) ? esc : pnt); /* shortcut out on escape IDs: level=1, esc char else all */
56 	}
57 
58 pnt2=pnt+len-1;
59 /* ch=*pnt2; */ /* scan-build : useless given loop below */
60 
61 for(i=0;i<len;i++)
62 	{
63 	ch=*(pnt2--);
64 	if((only_nums_so_far)&&(ch>='0')&&(ch<='9'))		/* skip 1st set of signal.number hier from right if it exists */
65 		{
66 		continue;
67 		/* nothing */
68 		}
69 	else
70 		{
71 		if(ch==GLOBALS->hier_delimeter)
72 			{
73 			if(!only_nums_so_far) levels--;
74 			if(!levels)
75 				{
76 				pnt2+=2;
77 				return(pnt2);
78 				}
79 			}
80 		only_nums_so_far=0;
81 		}
82 	}
83 
84 return(pnt); /* not as many levels as max, so give the full name.. */
85 }
86 
updateTraceGroup(Trptr t)87 void updateTraceGroup(Trptr t)
88 {
89   /*  t->t_match = NULL; */
90 
91   if (t->t_prev)
92     {
93       if (IsGroupBegin(t->t_prev))
94 	{
95 	  if (IsGroupEnd(t))
96 	    { /* empty group */
97 	      Trptr g_begin = t->t_prev;
98 	      t->t_grp = g_begin->t_grp;
99 	      t->t_match = g_begin;
100 	      g_begin->t_match = t;
101 	    }
102 	  else
103 	    { /* first trace in group */
104 	      t->t_grp = t->t_prev;
105 	    }
106 	}
107       else
108 	{
109 	  if (IsGroupEnd(t))
110 	    {
111 	      Trptr g_begin = t->t_prev->t_grp;
112 	      if(g_begin) /* scan-build */
113 		{
114 	      	t->t_grp = g_begin->t_grp;
115 	      	t->t_match = g_begin;
116 	      	g_begin->t_match = t;
117 		}
118 	    }
119 	  else
120 	    {
121 	      t->t_grp = t->t_prev->t_grp;
122 	    }
123 
124 
125 	}
126     }
127   else
128     { /* very first trace */
129       t->t_grp = NULL;
130     }
131 
132   if ((t->t_grp) && IsSelected(t->t_grp))
133     {
134       t->flags |= TR_HIGHLIGHT;
135     }
136 }
137 
CloseTrace(Trptr t)138 void CloseTrace(Trptr t)
139 {
140 GLOBALS->traces.dirty = 1;
141 
142   if (IsGroupBegin(t))
143     {
144       t->flags |= TR_CLOSED;
145       if (t->t_match) { t->t_match->flags |= TR_CLOSED; };
146 
147       if (!HasWave(t))
148 	{
149 	  /* Group End */
150 	  if (t->t_match) { t->t_match->flags |= TR_COLLAPSED; };
151 	}
152       else
153 	{
154 	  /* Composite  End */
155 	  if (t->t_match) { t->t_match->flags |= TR_COLLAPSED; };
156 	}
157     }
158 
159   if (IsGroupEnd(t))
160     {
161       t->flags |= TR_CLOSED;
162       if (t->t_match) { t->t_match->flags |= TR_CLOSED; };
163 
164       if ((t->t_match) && !HasWave(t->t_match))
165 	{
166 	  /* Group End */
167 	  t->flags |= TR_COLLAPSED;
168 	}
169       else
170 	{
171 	  /* Composite End */
172 	  t->flags |= TR_COLLAPSED;
173 	}
174     }
175 }
176 
177 
OpenTrace(Trptr t)178 void OpenTrace(Trptr t)
179 {
180 GLOBALS->traces.dirty = 1;
181 
182   if (IsGroupBegin(t) || IsGroupEnd(t))
183   {
184     t->flags &= ~TR_CLOSED;
185     if (t->t_match) { t->t_match->flags &= ~TR_CLOSED; };
186 
187     if (!HasWave(t))
188       {
189 	t->flags &= ~TR_COLLAPSED;
190 	if(t->t_match) { t->t_match->flags &= ~TR_COLLAPSED; };
191       }
192   }
193 }
194 
ClearTraces(void)195 void ClearTraces(void)
196 {
197   Trptr t = GLOBALS->traces.first;
198   while(t)
199 	{
200 	  t->flags &= ~TR_HIGHLIGHT;
201 	  t=t->t_next;
202 	}
203   GLOBALS->traces.dirty = 1;
204 }
205 
ClearGroupTraces(Trptr t_grp)206 void ClearGroupTraces(Trptr t_grp)
207 {
208   if (IsGroupBegin(t_grp))
209     {
210       Trptr t = t_grp;
211       while(t)
212 	{
213 	  t->flags &= ~TR_HIGHLIGHT;
214 	  if(t->t_match == t_grp) break;
215 	  t=t->t_next;
216 	}
217     GLOBALS->traces.dirty = 1;
218     }
219   else
220     {
221       fprintf(stderr, "INTERNAL ERROR: ClearGroupTrace applied to non-group!  Exiting.\n");
222       exit(255);
223     }
224 }
225 
MarkTraceCursor(Trptr t_curs)226 void MarkTraceCursor(Trptr t_curs)
227 {
228 if(t_curs)
229 	{
230         Trptr t=GLOBALS->traces.first;
231 
232         while(t)
233                 {
234                 t->is_cursor = 0;
235                 t=t->t_next;
236                 }
237 
238         t_curs->is_cursor = 1;
239         }
240 }
241 
242 /*
243  * Add a trace to the display...
244  */
AddTrace(Trptr t)245 static void AddTrace( Trptr t )
246 {
247 GLOBALS->traces.dirty = 1;
248 
249 t->t_fpdecshift = GLOBALS->default_fpshift;
250 
251 if((GLOBALS->which_t_color > 0) && (GLOBALS->which_t_color <= WAVE_NUM_RAINBOW))
252 	{
253 	t->t_color = GLOBALS->which_t_color;
254 	GLOBALS->which_t_color = 0;
255 	}
256 
257 if(GLOBALS->default_flags&TR_NUMMASK) t->flags=GLOBALS->default_flags;
258 	else t->flags=(t->flags&TR_NUMMASK)|GLOBALS->default_flags;
259 
260 if(!t->vector && GLOBALS->enum_nptrs_jrb)
261 	{
262 	JRB enum_nptr = jrb_find_vptr(GLOBALS->enum_nptrs_jrb, t->n.nd);
263 	if(enum_nptr)
264 		{
265 		int e_filter = enum_nptr->val.ui;
266 		if((e_filter > 0) && (e_filter <= GLOBALS->num_xl_enum_filter))
267 			{
268 			t->e_filter = e_filter;
269 			if(!(GLOBALS->default_flags&TR_NUMMASK)) t->flags = (t->flags & (~TR_NUMMASK)) | TR_ENUM | TR_BIN; /* need to downgrade to bin to make visible */
270 			}
271 		}
272 	}
273 
274 if(GLOBALS->default_flags & TR_FTRANSLATED)
275 	{
276 	t->f_filter = GLOBALS->current_translate_file;
277 	}
278 else
279 if(GLOBALS->default_flags & TR_PTRANSLATED)
280 	{
281 	t->p_filter = GLOBALS->current_translate_proc;
282 	}
283 
284 /* NOT an else! */
285 if(GLOBALS->default_flags & TR_TTRANSLATED)
286 	{
287 	t->t_filter = GLOBALS->current_translate_ttrans;
288 	if(t->t_filter)
289 		{
290 		if(!t->vector)
291 			{
292 			bvptr v;
293 			TraceFlagsType cache_hi = t->flags & TR_HIGHLIGHT;
294 
295 			t->flags |= TR_HIGHLIGHT;
296                         v = combine_traces(1, t); /* down: make single signal a vector */
297                       	if(v)
298                               	{
299                                 v->transaction_nd = t->n.nd; /* cache for savefile, disable */
300                                 t->vector = 1;
301                              	t->n.vec = v;           /* splice in */
302                                	}
303 
304 			t->flags &= ~TR_HIGHLIGHT;
305 			t->flags |= cache_hi;
306 			}
307 
308 		if(GLOBALS->ttranslate_args)
309                 	{
310                         t->transaction_args = strdup_2(GLOBALS->ttranslate_args);
311                         }
312                         else
313                         {
314                         t->transaction_args = NULL;
315                         }
316 
317 		traverse_vector_nodes(t);
318 		}
319 		else
320 		{
321 		t->flags &= ~TR_TTRANSLATED; /* malformed filter syntax?  should never have "which" of zero here */
322 		}
323 	}
324 
325  if (IsGroupBegin(t)) {
326    GLOBALS->group_depth = GLOBALS->group_depth + 1;
327  }
328 
329  if (IsGroupEnd(t)) {
330    if (GLOBALS->group_depth == 0) {
331      fprintf(stderr, "ERROR: Group End encountered with no matching start. Ignoring.\n");
332      t->flags &= ~TR_GRP_END;
333    } else {
334      GLOBALS->group_depth = GLOBALS->group_depth - 1;
335    }
336  }
337 
338 if(GLOBALS->shift_timebase_default_for_add)
339 	t->shift=GLOBALS->shift_timebase_default_for_add;
340 
341 if(!GLOBALS->strace_ctx->shadow_active)
342 	{
343 	if( GLOBALS->traces.first == NULL )
344 		{
345 		t->t_next = t->t_prev = NULL;
346 		GLOBALS->traces.first = GLOBALS->traces.last = t;
347 	      	}
348 	    	else
349 	      	{
350 		t->t_next = NULL;
351 		t->t_prev = GLOBALS->traces.last;
352 		GLOBALS->traces.last->t_next = t;
353 		GLOBALS->traces.last = t;
354 	      	}
355 	GLOBALS->traces.total++;
356 	updateTraceGroup(GLOBALS->traces.last);
357 	}
358 	else	/* hide offscreen */
359 	{
360 	struct strace *st = calloc_2(1, sizeof(struct strace));
361 	st->next = GLOBALS->strace_ctx->shadow_straces;
362 	st->value = GLOBALS->strace_ctx->shadow_type;
363 	st->trace = t;
364 
365 	st->string = GLOBALS->strace_ctx->shadow_string; /* copy string over */
366 	GLOBALS->strace_ctx->shadow_string = NULL;
367 
368 	GLOBALS->strace_ctx->shadow_straces = st;
369 	}
370 }
371 
372 
373 /*
374  * Add a blank trace to the display...
375  */
precondition_string(char * s)376 static char *precondition_string(char *s)
377 {
378 int len=0;
379 char *s2;
380 
381 if(!s) return(NULL);
382 s2=s;
383 while((*s2)&&((*s2)!='\n')&&((*s2)!='\r'))	/* strip off ending CR/LF */
384 	{
385 	len++;
386 	s2++;
387 	}
388 if(!len) return(NULL);
389 s2=(char *)calloc_2(1,len+1);
390 memcpy(s2,s,len);
391 return(s2);
392 }
393 
AddBlankTrace(char * commentname)394 int AddBlankTrace(char *commentname)
395 {
396   Trptr  t;
397   char *comment;
398   TraceFlagsType flags_filtered;
399 
400   if( (t = (Trptr) calloc_2( 1, sizeof( TraceEnt ))) == NULL )
401     {
402       fprintf( stderr, "Out of memory, can't add blank trace to analyzer\n");
403       return( 0 );
404     }
405   AddTrace(t);
406   /* Keep only flags that make sense for a blank trace. */
407   flags_filtered = TR_BLANK | (GLOBALS->default_flags & (TR_CLOSED|
408 							 TR_GRP_BEGIN|
409 							 TR_GRP_END|
410 							 TR_COLLAPSED|
411 							 TR_ANALOG_BLANK_STRETCH));
412   t->flags = flags_filtered;
413   if(t->flags & TR_ANALOG_BLANK_STRETCH)
414 
415     {
416       t->flags &= ~TR_BLANK;
417     }
418 
419   if((comment=precondition_string(commentname)))
420     {
421       t->name      = comment;
422     }
423 
424   return(1);
425 }
426 
427 
428 /*
429  * Insert a blank [or comment] trace into the display...
430  */
InsertBlankTrace(char * comment,TraceFlagsType different_flags)431 int InsertBlankTrace(char *comment, TraceFlagsType different_flags)
432 {
433 TempBuffer tb;
434 char *comm;
435 Trptr  t;
436 
437 if( (t = (Trptr) calloc_2( 1, sizeof( TraceEnt ))) == NULL )
438 	{
439 	fprintf( stderr, "Out of memory, can't insert blank trace to analyzer\n");
440 	return( 0 );
441       	}
442 
443 GLOBALS->traces.dirty = 1;
444 
445 if(!different_flags)
446 	{
447 	t->flags=TR_BLANK;
448 	}
449 	else
450 	{
451 	t->flags = different_flags;
452 	}
453 
454 if((comm=precondition_string(comment)))
455 	{
456 	t->name = comm;
457 	}
458 
459 if(!GLOBALS->traces.first)
460 	{
461 	GLOBALS->traces.first=GLOBALS->traces.last=t;
462 	GLOBALS->traces.total=1;
463 	return(1);
464 	}
465 	else
466 	{
467 	tb.buffer=GLOBALS->traces.buffer;
468 	tb.bufferlast=GLOBALS->traces.bufferlast;
469 	tb.buffercount=GLOBALS->traces.buffercount;
470 
471 	GLOBALS->traces.buffer=GLOBALS->traces.bufferlast=t;
472 	GLOBALS->traces.buffercount=1;
473 	PasteBuffer();
474 
475 	GLOBALS->traces.buffer=tb.buffer;
476 	GLOBALS->traces.bufferlast=tb.bufferlast;
477 	GLOBALS->traces.buffercount=tb.buffercount;
478 
479 	return(1);
480 	}
481 }
482 
483 
484 /*
485  * Adds a single bit signal to the display...
486  */
AddNodeTraceReturn(nptr nd,char * aliasname,Trptr * tret)487 int AddNodeTraceReturn(nptr nd, char *aliasname, Trptr *tret)
488 {
489   Trptr  t;
490   hptr histpnt;
491   hptr *harray;
492   int histcount;
493   int i;
494 
495   if(!nd) return(0); /* passed it a null node ptr by mistake */
496   if(nd->mv.mvlfac) import_trace(nd);
497 
498   GLOBALS->signalwindow_width_dirty=1;
499   GLOBALS->traces.dirty = 1;
500 
501   if( (t = (Trptr) calloc_2( 1, sizeof( TraceEnt ))) == NULL )
502     {
503       fprintf( stderr, "Out of memory, can't add to analyzer\n" );
504       return( 0 );
505     }
506 
507   if(!nd->harray)		/* make quick array lookup for aet display */
508     {
509       histpnt=&(nd->head);
510       histcount=0;
511 
512       while(histpnt)
513 	{
514 	  histcount++;
515 	  histpnt=histpnt->next;
516 	}
517 
518       nd->numhist=histcount;
519 
520       if(!(nd->harray=harray=(hptr *)malloc_2(histcount*sizeof(hptr))))
521 	{
522 	  fprintf( stderr, "Out of memory, can't add to analyzer\n" );
523 	  free_2(t);
524 	  return(0);
525 	}
526 
527       histpnt=&(nd->head);
528       for(i=0;i<histcount;i++)
529 	{
530 	  *harray=histpnt;
531 	  harray++;
532 	  histpnt=histpnt->next;
533 	}
534     }
535 
536   if(aliasname)
537    {
538      char *alias;
539 
540      t->name_full = alias =(char *)malloc_2(strlen(aliasname)+1);
541      strcpy(alias,aliasname);
542      t->name = t->name_full;
543      if(GLOBALS->hier_max_level)
544        t->name = hier_extract(t->name_full, GLOBALS->hier_max_level);
545    }
546   else
547     {
548       if(!GLOBALS->hier_max_level)
549 	{
550 	  int flagged = HIER_DEPACK_ALLOC;
551 
552 	  t->name = hier_decompress_flagged(nd->nname, &flagged);
553 	  t->is_depacked = (flagged != 0);
554 	}
555       else
556 	{
557 	  int flagged = HIER_DEPACK_ALLOC;
558 	  char *tbuff = hier_decompress_flagged(nd->nname, &flagged);
559 	  if(!flagged)
560 	    {
561 	      t->name = hier_extract(nd->nname, GLOBALS->hier_max_level);
562 	    }
563 	  else
564 	    {
565 	      t->name = strdup_2(hier_extract(tbuff, GLOBALS->hier_max_level));
566 	      free_2(tbuff);
567 	      t->is_depacked = 1;
568 	    }
569 	}
570     }
571 
572   if(nd->extvals) /* expansion vectors */
573     {
574       int n;
575 
576       n = nd->msi - nd->lsi;
577       if(n<0)n=-n;
578       n++;
579 
580       switch(nd->vartype)
581 	{
582 	case ND_VCD_INTEGER:
583 	case ND_VCD_PARAMETER:
584 	case ND_SV_INT:
585 	case ND_SV_SHORTINT:
586 	case ND_SV_LONGINT:	t->flags = TR_SIGNED | TR_RJUSTIFY;
587 				break;
588 
589 	default: 		t->flags = (( n > 3 )||( n < -3 )) ? TR_HEX|TR_RJUSTIFY : TR_BIN|TR_RJUSTIFY;
590 				break;
591 	}
592     }
593   else
594     {
595       t->flags |= TR_BIN;	/* binary */
596     }
597   t->vector = FALSE;
598   t->n.nd = nd;
599   if(tret) *tret = t;		/* for expand */
600   AddTrace( t );
601   return( 1 );
602 }
603 
604 
605 /* single node */
AddNode(nptr nd,char * aliasname)606 int AddNode(nptr nd, char *aliasname)
607 {
608 return(AddNodeTraceReturn(nd, aliasname, NULL));
609 }
610 
611 
612 /* add multiple nodes (if array) */
AddNodeUnroll(nptr nd,char * aliasname)613 int AddNodeUnroll(nptr nd, char *aliasname)
614 {
615 #ifdef WAVE_ARRAY_SUPPORT
616 if(nd->array_height <= 1)
617 #endif
618 	{
619 	return(AddNodeTraceReturn(nd, aliasname, NULL));
620 	}
621 #ifdef WAVE_ARRAY_SUPPORT
622 	else
623 	{
624 	unsigned int i;
625 	int rc = 1;
626 
627 	for(i=0;i<nd->array_height;i++)
628 		{
629 		rc |= AddNodeTraceReturn(nd+i, aliasname, NULL);
630 		}
631 	return(rc);
632 	}
633 #endif
634 }
635 
636 
637 /*
638  * Adds a vector to the display...
639  */
AddVector(bvptr vec,char * aliasname)640 int AddVector(bvptr vec, char *aliasname)
641   {
642     Trptr  t;
643     int    n;
644 
645     if(!vec) return(0); /* must've passed it a null pointer by mistake */
646 
647     GLOBALS->signalwindow_width_dirty=1;
648     GLOBALS->traces.dirty = 1;
649 
650     n = vec->nbits;
651     t = (Trptr) calloc_2(1, sizeof( TraceEnt ) );
652     if( t == NULL )
653       {
654 	fprintf( stderr, "Out of memory, can't add %s to analyzer\n",
655 	  vec->bvname );
656 	return( 0 );
657       }
658 
659     if (aliasname)
660       {
661 	t->name_full = strdup_2(aliasname);
662 	t->name = t->name_full;
663       }
664     else
665       {
666 	t->name = vec->bvname;
667       }
668 
669     if(GLOBALS->hier_max_level)
670       t->name = hier_extract(t->name, GLOBALS->hier_max_level);
671 
672     t->flags = ( n > 3 ) ? TR_HEX|TR_RJUSTIFY : TR_BIN|TR_RJUSTIFY;
673     t->vector = TRUE;
674     t->n.vec = vec;
675     AddTrace( t );
676     return( 1 );
677   }
678 
679 
680 /*
681  * Free up a trace's mallocs...
682  */
FreeTrace(Trptr t)683 void FreeTrace(Trptr t)
684 {
685 GLOBALS->traces.dirty = 1;
686 
687 if(GLOBALS->starting_unshifted_trace == t)
688 	{
689 	GLOBALS->starting_unshifted_trace = NULL; /* for new "standard" clicking routines */
690 	}
691 
692 if(GLOBALS->strace_ctx->straces)
693 	{
694 	struct strace_defer_free *sd = calloc_2(1, sizeof(struct strace_defer_free));
695 	sd->next = GLOBALS->strace_ctx->strace_defer_free_head;
696 	sd->defer = t;
697 
698 	GLOBALS->strace_ctx->strace_defer_free_head = sd;
699 	return;
700 	}
701 
702 if(t->vector)
703       	{
704       	bvptr bv, bv2;
705 	int i;
706 
707 	bv=t->n.vec;
708 	/* back out allocation to revert (if any) */
709         if(bv->transaction_cache)
710 		{
711 		t->n.vec = bv->transaction_cache;
712 
713 		while(bv)
714 			{
715 			bv2 = bv->transaction_chain;
716 			if(bv->bvname) { free_2(bv->bvname); }
717 
718 	                for(i=0;i<bv->numregions;i++)
719 				{
720 	                        free_2(bv->vectors[i]);
721 	                        }
722 
723 	                free_2(bv);
724 			bv = bv2;
725 			}
726 
727 		bv=t->n.vec;
728                 }
729 
730 	/* normal vector deallocation */
731 	for(i=0;i<bv->numregions;i++)
732 		{
733 		if(bv->vectors[i]) free_2(bv->vectors[i]);
734 		}
735 
736 	if(bv->bits)
737 		{
738 		if(bv->bits->name) free_2(bv->bits->name);
739 		if(bv->bits->attribs) free_2(bv->bits->attribs);
740 		for(i=0;i<bv->nbits;i++)
741 			{
742 			DeleteNode(bv->bits->nodes[i]);
743 			}
744 		free_2(bv->bits);
745 		}
746 
747 	if(bv->bvname) free_2(bv->bvname);
748       	if(t->n.vec) free_2(t->n.vec);
749       	}
750 	else
751 	{
752 	if(t->n.nd && t->n.nd->expansion)
753 		{
754 		DeleteNode(t->n.nd);
755 		}
756 	}
757 
758  if(t->is_depacked) free_2(t->name);
759  if(t->asciivalue) free_2(t->asciivalue);
760  if(t->name_full)  free_2(t->name_full);
761  if(t->transaction_args) free_2(t->transaction_args);
762  free_2( t );
763 }
764 
765 
766 /*
767  * Remove a trace from the display and optionally
768  * deallocate its memory usage...
769  */
RemoveTrace(Trptr t,int dofree)770 void RemoveTrace( Trptr t, int dofree )
771   {
772     GLOBALS->traces.dirty = 1;
773     GLOBALS->traces.total--;
774     if( t == GLOBALS->traces.first )
775       {
776 	GLOBALS->traces.first = t->t_next;
777 	if( t->t_next )
778             t->t_next->t_prev = NULL;
779         else
780             GLOBALS->traces.last = NULL;
781       }
782     else
783       {
784         if(t->t_prev)
785 		{
786 	        t->t_prev->t_next = t->t_next;
787 		}
788 		else
789 		{
790 		/* this code should likely *never* execute as if( t == GLOBALS->traces.first ) above should catch this */
791 		/* there is likely a problem elsewhere in the code! */
792 
793 		Trptr t2 = GLOBALS->traces.first = t->t_next;
794 		GLOBALS->traces.total = 0;
795 		while(t2)
796 			{
797 			t2 = t2->t_next;
798 			GLOBALS->traces.total++;
799 			}
800 		}
801 
802 
803         if( t->t_next )
804             t->t_next->t_prev = t->t_prev;
805         else
806             GLOBALS->traces.last = t->t_prev;
807       }
808 
809     if(dofree)
810 	{
811         FreeTrace(t);
812 	}
813   }
814 
815 
816 /*
817  * Deallocate the cut/paste buffer...
818  */
FreeCutBuffer(void)819 void FreeCutBuffer(void)
820 {
821 Trptr t, t2;
822 
823 t=GLOBALS->traces.buffer;
824 
825 while(t)
826 	{
827 	t2=t->t_next;
828 	FreeTrace(t);
829 	t=t2;
830 	}
831 
832 GLOBALS->traces.buffer=GLOBALS->traces.bufferlast=NULL;
833 GLOBALS->traces.buffercount=0;
834 }
835 
836 
837 /*
838  * Cut highlighted traces from the main screen
839  * and throw them in the cut buffer.  If anything's
840  * in the cut buffer, deallocate it first...
841  */
CutBuffer(void)842 Trptr CutBuffer(void)
843 {
844 Trptr t, tnext;
845 Trptr first=NULL, current=NULL;
846 
847 GLOBALS->shift_click_trace=NULL;		/* so shift-clicking doesn't explode */
848 
849 t=GLOBALS->traces.first;
850 while(t)
851 	{
852 	if((t->flags)&(TR_HIGHLIGHT)) break;
853 	t=t->t_next;
854 	}
855 if(!t) return(NULL);	/* keeps a double cut from blowing out the buffer */
856 
857 GLOBALS->signalwindow_width_dirty=1;
858 GLOBALS->traces.dirty = 1;
859 
860 FreeCutBuffer();
861 
862 t=GLOBALS->traces.first;
863 while(t)
864 	{
865 	tnext=t->t_next;
866 	if(IsSelected(t) || (t->t_grp && IsSelected(t->t_grp)))
867 	  {
868 	    /* members of closed groups may not be highlighted */
869 	    /* so propogate highlighting here */
870 	    t->flags |= TR_HIGHLIGHT;
871 	    GLOBALS->traces.bufferlast=t;
872 	    GLOBALS->traces.buffercount++;
873 
874 	    /* t->flags&=(~TR_HIGHLIGHT); */
875 	    RemoveTrace(t, 0);
876 	    if(!current)
877 	      {
878 		first=current=t;
879 		t->t_prev=NULL;
880 		t->t_next=NULL;
881 	      }
882 	    else
883 	      {
884 		current->t_next=t;
885 		t->t_prev=current;
886 		current=t;
887 		t->t_next=NULL;
888 	      }
889 	  }
890 	t=tnext;
891 	}
892 
893 return(GLOBALS->traces.buffer=first);
894 }
895 
896 
897 /*
898  * Delete highlighted traces from the main screen
899  * and throw them away.  Do not affect existing cut buffer...
900  */
DeleteBuffer(void)901 int DeleteBuffer(void)
902 {
903 Trptr t, tnext;
904 Trptr 	 current=NULL;
905 Trptr    buffer;            /* cut/copy buffer of traces */
906 Trptr    bufferlast;        /* last element of bufferchain */
907 int      buffercount;       /* number of traces in buffer */
908 int      num_deleted;
909 
910 GLOBALS->shift_click_trace=NULL;		/* so shift-clicking doesn't explode */
911 
912 t=GLOBALS->traces.first;
913 while(t)
914 	{
915 	if((t->flags)&(TR_HIGHLIGHT)) break;
916 	t=t->t_next;
917 	}
918 if(!t) return(0);	/* nothing to do */
919 
920 GLOBALS->signalwindow_width_dirty=1;
921 GLOBALS->traces.dirty = 1;
922 
923 buffer = GLOBALS->traces.buffer; /* copy cut buffer to make re-entrant */
924 bufferlast = GLOBALS->traces.bufferlast;
925 buffercount = GLOBALS->traces.buffercount;
926 
927 GLOBALS->traces.buffer = NULL;
928 GLOBALS->traces.bufferlast = NULL;
929 GLOBALS->traces.buffercount = 0;
930 
931 t=GLOBALS->traces.first;
932 while(t)
933 	{
934 	tnext=t->t_next;
935 	if(IsSelected(t) || (t->t_grp && IsSelected(t->t_grp)))
936 	  {
937 	    /* members of closed groups may not be highlighted */
938 	    /* so propogate highlighting here */
939 	    t->flags |= TR_HIGHLIGHT;
940 	    GLOBALS->traces.bufferlast=t;
941 	    GLOBALS->traces.buffercount++;
942 
943 	    /* t->flags&=(~TR_HIGHLIGHT); */
944 	    RemoveTrace(t, 0);
945 	    if(!current)
946 	      {
947 		current=t;
948 		t->t_prev=NULL;
949 		t->t_next=NULL;
950 	      }
951 	    else
952 	      {
953 		current->t_next=t;
954 		t->t_prev=current;
955 		current=t;
956 		t->t_next=NULL;
957 	      }
958 	  }
959 	t=tnext;
960 	}
961 
962 num_deleted = GLOBALS->traces.buffercount;
963 FreeCutBuffer();
964 
965 GLOBALS->traces.buffer = buffer; /* restore cut buffer */
966 GLOBALS->traces.bufferlast = bufferlast;
967 GLOBALS->traces.buffercount = buffercount;
968 
969 return(num_deleted);
970 }
971 
972 
973 /*
974  * Paste the cut buffer into the main display one and
975  * mark the cut buffer empty...
976  */
PasteBuffer(void)977 Trptr PasteBuffer(void)
978 {
979   Trptr t, tinsert=NULL, tinsertnext;
980   int count;
981   Trptr prev;
982 
983   if(!GLOBALS->traces.buffer) return(NULL);
984 
985   GLOBALS->signalwindow_width_dirty=1;
986   GLOBALS->traces.dirty = 1;
987 
988   if(!(t=GLOBALS->traces.first))
989     {
990       t=GLOBALS->traces.last=GLOBALS->traces.first=GLOBALS->traces.buffer;
991       prev = NULL;
992       while(t)
993 	{
994           t->t_prev = prev; /* defensive re-link move */
995 	  prev = t;
996 	  GLOBALS->traces.last=t;
997 	  GLOBALS->traces.total++;
998 	  t=t->t_next;
999 	}
1000 
1001       GLOBALS->traces.buffer=GLOBALS->traces.bufferlast=NULL;
1002       GLOBALS->traces.buffercount=0;
1003 
1004       return(GLOBALS->traces.first);
1005     }
1006 
1007   while(t)
1008     {
1009       if(t->flags&TR_HIGHLIGHT)
1010 	{
1011 	  tinsert=t;
1012 	}
1013       t=t->t_next;
1014     }
1015 
1016 
1017   if(!tinsert) tinsert=GLOBALS->traces.last;
1018 
1019   if(IsGroupBegin(tinsert) && IsClosed(tinsert) && IsCollapsed(tinsert->t_match))
1020     tinsert=tinsert->t_match;
1021 
1022   tinsertnext=tinsert->t_next;
1023   tinsert->t_next=GLOBALS->traces.buffer;
1024   GLOBALS->traces.buffer->t_prev=tinsert;
1025   GLOBALS->traces.bufferlast->t_next=tinsertnext;
1026   GLOBALS->traces.total+=GLOBALS->traces.buffercount;
1027 
1028   if(!tinsertnext)
1029     {
1030       GLOBALS->traces.last=GLOBALS->traces.bufferlast;
1031     }
1032   else
1033     {
1034       tinsertnext->t_prev=GLOBALS->traces.bufferlast;
1035     }
1036 
1037   GLOBALS->traces.scroll_top = GLOBALS->traces.buffer;
1038   GLOBALS->traces.scroll_bottom = GLOBALS->traces.bufferlast;
1039 
1040   if(GLOBALS->traces.first)
1041     {
1042       t = GLOBALS->traces.first;
1043       t->t_grp = NULL;
1044       while(t)
1045 	{
1046 	  updateTraceGroup(t);
1047 	  t->flags &= ~TR_HIGHLIGHT;
1048 	  t=t->t_next;
1049 	}
1050     }
1051 
1052   count = 0;
1053 
1054   if (GLOBALS->traces.buffer)
1055     {
1056       t = GLOBALS->traces.buffer;
1057       while(t)
1058 	{
1059 	  t->flags |= TR_HIGHLIGHT;
1060 	  t=t->t_next;
1061 	  count++;
1062 	  if (count == GLOBALS->traces.buffercount) break;
1063 	}
1064     }
1065 
1066   /* clean out the buffer */
1067   GLOBALS->traces.buffer=GLOBALS->traces.bufferlast=NULL;
1068   GLOBALS->traces.buffercount=0;
1069 
1070   /* defensive re-link */
1071   t=GLOBALS->traces.first;
1072   prev = NULL;
1073   while(t)
1074 	{
1075         t->t_prev = prev;
1076 	prev = t;
1077 	t=t->t_next;
1078 	}
1079 
1080   return(GLOBALS->traces.first);
1081 }
1082 
1083 
1084 /*
1085  * Prepend the cut buffer into the main display one and
1086  * mark the cut buffer empty...
1087  */
PrependBuffer(void)1088 Trptr PrependBuffer(void)
1089 {
1090 Trptr t, prev = NULL;
1091 int count;
1092 
1093 if(!GLOBALS->traces.buffer) return(NULL);
1094 
1095 GLOBALS->signalwindow_width_dirty=1;
1096 GLOBALS->traces.dirty = 1;
1097 
1098 t=GLOBALS->traces.buffer;
1099 
1100 while(t)
1101 	{
1102 	t->t_prev = prev; /* defensive re-link move */
1103 	prev=t;
1104 	t->flags&=(~TR_HIGHLIGHT);
1105 	GLOBALS->traces.total++;
1106 	t=t->t_next;
1107 	}
1108 
1109 if((prev->t_next=GLOBALS->traces.first))
1110 	{
1111 	/* traces.last current value is ok as it stays the same */
1112 	GLOBALS->traces.first->t_prev=prev; /* but we need the reverse link back up */
1113 	}
1114 	else
1115 	{
1116 	GLOBALS->traces.last=prev;
1117 	}
1118 
1119 GLOBALS->traces.first=GLOBALS->traces.buffer;
1120 
1121 if(GLOBALS->traces.first)
1122   {
1123     t = GLOBALS->traces.first;
1124     t->t_grp = NULL;
1125     while(t)
1126       {
1127 	updateTraceGroup(t);
1128 	t->flags &= ~TR_HIGHLIGHT;
1129 	t=t->t_next;
1130       }
1131   }
1132 
1133  count = 0;
1134 
1135  if (GLOBALS->traces.buffer)
1136    {
1137      t = GLOBALS->traces.buffer;
1138      while(t)
1139        {
1140 	 t->flags |= TR_HIGHLIGHT;
1141 	 t=t->t_next;
1142 	 count++;
1143 	 if (count == GLOBALS->traces.buffercount) break;
1144       }
1145    }
1146 
1147 /* clean out the buffer */
1148 GLOBALS->traces.buffer=GLOBALS->traces.bufferlast=NULL;
1149 GLOBALS->traces.buffercount=0;
1150 
1151 /* defensive re-link */
1152 t=GLOBALS->traces.first;
1153 prev = NULL;
1154 while(t)
1155 	{
1156         t->t_prev = prev;
1157 	prev = t;
1158 	t=t->t_next;
1159 	}
1160 
1161 return(GLOBALS->traces.first);
1162 }
1163 
1164 
1165 /*
1166  * avoid sort/rvs manipulations if there are group traces (for now)
1167  */
groupsArePresent(void)1168 static int groupsArePresent(void)
1169 {
1170 Trptr t;
1171 int i, rc = 0;
1172 
1173 t=GLOBALS->traces.first;
1174 for(i=0;i<GLOBALS->traces.total;i++)
1175         {
1176         if(!t)
1177                 {
1178                 fprintf(stderr, "INTERNAL ERROR: traces.total vs traversal mismatch!  Exiting.\n");
1179                 exit(255);
1180                 }
1181 
1182 	if((t->t_grp)||(t->t_match)||(t->flags & TR_GRP_MASK))
1183 		{
1184 		rc = 1; break;
1185 		}
1186 
1187         t=t->t_next;
1188         }
1189 
1190 return(rc);
1191 }
1192 
1193 
1194 /*************************************************************/
1195 
1196 
1197 /*
1198  * sort on tracename pointers (alpha/caseins alpha/sig sort full_reverse)
1199  */
tracenamecompare(const void * s1,const void * s2)1200 static int tracenamecompare(const void *s1, const void *s2)
1201 {
1202 char *str1, *str2;
1203 
1204 str1=(*((Trptr *)s1))->name;
1205 str2=(*((Trptr *)s2))->name;
1206 
1207 if((!str1) || (!*str1))	/* force blank lines to go to bottom */
1208 	{
1209 	if((!str2) || (!*str2))
1210 		{
1211 		return(0);
1212 		}
1213 		else
1214 		{
1215 		return(1);
1216 		}
1217 	}
1218 else
1219 if((!str2) || (!*str2))
1220 	{
1221 	return(-1);		/* str1==str2==zero case is covered above */
1222 	}
1223 
1224 return(strcmp(str1, str2));
1225 }
1226 
1227 
traceinamecompare(const void * s1,const void * s2)1228 static int traceinamecompare(const void *s1, const void *s2)
1229 {
1230 char *str1, *str2;
1231 
1232 str1=(*((Trptr *)s1))->name;
1233 str2=(*((Trptr *)s2))->name;
1234 
1235 if((!str1) || (!*str1))	/* force blank lines to go to bottom */
1236 	{
1237 	if((!str2) || (!*str2))
1238 		{
1239 		return(0);
1240 		}
1241 		else
1242 		{
1243 		return(1);
1244 		}
1245 	}
1246 else
1247 if((!str2) || (!*str2))
1248 	{
1249 	return(-1);		/* str1==str2==zero case is covered above */
1250 	}
1251 
1252 return(strcasecmp(str1, str2));
1253 }
1254 
tracesignamecompare(const void * s1,const void * s2)1255 static int tracesignamecompare(const void *s1, const void *s2)
1256 {
1257 char *str1, *str2;
1258 
1259 str1=(*((Trptr *)s1))->name;
1260 str2=(*((Trptr *)s2))->name;
1261 
1262 if((!str1) || (!*str1))	/* force blank lines to go to bottom */
1263 	{
1264 	if((!str2) || (!*str2))
1265 		{
1266 		return(0);
1267 		}
1268 		else
1269 		{
1270 		return(1);
1271 		}
1272 	}
1273 else
1274 if((!str2) || (!*str2))
1275 	{
1276 	return(-1);		/* str1==str2==zero case is covered above */
1277 	}
1278 
1279 return(sigcmp(str1, str2));
1280 }
1281 
1282 
1283 /*
1284  * alphabetization/reordering of traces
1285  */
TracesReorder(int mode)1286 int TracesReorder(int mode)
1287 {
1288 Trptr t, prev = NULL;
1289 Trptr *tsort, *tsort_pnt;
1290 #ifdef WAVE_HIERFIX
1291 char *subst, ch;
1292 #endif
1293 int i;
1294 int (*cptr)(const void*, const void*);
1295 
1296 if(!GLOBALS->traces.total) return(0);
1297 GLOBALS->traces.dirty = 1;
1298 
1299 t=GLOBALS->traces.first;
1300 tsort=tsort_pnt=wave_alloca(sizeof(Trptr)*GLOBALS->traces.total);
1301 memset(tsort_pnt, 0, sizeof(Trptr)*GLOBALS->traces.total);
1302 
1303 for(i=0;i<GLOBALS->traces.total;i++)
1304         {
1305         if(!t)
1306                 {
1307                 fprintf(stderr, "INTERNAL ERROR: traces.total vs traversal mismatch!  Exiting.\n");
1308                 exit(255);
1309                 }
1310         *(tsort_pnt++)=t;
1311 
1312 #ifdef WAVE_HIERFIX
1313 	if((subst=t->name))
1314 	        while((ch=(*subst)))
1315         	        {
1316         	        if(ch==GLOBALS->hier_delimeter) { *subst=VCDNAM_HIERSORT; } /* forces sort at hier boundaries */
1317         	        subst++;
1318         	        }
1319 #endif
1320 
1321         t=t->t_next;
1322         }
1323 
1324 switch(mode)
1325 	{
1326 	case TR_SORT_INS:  	cptr=traceinamecompare;   break;
1327 	case TR_SORT_NORM: 	cptr=tracenamecompare;	  break;
1328 	case TR_SORT_LEX:  	cptr=tracesignamecompare; break;
1329 	default: 		cptr=NULL; break;
1330 	}
1331 
1332 if((cptr) && (!groupsArePresent()))
1333 	{
1334 	qsort(tsort, GLOBALS->traces.total, sizeof(Trptr), cptr);
1335 	}
1336 	else /* keep groups segregated off on the side and sort names + (indirect pointer to) top-level groups */
1337 	{
1338 	Trptr *tsort_reduced = wave_alloca(sizeof(Trptr)*GLOBALS->traces.total);
1339 	int num_reduced = 0;
1340 	int j;
1341 
1342 	memset(tsort_reduced, 0, sizeof(Trptr)*GLOBALS->traces.total);
1343 
1344 	for(i=0;i<GLOBALS->traces.total;i++)
1345 	        {
1346 	        if(tsort[i]->flags & TR_GRP_BEGIN)
1347 	                {
1348 	                int cnt = 0;
1349 
1350 	                for(j=i;j<GLOBALS->traces.total;j++)
1351 	                        {
1352 	                        if(tsort[j]->flags & TR_GRP_BEGIN) { cnt++; }
1353 	                        else if(tsort[j]->flags & TR_GRP_END) { cnt--; }
1354 
1355 	                        if(!cnt)
1356 	                                {
1357 	                                tsort_reduced[num_reduced] = calloc_2(1, sizeof(struct TraceEnt));
1358 	                                tsort_reduced[num_reduced]->name = tsort[i]->name;
1359 	                                tsort_reduced[num_reduced]->is_sort_group = 1;
1360 	                                tsort_reduced[num_reduced]->t_grp = tsort[i];
1361 
1362 	                                tsort[j]->t_next = NULL;
1363 	                                num_reduced++;
1364 
1365 	                                i = j; break;
1366 	                                }
1367 	                        }
1368 	                }
1369 	                else
1370 	                {
1371 	                tsort_reduced[num_reduced++] = tsort[i];
1372 	                }
1373 	        }
1374 
1375 	if(num_reduced)
1376 		{
1377 		if(mode == TR_SORT_RVS) /* reverse of current order */
1378 			{
1379 			for(i=0;i<=(num_reduced/2);i++)
1380 				{
1381 				Trptr t_tmp = tsort_reduced[i];
1382 
1383 				j = num_reduced-i-1;
1384 				tsort_reduced[i] = tsort_reduced[j];
1385 				tsort_reduced[j] = t_tmp;
1386 				}
1387 			}
1388 			else
1389 			{
1390 			if(cptr)
1391 				{
1392 				qsort(tsort_reduced, num_reduced, sizeof(Trptr), cptr);
1393 				}
1394 			}
1395 		}
1396 
1397 	i = 0;
1398 	for(j=0;j<num_reduced;j++)
1399 		{
1400 		if(!tsort_reduced[j]->is_sort_group)
1401 			{
1402 			tsort[i++] = tsort_reduced[j];
1403 			}
1404 			else
1405 			{
1406 			Trptr trav = tsort_reduced[j]->t_grp;
1407 			free_2(tsort_reduced[j]);
1408 			while(trav)
1409 				{
1410 				tsort[i++] = trav;
1411 				trav = trav->t_next;
1412 				}
1413 			}
1414 		}
1415 	}
1416 
1417 tsort_pnt=tsort;
1418 for(i=0;i<GLOBALS->traces.total;i++)
1419         {
1420         t=*(tsort_pnt++);
1421 
1422 	if(!i)
1423 		{
1424 		GLOBALS->traces.first=t;
1425 		t->t_prev=NULL;
1426 		}
1427 		else
1428 		{
1429 		prev->t_next=t;
1430 		t->t_prev=prev;
1431 		}
1432 
1433 	prev=t;
1434 
1435 #ifdef WAVE_HIERFIX
1436 	if((subst=t->name))
1437 	        while((ch=(*subst)))
1438         	        {
1439         	        if(ch==VCDNAM_HIERSORT) { *subst=GLOBALS->hier_delimeter; } /* restore hier */
1440         	        subst++;
1441         	        }
1442 #endif
1443         }
1444 
1445 GLOBALS->traces.last=prev;
1446 if(prev) { prev->t_next=NULL; } /* scan-build */
1447 
1448 return(1);
1449 }
1450 
1451 
GiveNextTrace(Trptr t)1452 Trptr GiveNextTrace(Trptr t)
1453 {
1454   if(!t) return(t); /* should not happen */
1455 
1456   /* if(t->name) { printf("NEXT: %s %x\n", t->name, t->flags); } */
1457   UpdateTraceSelection(t);
1458   if (IsGroupBegin(t) && IsClosed(t))
1459     {
1460       Trptr next = t->t_match;
1461       if (next)
1462 	return (IsCollapsed(next) ? GiveNextTrace(next) : next);
1463       return NULL;
1464     }
1465   else
1466     {
1467       Trptr next = t->t_next;
1468       if (next)
1469 	return (IsCollapsed(next) ? GiveNextTrace(next) : next);
1470       return NULL;
1471     }
1472 }
1473 
GivePrevTraceSkipUpdate(Trptr t,int skip)1474 static Trptr GivePrevTraceSkipUpdate(Trptr t, int skip)
1475 {
1476   if(!t) return(t); /* should not happen */
1477 
1478   /* if(t->name) { printf("PREV: %s\n", t->name); } */
1479   if(!skip) { UpdateTraceSelection(t); }
1480   if (IsGroupEnd(t) && IsClosed(t))
1481     {
1482       Trptr prev = t->t_match;
1483       if (prev)
1484 	return (IsCollapsed(prev) ? GivePrevTrace(prev) : prev);
1485       return NULL;
1486     }
1487   else
1488     {
1489       Trptr prev = t->t_prev;
1490       if (prev)
1491 	return (IsCollapsed(prev) ? GivePrevTrace(prev) : prev);
1492       return NULL;
1493     }
1494 }
1495 
GivePrevTrace(Trptr t)1496 Trptr GivePrevTrace(Trptr t)
1497 {
1498 return(GivePrevTraceSkipUpdate(t, 0));
1499 }
1500 
1501 
1502 /* propogate selection info down into groups */
UpdateTraceSelection(Trptr t)1503 void UpdateTraceSelection(Trptr t)
1504 {
1505   if ((t->t_match) && (IsGroupBegin(t) || IsGroupEnd(t)) && (IsSelected(t) || IsSelected(t->t_match)))
1506     {
1507       t->flags          |= TR_HIGHLIGHT;
1508       t->t_match->flags |= TR_HIGHLIGHT;
1509     }
1510   else
1511   if ((t->t_grp) && IsSelected(t->t_grp))
1512     {
1513       t->flags |= TR_HIGHLIGHT;
1514     }
1515   else
1516   if((t->flags & (TR_BLANK|TR_ANALOG_BLANK_STRETCH)) && (GLOBALS->num_ttrans_filters))  /* seek to real xact trace if present... */
1517         {
1518 	if(!(t->flags & TR_HIGHLIGHT))
1519 		{
1520 	        Trptr tscan = t;
1521 	        int bcnt = 0;
1522 	        while((tscan) && (tscan = tscan->t_prev)) /* && branch formerly was (tscan = GivePrevTraceSkipUpdate(tscan, 1)): overkill as blank traces in transactions don't nest into groups */
1523 	                {
1524 	                if(!(tscan->flags & (TR_BLANK|TR_ANALOG_BLANK_STRETCH)))
1525 	                        {
1526 	                        if(tscan->flags & TR_TTRANSLATED)
1527 	                                {
1528 	                                break; /* found it */
1529 	                                }
1530 	                                else
1531 	                                {
1532 	                                tscan = NULL;
1533 	                                }
1534 	                        }
1535 	                        else
1536 	                        {
1537 	                        bcnt++; /* bcnt is number of blank traces */
1538 	                        }
1539 	                }
1540 
1541 	        if((tscan)&&(tscan->vector)&&(IsSelected(tscan)))
1542 	                {
1543 	                bvptr bv = tscan->n.vec;
1544 	                do
1545 	                        {
1546 	                        bv = bv->transaction_chain; /* correlate to blank trace */
1547 	                        } while(bv && (bcnt--));
1548 	                if(bv)
1549 	                        {
1550 				t->flags |= TR_HIGHLIGHT;
1551 	                        }
1552 	                }
1553 		}
1554         }
1555 }
1556 
1557 
UpdateTracesVisible(void)1558 int UpdateTracesVisible(void)
1559 {
1560   Trptr t = GLOBALS->traces.first;
1561   int cnt = 0;
1562 
1563   while(t)
1564     {
1565       t = GiveNextTrace(t);
1566       cnt++;
1567     }
1568 
1569   GLOBALS->traces.visible = cnt;
1570   return(cnt);
1571 }
1572 
1573 /* where is trace t_in in the list of displayable traces */
GetTraceNumber(Trptr t_in)1574 int GetTraceNumber(Trptr t_in)
1575 {
1576   Trptr t = GLOBALS->traces.first;
1577   int i   = 0;
1578   int num = -1;
1579 
1580   while(t)
1581     {
1582       if (t == t_in)
1583 	{
1584 	  num = i;
1585 	  break;
1586 	}
1587       i++;
1588       t = GiveNextTrace(t);
1589     }
1590 
1591   return(num);
1592 }
1593 
IsShadowed(Trptr t)1594 unsigned IsShadowed( Trptr t )
1595 {
1596 
1597   if (t->t_grp)
1598     {
1599       if (HasWave(t->t_grp))
1600 	{
1601 	  return IsSelected(t->t_grp);
1602 	}
1603       else
1604 	{
1605 	  return IsShadowed(t->t_grp);
1606 	}
1607     }
1608 
1609   return 0;
1610 }
1611 
GetFullName(Trptr t,int * was_packed)1612 char* GetFullName( Trptr t, int *was_packed )
1613 {
1614   if (HasAlias(t) || !HasWave(t))
1615     {
1616       return (t->name_full);
1617     }
1618   else if (t->vector)
1619     {
1620       return (t->n.vec->bvname);
1621 
1622     }
1623   else
1624     {
1625       return (hier_decompress_flagged(t->n.nd->nname, was_packed));
1626     }
1627 }
1628 
1629 
1630 /*
1631  * sanity checking to make sure there are not any group open/close mismatches
1632  */
EnsureGroupsMatch(void)1633 void EnsureGroupsMatch(void)
1634 {
1635 Trptr t = GLOBALS->traces.first;
1636 Trptr last_good = t;
1637 Trptr t2;
1638 int oc_cnt = 0;
1639 int underflow_sticky = 0;
1640 /* Trptr tkill_undeflow = NULL; */ /* scan-build */
1641 
1642 while(t)
1643 	{
1644 	if(t->flags & TR_GRP_MASK)
1645 		{
1646 		if(t->flags & TR_GRP_BEGIN)
1647 			{
1648 			oc_cnt++;
1649 			}
1650 		else
1651 		if(t->flags & TR_GRP_END)
1652 			{
1653 			oc_cnt--;
1654 			if(oc_cnt == 0)
1655 				{
1656 				if(!underflow_sticky)
1657 					{
1658 					last_good = t->t_next;
1659 					}
1660 				}
1661 			}
1662 
1663 		if(oc_cnt < 0)
1664 			{
1665 			/*
1666 			if(!underflow_sticky)
1667 				{
1668 				tkill_undeflow = t;
1669 				}
1670 			*/ /* scan-build */
1671 			underflow_sticky = 1;
1672 			}
1673 		}
1674 		else
1675 		{
1676 		if((oc_cnt == 0) && (!underflow_sticky))
1677 			{
1678 			last_good = t->t_next;
1679 			}
1680 		}
1681 
1682 	t = t->t_next;
1683 	}
1684 
1685 if((underflow_sticky) || (oc_cnt > 0))
1686 	{
1687 	t = last_good;
1688 	while(t)
1689 		{
1690 		t2 = t->t_next;
1691 		RemoveTrace(t, 0); /* conservatively don't set "dofree", if there is a reload memory will reclaim */
1692 		t = t2;
1693 		}
1694 	}
1695 }
1696 
1697