1 /*
2 * Copyright (c) Tony Bybell 2012-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
11 #include "globals.h"
12 #include <config.h>
13 #include "savefile.h"
14 #include "hierpack.h"
15 #ifdef HAVE_SYS_STAT_H
16 #include <sys/stat.h>
17 #endif
18
19 #ifdef __linux__
20 #ifndef _XOPEN_SOURCE
21 char *strptime(const char *s, const char *format, struct tm *tm);
22 #endif
23 #endif
24
extract_dumpname_from_save_file(char * lcname,gboolean * modified,int * opt_vcd)25 char *extract_dumpname_from_save_file(char *lcname, gboolean *modified, int *opt_vcd)
26 {
27 char *dfn = NULL;
28 char *sfn = NULL;
29 char *rp = NULL;
30 FILE *f;
31 off_t dumpsiz = -1;
32 time_t dumptim = -1;
33
34 if ((suffix_check(lcname, ".sav")) || (suffix_check(lcname, ".gtkw")))
35 {
36 read_save_helper(lcname, &dfn, &sfn, &dumpsiz, &dumptim, opt_vcd);
37
38 #if defined __USE_BSD || defined __USE_XOPEN_EXTENDED || defined __CYGWIN__ || defined HAVE_REALPATH || defined __MINGW32__
39 if(sfn && dfn)
40 {
41 char *can = realpath_2(lcname, NULL);
42 char *fdf = find_dumpfile(sfn, dfn, can);
43
44 free(can);
45 f = fopen(fdf, "rb");
46 if(f)
47 {
48 rp = fdf;
49 fclose(f);
50 goto bot;
51 }
52 }
53 #endif
54
55 if(dfn)
56 {
57 f = fopen(dfn, "rb");
58 if(f)
59 {
60 fclose(f);
61 rp = strdup_2(dfn);
62 goto bot;
63 }
64 }
65 }
66
67 bot:
68 if(dfn) free_2(dfn);
69 if(sfn) free_2(sfn);
70
71 if(modified) *modified = 0;
72 #ifdef HAVE_SYS_STAT_H
73 if(modified && rp && (dumpsiz != -1) && (dumptim != -1))
74 {
75 struct stat sbuf;
76 if(!stat(rp, &sbuf))
77 {
78 *modified = (dumpsiz != sbuf.st_size) || (dumptim != sbuf.st_mtime);
79 }
80 }
81 #endif
82
83 return(rp);
84 }
85
86
append_array_row(nptr n)87 char *append_array_row(nptr n)
88 {
89 int was_packed = HIER_DEPACK_ALLOC;
90 char *hname = hier_decompress_flagged(n->nname, &was_packed);
91
92 #ifdef WAVE_ARRAY_SUPPORT
93 if(!n->array_height)
94 #endif
95 {
96 strcpy(GLOBALS->buf_menu_c_1, hname);
97 }
98 #ifdef WAVE_ARRAY_SUPPORT
99 else
100 {
101 sprintf(GLOBALS->buf_menu_c_1, "%s{%d}", hname, n->this_row);
102 }
103 #endif
104
105 if(was_packed) free_2(hname);
106
107 return(GLOBALS->buf_menu_c_1);
108 }
109
110
write_save_helper(const char * savnam,FILE * wave)111 void write_save_helper(const char *savnam, FILE *wave) {
112 Trptr t;
113 int i;
114 TraceFlagsType def=0;
115 int sz_x, sz_y;
116 TimeType prevshift=LLDescriptor(0);
117 int root_x, root_y;
118 struct strace *st;
119 int s_ctx_iter;
120 time_t walltime;
121
122 DEBUG(printf("Write Save Fini: %s\n", savnam));
123
124 GLOBALS->dumpfile_is_modified = 0; /* writing a save file removes modification */
125 wave_gtk_window_set_title(GTK_WINDOW(GLOBALS->mainwindow), GLOBALS->winname, GLOBALS->dumpfile_is_modified ? WAVE_SET_TITLE_MODIFIED: WAVE_SET_TITLE_NONE, 0);
126
127 time(&walltime);
128 fprintf(wave, "[*]\n");
129 fprintf(wave, "[*] "WAVE_VERSION_INFO"\n");
130 fprintf(wave, "[*] %s",asctime(gmtime(&walltime)));
131 fprintf(wave, "[*]\n");
132
133 if(GLOBALS->loaded_file_name)
134 {
135 if((GLOBALS->loaded_file_type == MISSING_FILE)||(GLOBALS->is_optimized_stdin_vcd))
136 {
137 /* don't emit dumpfile tag */
138 }
139 else
140 {
141 #ifdef HAVE_SYS_STAT_H
142 struct stat sbuf;
143 #endif
144 char *unopt = GLOBALS->unoptimized_vcd_file_name ? GLOBALS->unoptimized_vcd_file_name: GLOBALS->loaded_file_name;
145 #if defined __USE_BSD || defined __USE_XOPEN_EXTENDED || defined __CYGWIN__ || defined HAVE_REALPATH || defined __MINGW32__
146 char *can = realpath_2(GLOBALS->optimize_vcd ? unopt : GLOBALS->loaded_file_name, NULL);
147 const char *cansav = realpath_2(savnam, NULL);
148 const int do_free = 1;
149 #else
150 char *can = GLOBALS->optimize_vcd ? unopt : GLOBALS->loaded_file_name;
151 const char *cansav = savnam;
152 const int do_free = 0;
153 #endif
154 fprintf(wave, "[dumpfile] \"%s\"\n", can);
155 #ifdef HAVE_SYS_STAT_H
156 if(!stat(can, &sbuf))
157 {
158 char *asct = asctime(gmtime(&sbuf.st_mtime));
159 if(asct)
160 {
161 char *asct2 = strdup_2(asct);
162 char *nl = strchr(asct2, '\n');
163 if(nl) *nl = 0;
164 fprintf(wave, "[dumpfile_mtime] \"%s\"\n", asct2);
165 free_2(asct2);
166 fprintf(wave, "[dumpfile_size] %"PRIu64"\n", sbuf.st_size);
167 }
168 }
169 #endif
170 if(GLOBALS->optimize_vcd && GLOBALS->unoptimized_vcd_file_name) { fprintf(wave, "[optimize_vcd]\n"); }
171 fprintf(wave, "[savefile] \"%s\"\n", cansav); /* emit also in order to do relative path matching in future... */
172 if(do_free)
173 {
174 free(can);
175 }
176 }
177 }
178
179 fprintf(wave, "[timestart] "TTFormat"\n", GLOBALS->tims.start);
180
181 get_window_size (&sz_x, &sz_y);
182 if(!GLOBALS->ignore_savefile_size) fprintf(wave,"[size] %d %d\n", sz_x, sz_y);
183
184 get_window_xypos(&root_x, &root_y);
185
186 if(!GLOBALS->ignore_savefile_pos) fprintf(wave,"[pos] %d %d\n", root_x + GLOBALS->xpos_delta, root_y + GLOBALS->ypos_delta);
187
188 fprintf(wave,"*%f "TTFormat, (float)(GLOBALS->tims.zoom),GLOBALS->tims.marker);
189
190 for(i=0;i<WAVE_NUM_NAMED_MARKERS;i++)
191 {
192 TimeType nm = GLOBALS->named_markers[i]; /* gcc compiler problem...thinks this is a 'long int' in printf format warning reporting */
193 fprintf(wave," "TTFormat,nm);
194 }
195 fprintf(wave,"\n");
196
197 for(i=0;i<WAVE_NUM_NAMED_MARKERS;i++)
198 {
199 if(GLOBALS->marker_names[i])
200 {
201 char mbuf[16];
202
203 make_bijective_marker_id_string(mbuf, i);
204 if(strlen(mbuf)<2)
205 {
206 fprintf(wave, "[markername] %s%s\n", mbuf, GLOBALS->marker_names[i]);
207 }
208 else
209 {
210 fprintf(wave, "[markername_long] %s %s\n", mbuf, GLOBALS->marker_names[i]);
211 }
212 }
213 }
214
215 if(GLOBALS->ruler_step)
216 {
217 fprintf(wave, "[ruler] "TTFormat" "TTFormat"\n", GLOBALS->ruler_origin, GLOBALS->ruler_step);
218 }
219
220 #if WAVE_USE_GTK2
221 if(GLOBALS->open_tree_nodes)
222 {
223 dump_open_tree_nodes(wave, GLOBALS->open_tree_nodes);
224 }
225 #endif
226
227 #if GTK_CHECK_VERSION(2,4,0)
228 if(!GLOBALS->ignore_savefile_pane_pos)
229 {
230 if(GLOBALS->toppanedwindow)
231 {
232 fprintf(wave, "[sst_width] %d\n", gtk_paned_get_position(GTK_PANED(GLOBALS->toppanedwindow)));
233 }
234 if(GLOBALS->panedwindow)
235 {
236 fprintf(wave, "[signals_width] %d\n", gtk_paned_get_position(GTK_PANED(GLOBALS->panedwindow)));
237 }
238 if(GLOBALS->expanderwindow)
239 {
240 GLOBALS->sst_expanded = gtk_expander_get_expanded(GTK_EXPANDER(GLOBALS->expanderwindow));
241 fprintf(wave, "[sst_expanded] %d\n", GLOBALS->sst_expanded);
242 }
243 if(GLOBALS->sst_vpaned)
244 {
245 fprintf(wave, "[sst_vpaned_height] %d\n", gtk_paned_get_position(GTK_PANED(GLOBALS->sst_vpaned)));
246 }
247 }
248 #endif
249
250 t=GLOBALS->traces.first;
251 while(t)
252 {
253 if((t->flags!=def)||(t==GLOBALS->traces.first))
254 {
255 if((t->flags & TR_PTRANSLATED) && (!t->p_filter)) t->flags &= (~TR_PTRANSLATED);
256 if((t->flags & TR_FTRANSLATED) && (!t->f_filter)) t->flags &= (~TR_FTRANSLATED);
257 if((t->flags & TR_TTRANSLATED) && (!t->t_filter)) t->flags &= (~TR_TTRANSLATED);
258 fprintf(wave,"@%"TRACEFLAGSPRIFMT"\n",def=t->flags);
259 }
260
261 if((t->shift)||((prevshift)&&(!t->shift)))
262 {
263 fprintf(wave,">"TTFormat"\n", t->shift);
264 }
265 prevshift=t->shift;
266
267 if(!(t->flags&(TR_BLANK|TR_ANALOG_BLANK_STRETCH)))
268 {
269 if(t->t_color)
270 {
271 fprintf(wave, "[color] %d\n", t->t_color);
272 }
273 if(t->flags & TR_FPDECSHIFT)
274 {
275 fprintf(wave, "[fpshift_count] %d\n", t->t_fpdecshift);
276 }
277
278 if(t->flags & TR_FTRANSLATED)
279 {
280 if(t->f_filter && GLOBALS->filesel_filter[t->f_filter])
281 {
282 #if defined __USE_BSD || defined __USE_XOPEN_EXTENDED || defined __CYGWIN__ || defined HAVE_REALPATH || defined __MINGW32__
283 char *can = realpath_2(GLOBALS->filesel_filter[t->f_filter], NULL);
284 fprintf(wave, "^%d %s\n", t->f_filter, can);
285 free(can);
286 #else
287 fprintf(wave, "^%d %s\n", t->f_filter, GLOBALS->filesel_filter[t->f_filter]);
288 #endif
289 }
290 else
291 {
292 fprintf(wave, "^%d %s\n", 0, "disabled");
293 }
294 }
295 else
296 if(t->flags & TR_PTRANSLATED)
297 {
298 if(t->p_filter && GLOBALS->procsel_filter[t->p_filter])
299 {
300 #if defined __USE_BSD || defined __USE_XOPEN_EXTENDED || defined __CYGWIN__ || defined HAVE_REALPATH || defined __MINGW32__
301 char *can = realpath_2(GLOBALS->procsel_filter[t->p_filter], NULL);
302 fprintf(wave, "^>%d %s\n", t->p_filter, can);
303 free(can);
304 #else
305 fprintf(wave, "^>%d %s\n", t->p_filter, GLOBALS->procsel_filter[t->p_filter]);
306 #endif
307 }
308 else
309 {
310 fprintf(wave, "^>%d %s\n", 0, "disabled");
311 }
312 }
313
314 /* NOT an else! */
315 if(t->flags & TR_TTRANSLATED)
316 {
317 if(t->transaction_args)
318 {
319 fprintf(wave, "[transaction_args] \"%s\"\n", t->transaction_args);
320 }
321 else
322 {
323 fprintf(wave, "[transaction_args] \"%s\"\n", "");
324 }
325
326 if(t->t_filter && GLOBALS->ttranssel_filter[t->t_filter])
327 {
328 #if defined __USE_BSD || defined __USE_XOPEN_EXTENDED || defined __CYGWIN__ || defined HAVE_REALPATH || defined __MINGW32__
329 char *can = realpath_2(GLOBALS->ttranssel_filter[t->t_filter], NULL);
330 fprintf(wave, "^<%d %s\n", t->t_filter, can);
331 free(can);
332 #else
333 fprintf(wave, "^<%d %s\n", t->t_filter, GLOBALS->ttranssel_filter[t->t_filter]);
334 #endif
335 }
336 else
337 {
338 fprintf(wave, "^<%d %s\n", 0, "disabled");
339 }
340 }
341
342 if(t->vector && !(t->n.vec->transaction_cache && t->n.vec->transaction_cache->transaction_nd))
343 {
344 int ix;
345 nptr *nodes;
346 bptr bits;
347 baptr ba;
348
349 if (HasAlias(t)) { fprintf(wave,"+{%s} ", t->name_full); }
350 bits = t->n.vec->bits;
351 ba = bits ? bits->attribs : NULL;
352
353 fprintf(wave,"%c{%s}", ba ? ':' : '#',
354 t->n.vec->transaction_cache ? t->n.vec->transaction_cache->bvname : t->n.vec->bvname);
355
356 nodes=t->n.vec->bits->nodes;
357 for(ix=0;ix<t->n.vec->bits->nnbits;ix++)
358 {
359 if(nodes[ix]->expansion)
360 {
361 fprintf(wave," (%d)%s",nodes[ix]->expansion->parentbit, append_array_row(nodes[ix]->expansion->parent));
362 }
363 else
364 {
365 fprintf(wave," %s",append_array_row(nodes[ix]));
366 }
367 if(ba)
368 {
369 fprintf(wave, " "TTFormat" %"TRACEFLAGSPRIFMT, ba[ix].shift, ba[ix].flags);
370 }
371 }
372 fprintf(wave,"\n");
373 }
374 else
375 {
376 nptr nd = (t->vector && t->n.vec->transaction_cache && t->n.vec->transaction_cache->transaction_nd) ?
377 t->n.vec->transaction_cache->transaction_nd : t->n.nd;
378
379 if(HasAlias(t))
380 {
381 if(nd->expansion)
382 {
383 fprintf(wave,"+{%s} (%d)%s\n",t->name_full,nd->expansion->parentbit, append_array_row(nd->expansion->parent));
384 }
385 else
386 {
387 fprintf(wave,"+{%s} %s\n",t->name_full,append_array_row(nd));
388 }
389 }
390 else
391 {
392 if(nd->expansion)
393 {
394 fprintf(wave,"(%d)%s\n",nd->expansion->parentbit, append_array_row(nd->expansion->parent));
395 }
396 else
397 {
398 fprintf(wave,"%s\n",append_array_row(nd));
399 }
400 }
401 }
402 }
403 else
404 {
405 if(!t->name) fprintf(wave,"-\n");
406 else fprintf(wave,"-%s\n",t->name);
407 }
408 t=t->t_next;
409 }
410
411 WAVE_STRACE_ITERATOR(s_ctx_iter)
412 {
413 GLOBALS->strace_ctx = &GLOBALS->strace_windows[GLOBALS->strace_current_window = s_ctx_iter];
414 fprintf(wave, "[pattern_trace] %d\n", s_ctx_iter);
415
416 if(GLOBALS->strace_ctx->timearray)
417 {
418 if(GLOBALS->strace_ctx->shadow_straces)
419 {
420 swap_strace_contexts();
421
422 st=GLOBALS->strace_ctx->straces;
423 if(GLOBALS->strace_ctx->straces)
424 {
425 fprintf(wave, "!%d%d%d%d%d%d%c%c\n", GLOBALS->strace_ctx->logical_mutex[0], GLOBALS->strace_ctx->logical_mutex[1], GLOBALS->strace_ctx->logical_mutex[2], GLOBALS->strace_ctx->logical_mutex[3], GLOBALS->strace_ctx->logical_mutex[4], GLOBALS->strace_ctx->logical_mutex[5], '@'+GLOBALS->strace_ctx->mark_idx_start, '@'+GLOBALS->strace_ctx->mark_idx_end);
426 }
427
428 while(st)
429 {
430 if(st->value==ST_STRING)
431 {
432 fprintf(wave, "?\"%s\n", st->string ? st->string : ""); /* search type for this trace is string.. */
433 }
434 else
435 {
436 fprintf(wave, "?%02x\n", (unsigned char)st->value); /* else search type for this trace.. */
437 }
438
439 t=st->trace;
440
441 if(t->flags!=def)
442 {
443 if((t->flags & TR_FTRANSLATED) && (!t->f_filter)) t->flags &= (~TR_FTRANSLATED);
444 if((t->flags & TR_PTRANSLATED) && (!t->p_filter)) t->flags &= (~TR_PTRANSLATED);
445 if((t->flags & TR_TTRANSLATED) && (!t->t_filter)) t->flags &= (~TR_TTRANSLATED);
446 fprintf(wave,"@%"TRACEFLAGSPRIFMT"\n",def=t->flags);
447 }
448
449 if((t->shift)||((prevshift)&&(!t->shift)))
450 {
451 fprintf(wave,">"TTFormat"\n", t->shift);
452 }
453 prevshift=t->shift;
454
455 if(!(t->flags&(TR_BLANK|TR_ANALOG_BLANK_STRETCH)))
456 {
457 if(t->flags & TR_FTRANSLATED)
458 {
459 if(t->f_filter && GLOBALS->filesel_filter[t->f_filter])
460 {
461 fprintf(wave, "^%d %s\n", t->f_filter, GLOBALS->filesel_filter[t->f_filter]);
462 }
463 else
464 {
465 fprintf(wave, "^%d %s\n", 0, "disabled");
466 }
467 }
468 else
469 if(t->flags & TR_PTRANSLATED)
470 {
471 if(t->p_filter && GLOBALS->procsel_filter[t->p_filter])
472 {
473 fprintf(wave, "^>%d %s\n", t->p_filter, GLOBALS->procsel_filter[t->p_filter]);
474 }
475 else
476 {
477 fprintf(wave, "^>%d %s\n", 0, "disabled");
478 }
479 }
480
481 /* NOT an else! */
482 if(t->flags & TR_TTRANSLATED)
483 {
484 if(t->transaction_args)
485 {
486 fprintf(wave, "[transaction_args] \"%s\"\n", t->transaction_args);
487 }
488 else
489 {
490 fprintf(wave, "[transaction_args] \"%s\"\n", "");
491 }
492
493 if(t->t_filter && GLOBALS->ttranssel_filter[t->t_filter])
494 {
495 #if defined __USE_BSD || defined __USE_XOPEN_EXTENDED || defined __CYGWIN__ || defined HAVE_REALPATH || defined __MINGW32__
496 char *can = realpath_2(GLOBALS->ttranssel_filter[t->t_filter], NULL);
497 fprintf(wave, "^<%d %s\n", t->t_filter, can);
498 free(can);
499 #else
500 fprintf(wave, "^<%d %s\n", t->t_filter, GLOBALS->ttranssel_filter[t->t_filter]);
501 #endif
502 }
503 else
504 {
505 fprintf(wave, "^<%d %s\n", 0, "disabled");
506 }
507 }
508
509
510 if(t->vector && !(t->n.vec->transaction_cache && t->n.vec->transaction_cache->transaction_nd))
511 {
512 int ix;
513 nptr *nodes;
514 bptr bits;
515 baptr ba;
516
517 if (HasAlias(t)) { fprintf(wave,"+{%s} ", t->name_full); }
518
519 bits = t->n.vec->bits;
520 ba = bits ? bits->attribs : NULL;
521
522 fprintf(wave,"%c{%s}", ba ? ':' : '#',
523 t->n.vec->transaction_cache ? t->n.vec->transaction_cache->bvname : t->n.vec->bvname);
524
525 nodes=t->n.vec->bits->nodes;
526 for(ix=0;ix<t->n.vec->bits->nnbits;ix++)
527 {
528 if(nodes[ix]->expansion)
529 {
530 fprintf(wave," (%d)%s",nodes[ix]->expansion->parentbit, append_array_row(nodes[ix]->expansion->parent));
531 }
532 else
533 {
534 fprintf(wave," %s",append_array_row(nodes[ix]));
535 }
536 if(ba)
537 {
538 fprintf(wave, " "TTFormat" %"TRACEFLAGSPRIFMT, ba[ix].shift, ba[ix].flags);
539 }
540 }
541 fprintf(wave,"\n");
542 }
543 else
544 {
545 nptr nd = (t->vector && t->n.vec->transaction_cache && t->n.vec->transaction_cache->transaction_nd) ?
546 t->n.vec->transaction_cache->transaction_nd : t->n.nd;
547
548 if(HasAlias(t))
549 {
550 if(nd->expansion)
551 {
552 fprintf(wave,"+{%s} (%d)%s\n",t->name_full,nd->expansion->parentbit, append_array_row(nd->expansion->parent));
553 }
554 else
555 {
556 fprintf(wave,"+{%s} %s\n",t->name_full,append_array_row(nd));
557 }
558 }
559 else
560 {
561 if(nd->expansion)
562 {
563 fprintf(wave,"(%d)%s\n",nd->expansion->parentbit, append_array_row(nd->expansion->parent));
564 }
565 else
566 {
567 fprintf(wave,"%s\n",append_array_row(nd));
568 }
569 }
570 }
571 }
572
573 st=st->next;
574 } /* while(st)... */
575
576 if(GLOBALS->strace_ctx->straces)
577 {
578 fprintf(wave, "!!\n"); /* mark end of strace region */
579 }
580
581 swap_strace_contexts();
582 }
583 else
584 {
585 struct mprintf_buff_t *mt = GLOBALS->strace_ctx->mprintf_buff_head;
586
587 while(mt)
588 {
589 fprintf(wave, "%s", mt->str);
590 mt=mt->next;
591 }
592 }
593
594 } /* if(timearray)... */
595 }
596 }
597
598
read_save_helper_relative_init(char * wname)599 void read_save_helper_relative_init(char *wname)
600 {
601 /* for relative files in parsewavline() */
602 if(GLOBALS->lcname)
603 {
604 free_2(GLOBALS->lcname);
605 }
606
607 GLOBALS->lcname = wname ? strdup_2(wname) : NULL;
608
609 if(GLOBALS->sfn)
610 {
611 free_2(GLOBALS->sfn);
612 GLOBALS->sfn = NULL;
613 }
614 }
615
616
get_relative_adjusted_name(char * sfn,char * dfn,char * lcname)617 char *get_relative_adjusted_name(char *sfn, char *dfn, char *lcname)
618 {
619 char *rp = NULL;
620 FILE *f;
621
622 #if defined __USE_BSD || defined __USE_XOPEN_EXTENDED || defined __CYGWIN__ || defined HAVE_REALPATH
623 if(sfn && dfn)
624 {
625 char *can = realpath_2(lcname, NULL);
626 char *fdf = find_dumpfile(sfn, dfn, can);
627
628 free(can);
629
630 if(fdf)
631 {
632 f = fopen(fdf, "rb");
633 if(f)
634 {
635 rp = fdf;
636 fclose(f);
637 goto bot;
638 }
639 }
640 }
641 #endif
642
643 if(dfn)
644 {
645 f = fopen(dfn, "rb");
646 if(f)
647 {
648 fclose(f);
649 rp = strdup_2(dfn);
650 goto bot;
651 }
652 }
653
654 bot:
655 return(rp);
656 }
657
658
read_save_helper(char * wname,char ** dumpfile,char ** savefile,off_t * dumpsiz,time_t * dumptim,int * opt_vcd)659 int read_save_helper(char *wname, char **dumpfile, char **savefile, off_t *dumpsiz, time_t *dumptim, int *opt_vcd) {
660 FILE *wave;
661 char *str = NULL;
662 int wave_is_compressed;
663 char traces_already_exist = (GLOBALS->traces.first != NULL);
664 int rc = -1;
665 int extract_dumpfile_savefile_only = (dumpfile != NULL) && (savefile != NULL);
666
667 GLOBALS->is_gtkw_save_file = suffix_check(wname, ".gtkw") || suffix_check(wname, ".gtkw.gz") || suffix_check(wname, ".gtkw.zip");
668
669 if(suffix_check(wname, ".gz") || suffix_check(wname, ".zip"))
670 {
671 str=wave_alloca(strlen(wname)+5+1);
672 strcpy(str,"zcat ");
673 strcpy(str+5,wname);
674 wave=popen(str,"r");
675 wave_is_compressed=~0;
676 }
677 else
678 {
679 wave=fopen(wname,"rb");
680 wave_is_compressed=0;
681 }
682
683
684 if(!wave)
685 {
686 fprintf(stderr, "Error opening save file '%s' for reading.\n", wname);
687 perror("Why");
688 errno=0;
689 }
690 else
691 {
692 char *iline;
693 int s_ctx_iter;
694
695 if(extract_dumpfile_savefile_only)
696 {
697 while((iline=fgetmalloc(wave)))
698 {
699 if(!strncmp(iline, "[dumpfile]", 10))
700 {
701 char *lhq = strchr(iline+10, '"');
702 char *rhq = strrchr(iline+10, '"');
703 if((lhq) && (rhq) && (lhq != rhq)) /* no real need to check rhq != NULL*/
704 {
705 *rhq = 0;
706 if(*dumpfile) free_2(*dumpfile);
707 *dumpfile = strdup_2(lhq + 1);
708 }
709 }
710 else
711 if(!strncmp(iline, "[dumpfile_mtime]", 16))
712 {
713 if(dumptim)
714 {
715 struct tm tm;
716 time_t t;
717 char *lhq = strchr(iline+16, '"');
718 char *rhq = strrchr(iline+16, '"');
719 memset(&tm, 0, sizeof(struct tm));
720
721 *dumptim = -1;
722 #if !defined _MSC_VER && !defined __MINGW32__
723 /* format is: "Fri Feb 4 15:50:48 2011" */
724 if(lhq && rhq && (lhq != rhq))
725 {
726 int slen;
727 char *strp_buf;
728
729 *rhq = 0;
730 slen = strlen(lhq+1);
731 strp_buf = calloc_2(1, slen + 32); /* workaround: linux strptime seems to overshoot its buffer */
732 strcpy(strp_buf, lhq+1);
733
734 if(strptime(strp_buf, "%a %b %d %H:%M:%S %Y", &tm) != NULL)
735 {
736 t = timegm(&tm);
737 if(t != -1)
738 {
739 *dumptim = t;
740 }
741 }
742
743 free_2(strp_buf);
744 }
745 #endif
746 }
747 }
748 else
749 if(!strncmp(iline, "[dumpfile_size]", 15))
750 {
751 if(dumpsiz)
752 {
753 *dumpsiz = atoi_64(iline+15);
754 }
755 }
756 else
757 if(!strncmp(iline, "[savefile]", 10))
758 {
759 char *lhq = strchr(iline+10, '"');
760 char *rhq = strrchr(iline+10, '"');
761 if((lhq) && (rhq) && (lhq != rhq)) /* no real need to check rhq != NULL*/
762 {
763 *rhq = 0;
764 if(*savefile) free_2(*savefile);
765 *savefile = strdup_2(lhq + 1);
766 }
767 }
768 else
769 if(!strncmp(iline, "[optimize_vcd]", 14))
770 {
771 if(opt_vcd) { *opt_vcd = 1; }
772 }
773
774 free_2(iline);
775 rc++;
776 }
777
778 if(wave_is_compressed) pclose(wave); else fclose(wave);
779 return(rc);
780 }
781
782
783 read_save_helper_relative_init(wname);
784
785
786 WAVE_STRACE_ITERATOR(s_ctx_iter)
787 {
788 GLOBALS->strace_ctx = &GLOBALS->strace_windows[GLOBALS->strace_current_window = s_ctx_iter];
789 GLOBALS->strace_ctx->shadow_encountered_parsewavline = 0;
790 }
791
792 if(GLOBALS->traces.total)
793 {
794 GLOBALS->group_depth=0;
795 /* AddBlankTrace(NULL); in order to terminate any possible collapsed groups */
796 }
797
798 if(GLOBALS->is_lx2)
799 {
800 while((iline=fgetmalloc(wave)))
801 {
802 parsewavline_lx2(iline, NULL, 0);
803 free_2(iline);
804 }
805
806 lx2_import_masked();
807
808 if(wave_is_compressed)
809 {
810 pclose(wave);
811 wave=popen(str,"r");
812 }
813 else
814 {
815 fclose(wave);
816 wave=fopen(wname,"rb");
817 }
818
819 if(!wave)
820 {
821 fprintf(stderr, "Error opening save file '%s' for reading.\n", wname);
822 perror("Why");
823 errno=0;
824 return(rc);
825 }
826 }
827
828 GLOBALS->default_flags=TR_RJUSTIFY;
829 GLOBALS->default_fpshift=0;
830 GLOBALS->shift_timebase_default_for_add=LLDescriptor(0);
831 GLOBALS->strace_current_window = 0; /* in case there are shadow traces */
832
833 rc = 0;
834 GLOBALS->which_t_color = 0;
835 while((iline=fgetmalloc(wave)))
836 {
837 parsewavline(iline, NULL, 0);
838 GLOBALS->strace_ctx->shadow_encountered_parsewavline |= GLOBALS->strace_ctx->shadow_active;
839 free_2(iline);
840 rc++;
841 }
842 GLOBALS->which_t_color = 0;
843
844 WAVE_STRACE_ITERATOR(s_ctx_iter)
845 {
846 GLOBALS->strace_ctx = &GLOBALS->strace_windows[GLOBALS->strace_current_window = s_ctx_iter];
847
848 if(GLOBALS->strace_ctx->shadow_encountered_parsewavline)
849 {
850 GLOBALS->strace_ctx->shadow_encountered_parsewavline = 0;
851
852 if(GLOBALS->strace_ctx->shadow_straces)
853 {
854 GLOBALS->strace_ctx->shadow_active = 1;
855
856 swap_strace_contexts();
857 strace_maketimetrace(1);
858 swap_strace_contexts();
859
860 GLOBALS->strace_ctx->shadow_active = 0;
861 }
862 }
863 }
864
865 GLOBALS->default_flags=TR_RJUSTIFY;
866 GLOBALS->default_fpshift=0;
867 GLOBALS->shift_timebase_default_for_add=LLDescriptor(0);
868 update_markertime(GLOBALS->tims.marker);
869 if(wave_is_compressed) pclose(wave); else fclose(wave);
870
871 if(traces_already_exist) GLOBALS->timestart_from_savefile_valid = 0;
872
873 EnsureGroupsMatch();
874
875 GLOBALS->signalwindow_width_dirty=1;
876 MaxSignalLength();
877 signalarea_configure_event(GLOBALS->signalarea, NULL);
878 wavearea_configure_event(GLOBALS->wavearea, NULL);
879
880 #ifdef MAC_INTEGRATION
881 if(GLOBALS->num_notebook_pages > 1)
882 #endif
883 {
884 if(!GLOBALS->block_xy_update)
885 {
886 int x, y;
887
888 get_window_size(&x, &y);
889 set_window_size(x, y);
890 }
891 }
892 }
893
894 GLOBALS->current_translate_file = 0;
895
896 return(rc);
897 }
898
899 /******************************************************************/
900
901 /*
902 * attempt to synthesize bitwise on loader fail...caller must free return pnt
903 */
synth_blastvec(char * w)904 static char *synth_blastvec(char *w)
905 {
906 char *mem = NULL;
907 char *t;
908 char *lbrack, *colon, *rbrack, *rname, *msbs, *lsbs;
909 int wlen, bitlen, msb, lsb;
910 int msbslen, lsbslen, maxnumlen;
911 int i, siz;
912
913 if(w)
914 {
915 if((lbrack = strrchr(w, '[')))
916 if((colon = strchr(lbrack+1, ':')))
917 if((rbrack = strchr(colon+1, ']')))
918 {
919 *lbrack = *colon = *rbrack = 0;
920 msbs = lbrack + 1;
921 lsbs = colon + 1;
922 rname = hier_extract(w, GLOBALS->hier_max_level);
923
924 msb = atoi(msbs);
925 lsb = atoi(lsbs);
926 bitlen = (msb > lsb) ? (msb - lsb + 1) : (lsb - msb + 1);
927 if(bitlen > 1)
928 {
929 wlen = strlen(w);
930
931 msbslen = strlen(msbs);
932 lsbslen = strlen(lsbs);
933 maxnumlen = (msbslen > lsbslen) ? msbslen : lsbslen;
934
935 siz = 1 + /* # */
936 strlen(rname) + /* vector alias name */
937 1+ /* */
938 1+ /* [ */
939 msbslen+ /* msb */
940 1+ /* : */
941 lsbslen+ /* lsb */
942 1+ /* ] */
943 1; /* */
944
945 siz += bitlen * (
946 wlen + /* full bitname */
947 1+ /* [ */
948 maxnumlen+ /* individual bit */
949 1+ /* ] */
950 1 /* */
951 );
952
953 mem = calloc_2(1, siz);
954 t = mem + sprintf(mem, "#%s[%d:%d] ", rname, msb, lsb);
955
956 if(msb > lsb)
957 {
958 for(i = msb; i >= lsb; i--)
959 {
960 t += sprintf(t, "%s[%d]", w, i);
961 if(i!=lsb) t += sprintf(t, " ");
962 }
963 }
964 else
965 {
966 for(i = msb; i <= lsb; i++)
967 {
968 t += sprintf(t, "%s[%d]", w, i);
969 if(i!=lsb) t += sprintf(t, " ");
970 }
971 }
972
973 /* fprintf(stderr, "%d,%d: %s\n", siz, strlen(mem), mem); */
974 }
975
976 }
977 }
978
979 return(mem);
980 }
981
982 /******************************************************************/
983
984 /*
985 * Parse a line of the wave file and act accordingly..
986 * Returns nonzero if trace(s) added.
987 */
parsewavline(char * w,char * alias,int depth)988 int parsewavline(char *w, char *alias, int depth)
989 {
990 int i;
991 int len;
992 char *w2;
993 nptr nexp;
994 unsigned int rows = 0;
995 char *prefix, *suffix, *new;
996 char *prefix_init, *w2_init;
997 unsigned int mode;
998 int current_grp_depth = -1;
999
1000 if(!(len=strlen(w))) return(0);
1001 if(*(w+len-1)=='\n')
1002 {
1003 *(w+len-1)=0x00; /* strip newline if present */
1004 len--;
1005 if(!len) return(0);
1006 }
1007
1008 while(1)
1009 {
1010 if(isspace((int)(unsigned char)*w)) { w++; continue; }
1011 if(!(*w)) return(0); /* no args */
1012 break; /* start grabbing chars from here */
1013 }
1014
1015 w2=w;
1016
1017 /* sscanf(w2,"%s",prefix); */
1018
1019 prefix=(char *)wave_alloca(len+1);
1020 suffix=(char *)wave_alloca(len+1);
1021 new=(char *)wave_alloca(len+1);
1022 memset(new, 0, len+1); /* scan-build */
1023
1024 prefix_init = prefix;
1025 w2_init = new;
1026 mode = 0; /* 0 = before "{", 1 = after "{", 2 = after "}" or " " */
1027
1028 while(*w2)
1029 {
1030 if((mode == 0) && (*w2 == '{'))
1031 {
1032 mode = 1;
1033 w2++;
1034 }
1035 else if((mode == 1) && (*w2 == '}'))
1036 {
1037 /* strcpy(prefix, ""); */
1038 *(prefix) = '\0';
1039 mode = 2;
1040 w2++;
1041 }
1042 else if((mode == 0) && (*w2 == ' '))
1043 {
1044 /* strcpy(prefix, ""); */
1045 *(prefix) = '\0';
1046 strcpy(new, w2);
1047 mode = 2;
1048 w2++;
1049 new++;
1050 }
1051 else
1052 {
1053 strcpy(new, w2);
1054 if (mode != 2)
1055 {
1056 strcpy(prefix, w2);
1057 prefix++;
1058 }
1059 w2++;
1060 new++;
1061 }
1062 }
1063
1064 prefix = prefix_init;
1065 w2 = w2_init;
1066
1067 /* printf("HHHHH |%s| %s\n", prefix, w2); */
1068
1069
1070 if(*w2=='*')
1071 {
1072 float f;
1073 TimeType ttlocal;
1074 int which=0;
1075
1076 GLOBALS->zoom_was_explicitly_set=~0;
1077 w2++;
1078
1079 for(;;)
1080 {
1081 while(*w2==' ') w2++;
1082 if(*w2==0) return(~0);
1083
1084 if(!which)
1085 {
1086 sscanf(w2,"%f",&f);
1087 if((!GLOBALS->do_initial_zoom_fit)||(!GLOBALS->do_initial_zoom_fit_used))
1088 {
1089 GLOBALS->tims.zoom=(gdouble)f;
1090 }
1091 }
1092 else
1093 {
1094 sscanf(w2,TTFormat,&ttlocal);
1095 switch(which)
1096 {
1097 case 1: GLOBALS->tims.marker=ttlocal; break;
1098 default:
1099 if((which-2)<WAVE_NUM_NAMED_MARKERS) GLOBALS->named_markers[which-2]=ttlocal;
1100 break;
1101 }
1102 }
1103 which++;
1104 w2++;
1105 for(;;)
1106 {
1107 if(*w2==0) return(~0);
1108 if(*w2=='\n') return(~0);
1109 if(*w2!=' ') w2++; else break;
1110 }
1111 }
1112 }
1113 else
1114 if(*w2=='-')
1115 {
1116 AddBlankTrace((*(w2+1)!=0)?(w2+1):NULL);
1117 }
1118 else
1119 if(*w2=='>')
1120 {
1121 char *wnptr=(*(w2+1)!=0)?(w2+1):NULL;
1122 GLOBALS->shift_timebase_default_for_add=wnptr?atoi_64(wnptr):LLDescriptor(0);
1123 }
1124 else
1125 if(*w2=='@')
1126 {
1127 /* handle trace flags */
1128 sscanf(w2+1, "%"TRACEFLAGSSCNFMT, &GLOBALS->default_flags);
1129 if( (GLOBALS->default_flags & (TR_FTRANSLATED|TR_PTRANSLATED)) == (TR_FTRANSLATED|TR_PTRANSLATED) )
1130 {
1131 GLOBALS->default_flags &= ~TR_PTRANSLATED; /* safest bet though this is a cfg file error */
1132 }
1133
1134 return(~0);
1135 }
1136 else
1137 if(*w2=='+')
1138 {
1139 /* handle aliasing */
1140 struct symbol *s;
1141 sscanf(w2+strlen(prefix),"%s",suffix);
1142
1143 if(suffix[0]=='(')
1144 {
1145 for(i=1;;i++)
1146 {
1147 if(suffix[i]==0) return(0);
1148 if((suffix[i]==')')&&(suffix[i+1])) {i++; break; }
1149 }
1150
1151 s=symfind(suffix+i, &rows);
1152 if (s) {
1153 nexp = ExtractNodeSingleBit(&s->n[rows], atoi(suffix+1));
1154 if(nexp)
1155 {
1156 AddNode(nexp, prefix+1);
1157 return(~0);
1158 }
1159 else
1160 {
1161 return(0);
1162 }
1163 }
1164 else
1165 {
1166 char *lp = strrchr(suffix+i, '[');
1167 if(lp)
1168 {
1169 char *ns = malloc_2(strlen(suffix+i) + 32);
1170 char *colon = strchr(lp+1, ':');
1171 int msi, lsi, bval, actual;
1172 *lp = 0;
1173
1174 bval = atoi(suffix+1);
1175 if(colon)
1176 {
1177 msi = atoi(lp+1);
1178 lsi = atoi(colon+1);
1179
1180 if(lsi > msi)
1181 {
1182 actual = msi + bval;
1183 }
1184 else
1185 {
1186 actual = msi - bval;
1187 }
1188 }
1189 else
1190 {
1191 actual = bval; /* punt */
1192 }
1193
1194 sprintf(ns, "%s[%d]", suffix+i, actual);
1195 *lp = '[';
1196
1197 s=symfind(ns, &rows);
1198 free_2(ns);
1199 if(s)
1200 {
1201 AddNode(&s->n[rows], prefix+1);
1202 return(~0);
1203 }
1204
1205 }
1206
1207 return(0);
1208 }
1209 }
1210 else
1211 {
1212 int rc;
1213
1214 char *newl = strdup_2(w2+strlen(prefix));
1215 char *nalias = strdup_2(prefix+1);
1216
1217 rc = parsewavline(newl, nalias, depth);
1218 if (newl) free_2(newl);
1219 if (nalias) free_2(nalias);
1220
1221 return rc;
1222 }
1223 /* { */
1224 /* if((s=symfind(suffix, &rows))) */
1225 /* { */
1226 /* AddNode(&s->n[rows],prefix+1); */
1227 /* return(~0); */
1228 /* } */
1229 /* else */
1230 /* { */
1231 /* return(0); */
1232 /* } */
1233 /* } */
1234 }
1235 else
1236 if((*w2=='#')||(*w2==':'))
1237 {
1238 /* handle bitvec */
1239 bvptr v=NULL;
1240 bptr b=NULL;
1241 int maketyp = (*w2=='#');
1242
1243 w2=w2+strlen(prefix);
1244 while(1)
1245 {
1246 if(isspace((int)(unsigned char)*w2)) { w2++; continue; }
1247 if(!(*w2)) return(0); /* no more args */
1248 break; /* start grabbing chars from here */
1249 }
1250
1251 b = maketyp ? makevec(prefix+1,w2) : makevec_annotated(prefix+1,w2); /* '#' vs ':' cases... */
1252
1253 if(GLOBALS->default_flags&TR_GRP_BEGIN) { current_grp_depth = GLOBALS->group_depth; }
1254
1255 if(b)
1256 {
1257 if((v=bits2vector(b)))
1258 {
1259 v->bits=b; /* only needed for savefile function */
1260 AddVector(v, alias);
1261 free_2(b->name);
1262 b->name=NULL;
1263 goto grp_bot;
1264 }
1265 else
1266 {
1267 free_2(b->name);
1268 if(b->attribs) free_2(b->attribs);
1269 free_2(b);
1270 }
1271 }
1272 else if(!depth) /* don't try vectorized if we're re-entrant */
1273 {
1274 char *sp = strchr(w2, ' ');
1275 char *lbrack;
1276
1277 if(sp)
1278 {
1279 *sp = 0;
1280
1281 lbrack = strrchr(w2, '[');
1282
1283 if(lbrack)
1284 {
1285 /* int made = 0; */ /* scan-build */
1286 char *w3;
1287 char *rbrack = strrchr(w2, ']');
1288 char *rightmost_lbrack = strrchr(sp+1, '[');
1289
1290 if(rbrack && rightmost_lbrack)
1291 {
1292 *rbrack = 0;
1293
1294 w3 = malloc_2(strlen(w2) + 1 + strlen(rightmost_lbrack+1) + 1);
1295 sprintf(w3, "%s:%s", w2, rightmost_lbrack+1);
1296
1297 /* made = */ maketraces(w3, alias, 1); /* scan-build */
1298 free_2(w3);
1299 }
1300
1301 #if 0
1302 /* this is overkill for now with possible delay implications so commented out */
1303 if(!made)
1304 {
1305 *lbrack = 0;
1306 fprintf(stderr, "GTKWAVE | Attempting regex '%s' on missing stranded vector\n", w2);
1307
1308 w3 = malloc_2(1 + strlen(w2) + 5);
1309 sprintf(w3, "^%s\\[.*", w2);
1310 maketraces(w3, alias, 1);
1311 free_2(w3);
1312 }
1313 #endif
1314 }
1315 }
1316 }
1317
1318 grp_bot:
1319 if((GLOBALS->default_flags&TR_GRP_BEGIN) && (current_grp_depth >= 0) && (current_grp_depth == GLOBALS->group_depth)) { AddBlankTrace(prefix+1); }
1320 return(v!=NULL);
1321 }
1322 else
1323 if(*w2=='!')
1324 {
1325 /* fill logical_mutex */
1326 char ch;
1327
1328 for(i=0;i<6;i++)
1329 {
1330 ch = *(w2+i+1);
1331 if(ch != 0)
1332 {
1333 if(ch=='!')
1334 {
1335 GLOBALS->strace_ctx->shadow_active = 0;
1336 return(~0);
1337 }
1338
1339 if((!i)&&(GLOBALS->strace_ctx->shadow_straces))
1340 {
1341 delete_strace_context();
1342 }
1343
1344 GLOBALS->strace_ctx->shadow_logical_mutex[i] = (ch & 1);
1345 }
1346 else /* in case of short read */
1347 {
1348 GLOBALS->strace_ctx->shadow_logical_mutex[i] = 0;
1349 }
1350 }
1351
1352 GLOBALS->strace_ctx->shadow_mark_idx_start = 0;
1353 GLOBALS->strace_ctx->shadow_mark_idx_end = 0;
1354
1355 if(i==6)
1356 {
1357 ch = *(w2+7);
1358 if(ch != 0)
1359 {
1360 if (isupper((int)(unsigned char)ch) || ch=='@')
1361 GLOBALS->strace_ctx->shadow_mark_idx_start = ch - '@';
1362
1363 ch = *(w2+8);
1364 if(ch != 0)
1365 {
1366 if (isupper((int)(unsigned char)ch) || ch=='@')
1367 GLOBALS->strace_ctx->shadow_mark_idx_end = ch - '@';
1368 }
1369 }
1370 }
1371
1372 GLOBALS->strace_ctx->shadow_active = 1;
1373 return(~0);
1374 }
1375 else
1376 if(*w2=='?')
1377 {
1378 /* fill st->type */
1379 if(*(w2+1)=='\"')
1380 {
1381 int lens = strlen(w2+2);
1382 if(GLOBALS->strace_ctx->shadow_string) free_2(GLOBALS->strace_ctx->shadow_string);
1383 GLOBALS->strace_ctx->shadow_string=NULL;
1384
1385 if(lens)
1386 {
1387 GLOBALS->strace_ctx->shadow_string = malloc_2(lens+1);
1388 strcpy(GLOBALS->strace_ctx->shadow_string, w2+2);
1389 }
1390
1391 GLOBALS->strace_ctx->shadow_type = ST_STRING;
1392 }
1393 else
1394 {
1395 unsigned int hex;
1396 sscanf(w2+1, "%x", &hex);
1397 GLOBALS->strace_ctx->shadow_type = hex;
1398 }
1399
1400 return(~0);
1401 }
1402 else if(*w2=='^')
1403 {
1404 if(*(w2+1) == '>')
1405 {
1406 GLOBALS->current_translate_proc = 0; /* will overwrite if loadable/translatable */
1407
1408 if(*(w2+2) != '0')
1409 {
1410 /* char *fn = strstr(w2+3, " "); */
1411 char *fn = w2+2;
1412 while(*fn && !isspace((int)(unsigned char)*fn)) fn++;
1413 if(fn)
1414 {
1415 while(*fn && isspace((int)(unsigned char)*fn)) fn++;
1416 if(*fn && !isspace((int)(unsigned char)*fn))
1417 {
1418 char *rp = get_relative_adjusted_name(GLOBALS->sfn, fn, GLOBALS->lcname);
1419 set_current_translate_proc(rp ? rp : fn);
1420 if(rp) free_2(rp);
1421 }
1422 }
1423 }
1424 }
1425 else
1426 if(*(w2+1) == '<')
1427 {
1428 GLOBALS->current_translate_ttrans = 0; /* will overwrite if loadable/translatable */
1429
1430 if(*(w2+2) != '0')
1431 {
1432 /* char *fn = strstr(w2+3, " "); */
1433 char *fn = w2+3;
1434 if(fn)
1435 {
1436 while(*fn && isspace((int)(unsigned char)*fn)) fn++;
1437 if(*fn && !isspace((int)(unsigned char)*fn))
1438 {
1439 char *rp = get_relative_adjusted_name(GLOBALS->sfn, fn, GLOBALS->lcname);
1440 set_current_translate_ttrans(rp ? rp : fn);
1441 if(rp) free_2(rp);
1442 }
1443 }
1444 }
1445 }
1446 else
1447 {
1448 GLOBALS->current_translate_file = 0; /* will overwrite if loadable/translatable */
1449
1450 if(*(w2+1) != '0')
1451 {
1452 char *fn = strstr(w2+2, " ");
1453 if(fn)
1454 {
1455 while(*fn && isspace((int)(unsigned char)*fn)) fn++;
1456 if(*fn && !isspace((int)(unsigned char)*fn))
1457 {
1458 char *rp = get_relative_adjusted_name(GLOBALS->sfn, fn, GLOBALS->lcname);
1459 set_current_translate_file(rp ? rp : fn);
1460 if(rp) free_2(rp);
1461 }
1462 }
1463 }
1464 }
1465 }
1466 else if (*w2 == '[')
1467 {
1468 /* Search for matching ']'. */
1469 w2++;
1470 for (w = w2; *w; w++)
1471 if (*w == ']')
1472 break;
1473 if (!*w)
1474 return 0;
1475
1476 *w++ = 0;
1477 if (strcmp (w2, "size") == 0)
1478 {
1479 if(!GLOBALS->ignore_savefile_size)
1480 {
1481 /* Main window size. */
1482 int x, y;
1483 sscanf (w, "%d %d", &x, &y);
1484 if(!GLOBALS->block_xy_update) set_window_size (x, y);
1485 }
1486 }
1487 else if (strcmp (w2, "pos") == 0)
1488 {
1489 if(!GLOBALS->ignore_savefile_pos)
1490 {
1491 /* Main window position. */
1492 int x, y;
1493 sscanf (w, "%d %d", &x, &y);
1494 if(!GLOBALS->block_xy_update) set_window_xypos (x, y);
1495 }
1496 }
1497 else if (strcmp (w2, "sst_width") == 0)
1498 {
1499 if(!GLOBALS->ignore_savefile_pane_pos)
1500 {
1501 /* sst vs rhs of window position. */
1502 int x;
1503 sscanf (w, "%d", &x);
1504 if(!GLOBALS->block_xy_update)
1505 {
1506 if(GLOBALS->toppanedwindow)
1507 {
1508 #if GTK_CHECK_VERSION(2,4,0)
1509 gtk_paned_set_position(GTK_PANED(GLOBALS->toppanedwindow), x);
1510 #endif
1511 }
1512 else
1513 {
1514 GLOBALS->toppanedwindow_size_cache = x;
1515 }
1516 }
1517 }
1518 }
1519 else if (strcmp (w2, "signals_width") == 0)
1520 {
1521 if(!GLOBALS->ignore_savefile_pane_pos)
1522 {
1523 /* signals vs waves panes position. */
1524 int x;
1525 sscanf (w, "%d", &x);
1526 if(!GLOBALS->block_xy_update)
1527 {
1528 if(GLOBALS->panedwindow)
1529 {
1530 #if GTK_CHECK_VERSION(2,4,0)
1531 gtk_paned_set_position(GTK_PANED(GLOBALS->panedwindow), x);
1532 #endif
1533 }
1534 else
1535 {
1536 GLOBALS->panedwindow_size_cache = x;
1537 }
1538 }
1539 }
1540 }
1541 else if (strcmp (w2, "sst_expanded") == 0)
1542 {
1543 if(!GLOBALS->ignore_savefile_pane_pos)
1544 {
1545 /* sst is expanded? */
1546 int x;
1547 sscanf (w, "%d", &x);
1548 GLOBALS->sst_expanded = (x != 0);
1549 #if GTK_CHECK_VERSION(2,4,0)
1550 if(!GLOBALS->block_xy_update)
1551 {
1552 if(GLOBALS->expanderwindow)
1553 {
1554 gtk_expander_set_expanded(GTK_EXPANDER(GLOBALS->expanderwindow), GLOBALS->sst_expanded);
1555 }
1556 }
1557 #endif
1558 }
1559 }
1560 else if (strcmp (w2, "sst_vpaned_height") == 0)
1561 {
1562 if(!GLOBALS->ignore_savefile_pane_pos)
1563 {
1564 /* signals vs waves panes position. */
1565 int x;
1566 sscanf (w, "%d", &x);
1567 if(!GLOBALS->block_xy_update)
1568 {
1569 if(GLOBALS->sst_vpaned)
1570 {
1571 #if GTK_CHECK_VERSION(2,4,0)
1572 gtk_paned_set_position(GTK_PANED(GLOBALS->sst_vpaned), x);
1573 #endif
1574 }
1575 else
1576 {
1577 GLOBALS->vpanedwindow_size_cache = x;
1578 }
1579 }
1580 }
1581 }
1582 else if (strcmp (w2, "color") == 0)
1583 {
1584 int which_col = 0;
1585 sscanf (w, "%d", &which_col);
1586 if((which_col>=0)&&(which_col<=WAVE_NUM_RAINBOW))
1587 {
1588 GLOBALS->which_t_color = which_col;
1589 }
1590 else
1591 {
1592 GLOBALS->which_t_color = 0;
1593 }
1594 }
1595 else if (strcmp (w2, "fpshift_count") == 0)
1596 {
1597 int fpshift_count = 0;
1598 sscanf (w, "%d", &fpshift_count);
1599 if((fpshift_count<0)||(fpshift_count>255))
1600 {
1601 fpshift_count = 0;
1602 }
1603 GLOBALS->default_fpshift = fpshift_count;
1604 }
1605 else if (strcmp (w2, "pattern_trace") == 0)
1606 {
1607 int which_ctx = 0;
1608 sscanf (w, "%d", &which_ctx);
1609 if((which_ctx>=0)&&(which_ctx<WAVE_NUM_STRACE_WINDOWS))
1610 {
1611 GLOBALS->strace_ctx = &GLOBALS->strace_windows[GLOBALS->strace_current_window = which_ctx];
1612 }
1613 }
1614 else if (strcmp (w2, "ruler") == 0)
1615 {
1616 GLOBALS->ruler_origin = GLOBALS->ruler_step = LLDescriptor(0);
1617 sscanf(w, TTFormat" "TTFormat, &GLOBALS->ruler_origin, &GLOBALS->ruler_step);
1618 }
1619 else if (strcmp (w2, "timestart") == 0)
1620 {
1621 sscanf(w, TTFormat, &GLOBALS->timestart_from_savefile);
1622 GLOBALS->timestart_from_savefile_valid = 1;
1623 }
1624 #if WAVE_USE_GTK2
1625 else if (strcmp (w2, "treeopen") == 0)
1626 {
1627 while(*w)
1628 {
1629 if(!isspace((int)(unsigned char)*w))
1630 {
1631 break;
1632 }
1633 w++;
1634 }
1635
1636 if(GLOBALS->ctree_main)
1637 {
1638 force_open_tree_node(w, 0, NULL);
1639 }
1640 else
1641 {
1642 /* cache values until ctree_main is created */
1643 struct string_chain_t *t = calloc_2(1, sizeof(struct string_chain_t));
1644 t->str = strdup_2(w);
1645
1646 if(!GLOBALS->treeopen_chain_curr)
1647 {
1648 GLOBALS->treeopen_chain_head = GLOBALS->treeopen_chain_curr = t;
1649 }
1650 else
1651 {
1652 GLOBALS->treeopen_chain_curr->next = t;
1653 GLOBALS->treeopen_chain_curr = t;
1654 }
1655 }
1656 }
1657 #endif
1658 else if (strcmp (w2, "markername") == 0)
1659 {
1660 char *pnt = w;
1661 int which;
1662
1663 if((*pnt) && (isspace((int)(unsigned char)*pnt))) pnt++;
1664
1665 if(*pnt)
1666 {
1667 which = (*pnt) - 'A';
1668 if((which >=0) && (which < WAVE_NUM_NAMED_MARKERS))
1669 {
1670 pnt++;
1671
1672 if(*pnt)
1673 {
1674 if(GLOBALS->marker_names[which]) free_2(GLOBALS->marker_names[which]);
1675 GLOBALS->marker_names[which] = strdup_2(pnt);
1676 }
1677 }
1678 }
1679 }
1680 else if (strcmp (w2, "markername_long") == 0)
1681 {
1682 char *pnt = w;
1683 int which;
1684
1685 if((*pnt) && (isspace((int)(unsigned char)*pnt))) pnt++;
1686
1687 if(*pnt)
1688 {
1689 char *pnt2 = strchr(pnt, ' ');
1690 if(pnt2)
1691 {
1692 *pnt2 = 0;
1693 which = bijective_marker_id_string_hash(pnt);
1694 if((which >=0) && (which < WAVE_NUM_NAMED_MARKERS))
1695 {
1696 pnt = pnt2 + 1;
1697 if((*pnt) && (isspace((int)(unsigned char)*pnt))) pnt++;
1698
1699 if(*pnt)
1700 {
1701 if(GLOBALS->marker_names[which]) free_2(GLOBALS->marker_names[which]);
1702 GLOBALS->marker_names[which] = strdup_2(pnt);
1703 }
1704 }
1705 }
1706 }
1707 }
1708 else if (strcmp (w2, "dumpfile") == 0)
1709 {
1710 /* nothing here currently...only finder/DnD processes these externally */
1711 }
1712 else if (strcmp (w2, "savefile") == 0)
1713 {
1714 /* store name for relative name processing of filters */
1715 char *lhq = strchr(w, '"');
1716 char *rhq = strrchr(w, '"');
1717
1718 if(GLOBALS->sfn)
1719 {
1720 free_2(GLOBALS->sfn); GLOBALS->sfn = NULL;
1721 }
1722
1723 if((lhq) && (rhq) && (lhq != rhq)) /* no real need to check rhq != NULL*/
1724 {
1725 *rhq = 0;
1726 GLOBALS->sfn = strdup_2(lhq + 1);
1727 }
1728 }
1729 else if (strcmp (w2, "transaction_args") == 0)
1730 {
1731 char *lhq = strchr(w, '"');
1732 char *rhq = strrchr(w, '"');
1733
1734 if(GLOBALS->ttranslate_args)
1735 {
1736 free_2(GLOBALS->ttranslate_args); GLOBALS->ttranslate_args = NULL;
1737 }
1738
1739 if((lhq) && (rhq) && (lhq != rhq)) /* no real need to check rhq != NULL*/
1740 {
1741 *rhq = 0;
1742 GLOBALS->ttranslate_args = strdup_2(lhq + 1);
1743 }
1744 }
1745 else if (strcmp (w2, "*") == 0)
1746 {
1747 /* reserved for [*] comment lines */
1748 }
1749 else
1750 {
1751 /* Unknown attribute. Forget it. */
1752 return 0;
1753 }
1754 }
1755 else
1756 {
1757 int rc = maketraces(w, alias, 0);
1758
1759 if(rc)
1760 {
1761 return(rc);
1762 }
1763 else
1764 {
1765 char *newl = synth_blastvec(w);
1766
1767 if(newl)
1768 {
1769 rc = parsewavline(newl, alias, depth+1);
1770 free_2(newl);
1771 }
1772
1773 /* prevent malformed group openings [missing group opening] from keeping other signals from displaying */
1774 if((!rc)&&(GLOBALS->default_flags&TR_GRP_BEGIN))
1775 {
1776 AddBlankTrace(w);
1777 rc = ~0;
1778 }
1779
1780 return(rc);
1781 }
1782 }
1783
1784 return(0);
1785 }
1786
1787 /******************************************************************/
1788
1789 /****************/
1790 /* LX2 variants */
1791 /****************/
1792
1793 /*
1794 * Make solitary traces from wildcarded signals...
1795 */
maketraces_lx2(char * str,char * alias,int quick_return)1796 int maketraces_lx2(char *str, char *alias, int quick_return)
1797 {
1798 (void)alias;
1799
1800 char *pnt, *wild;
1801 char ch, wild_active=0;
1802 int len;
1803 int i;
1804 int made = 0;
1805
1806 pnt=str;
1807 while((ch=*pnt))
1808 {
1809 if(ch=='*')
1810 {
1811 wild_active=1;
1812 break;
1813 }
1814 pnt++;
1815 }
1816
1817 if(!wild_active) /* short circuit wildcard evaluation with bsearch */
1818 {
1819 struct symbol *s;
1820
1821 if(str[0]=='(')
1822 {
1823 for(i=1;;i++)
1824 {
1825 if(str[i]==0) return(0);
1826 if((str[i]==')')&&(str[i+1])) {i++; break; }
1827 }
1828
1829 if((s=symfind(str+i, NULL)))
1830 {
1831 lx2_set_fac_process_mask(s->n);
1832 made = ~0;
1833 }
1834 return(made);
1835 }
1836 else
1837 {
1838 if((s=symfind(str, NULL)))
1839 {
1840 lx2_set_fac_process_mask(s->n);
1841 made = ~0;
1842 }
1843 return(made);
1844 }
1845 }
1846
1847 while(1)
1848 {
1849 pnt=str;
1850 len=0;
1851
1852 while(1)
1853 {
1854 ch=*pnt++;
1855 if(isspace((int)(unsigned char)ch)||(!ch)) break;
1856 len++;
1857 }
1858
1859 if(len)
1860 {
1861 wild=(char *)calloc_2(1,len+1);
1862 memcpy(wild,str,len);
1863 wave_regex_compile(wild, WAVE_REGEX_WILD);
1864
1865 for(i=0;i<GLOBALS->numfacs;i++)
1866 {
1867 if(wave_regex_match(GLOBALS->facs[i]->name, WAVE_REGEX_WILD))
1868 {
1869 lx2_set_fac_process_mask(GLOBALS->facs[i]->n);
1870 made = ~0;
1871 if(quick_return) break;
1872 }
1873 }
1874
1875 free_2(wild);
1876 }
1877
1878 if(!ch) break;
1879 str=pnt;
1880 }
1881 return(made);
1882 }
1883
1884
1885 /*
1886 * Create a vector from wildcarded signals...
1887 */
makevec_lx2(char * str)1888 int makevec_lx2(char *str)
1889 {
1890 char *pnt, *pnt2, *wild=NULL;
1891 char ch, ch2, wild_active;
1892 int len;
1893 int i;
1894 int rc = 0;
1895
1896 while(1)
1897 {
1898 pnt=str;
1899 len=0;
1900
1901 while(1)
1902 {
1903 ch=*pnt++;
1904 if(isspace((int)(unsigned char)ch)||(!ch)) break;
1905 len++;
1906 }
1907
1908 if(len)
1909 {
1910 wild=(char *)calloc_2(1,len+1);
1911 memcpy(wild,str,len);
1912
1913 DEBUG(printf("WILD: %s\n",wild));
1914
1915 wild_active=0;
1916 pnt2=wild;
1917 while((ch2=*pnt2))
1918 {
1919 if(ch2=='*')
1920 {
1921 wild_active=1;
1922 break;
1923 }
1924 pnt2++;
1925 }
1926
1927 if(!wild_active) /* short circuit wildcard evaluation with bsearch */
1928 {
1929 struct symbol *s;
1930 if(wild[0]=='(')
1931 {
1932 for(i=1;;i++)
1933 {
1934 if(wild[i]==0) break;
1935 if((wild[i]==')')&&(wild[i+1]))
1936 {
1937 i++;
1938 s=symfind(wild+i, NULL);
1939 if(s)
1940 {
1941 lx2_set_fac_process_mask(s->n);
1942 rc = 1;
1943 }
1944 break;
1945 }
1946 }
1947 }
1948 else
1949 {
1950 if((s=symfind(wild, NULL)))
1951 {
1952 lx2_set_fac_process_mask(s->n);
1953 rc = 1;
1954 }
1955 }
1956 }
1957 else
1958 {
1959 wave_regex_compile(wild, WAVE_REGEX_WILD);
1960 for(i=GLOBALS->numfacs-1;i>=0;i--) /* to keep vectors in little endian hi..lo order */
1961 {
1962 if(wave_regex_match(GLOBALS->facs[i]->name, WAVE_REGEX_WILD))
1963 {
1964 lx2_set_fac_process_mask(GLOBALS->facs[i]->n);
1965 rc = 1;
1966 }
1967 }
1968 }
1969 free_2(wild);
1970 }
1971
1972 if(!ch) break;
1973 str=pnt;
1974 }
1975
1976 return(rc);
1977 }
1978
1979
1980 /*
1981 * Parse a line of the wave file and act accordingly..
1982 * Returns nonzero if trace(s) added.
1983 */
parsewavline_lx2(char * w,char * alias,int depth)1984 int parsewavline_lx2(char *w, char *alias, int depth)
1985 {
1986 int made = 0;
1987 int i;
1988 int len;
1989 char *w2;
1990 char *prefix, *suffix, *new;
1991 char *prefix_init, *w2_init;
1992 unsigned int mode;
1993
1994
1995 if(!(len=strlen(w))) return(0);
1996 if(*(w+len-1)=='\n')
1997 {
1998 *(w+len-1)=0x00; /* strip newline if present */
1999 len--;
2000 if(!len) return(0);
2001 }
2002
2003 while(1)
2004 {
2005 if(isspace((int)(unsigned char)*w)) { w++; continue; }
2006 if(!(*w)) return(0); /* no args */
2007 break; /* start grabbing chars from here */
2008 }
2009
2010 w2=w;
2011
2012 /* sscanf(w2,"%s",prefix); */
2013
2014 prefix=(char *)wave_alloca(len+1);
2015 suffix=(char *)wave_alloca(len+1);
2016 new=(char *)wave_alloca(len+1);
2017 new[0] = 0; /* scan-build : in case there are weird mode problems */
2018
2019 prefix_init = prefix;
2020 w2_init = new;
2021 mode = 0; /* 0 = before "{", 1 = after "{", 2 = after "}" or " " */
2022
2023 while(*w2)
2024 {
2025 if((mode == 0) && (*w2 == '{'))
2026 {
2027 mode = 1;
2028 w2++;
2029 }
2030 else if((mode == 1) && (*w2 == '}'))
2031 {
2032
2033 *(prefix) = '\0';
2034 mode = 2;
2035 w2++;
2036 }
2037 else if((mode == 0) && (*w2 == ' '))
2038 {
2039 *(prefix) = '\0';
2040 strcpy(new, w2);
2041 mode = 2;
2042 w2++;
2043 new++;
2044 }
2045 else
2046 {
2047 strcpy(new, w2);
2048 if (mode != 2)
2049 {
2050 strcpy(prefix, w2);
2051 prefix++;
2052 }
2053 w2++;
2054 new++;
2055 }
2056 }
2057
2058 prefix = prefix_init;
2059 w2 = w2_init;
2060
2061 /* printf("IIIII |%s| %s\n", prefix, w2); */
2062
2063 if(*w2=='[')
2064 {
2065 }
2066 else
2067 if(*w2=='*')
2068 {
2069 }
2070 else
2071 if(*w2=='-')
2072 {
2073 }
2074 else
2075 if(*w2=='>')
2076 {
2077 }
2078 else
2079 if(*w2=='@')
2080 {
2081 }
2082 else
2083 if(*w2=='+')
2084 {
2085 /* handle aliasing */
2086 struct symbol *s;
2087 sscanf(w2+strlen(prefix),"%s",suffix);
2088
2089 if(suffix[0]=='(')
2090 {
2091 for(i=1;;i++)
2092 {
2093 if(suffix[i]==0) return(0);
2094 if((suffix[i]==')')&&(suffix[i+1])) {i++; break; }
2095 }
2096
2097 s=symfind(suffix+i, NULL);
2098 if(s)
2099 {
2100 lx2_set_fac_process_mask(s->n);
2101 made = ~0;
2102 }
2103 else
2104 {
2105 char *lp = strrchr(suffix+i, '[');
2106 if(lp)
2107 {
2108 char *ns = malloc_2(strlen(suffix+i) + 32);
2109 char *colon = strchr(lp+1, ':');
2110 int msi, lsi, bval, actual;
2111 *lp = 0;
2112
2113 bval = atoi(suffix+1);
2114 if(colon)
2115 {
2116 msi = atoi(lp+1);
2117 lsi = atoi(colon+1);
2118
2119 if(lsi > msi)
2120 {
2121 actual = msi + bval;
2122 }
2123 else
2124 {
2125 actual = msi - bval;
2126 }
2127 }
2128 else
2129 {
2130 actual = bval; /* punt */
2131 }
2132
2133 sprintf(ns, "%s[%d]", suffix+i, actual);
2134 *lp = '[';
2135
2136 s=symfind(ns, NULL);
2137 free_2(ns);
2138 if(s)
2139 {
2140 lx2_set_fac_process_mask(s->n);
2141 made = ~0;
2142 }
2143 }
2144 }
2145
2146 return(made);
2147 }
2148 else
2149 {
2150 int rc;
2151 char *newl = strdup_2(w2+strlen(prefix));
2152 char *nalias = strdup_2(prefix+1);
2153
2154 rc = parsewavline_lx2(newl, nalias, depth);
2155 if (newl) free_2(newl);
2156 if (nalias) free_2(nalias);
2157
2158 return rc;
2159 }
2160
2161 /* { */
2162 /* if((s=symfind(suffix, NULL))) */
2163 /* { */
2164 /* lx2_set_fac_process_mask(s->n); */
2165 /* made = ~0; */
2166 /* } */
2167 /* return(made); */
2168 /* } */
2169 }
2170 else
2171 if((*w2=='#')||(*w2==':'))
2172 {
2173 int rc;
2174
2175 /* handle bitvec, parsing extra time info and such is inefficient but ok for ":" case */
2176 w2=w2+strlen(prefix);
2177 while(1)
2178 {
2179 if(isspace((int)(unsigned char)*w2)) { w2++; continue; }
2180 if(!(*w2)) return(0); /* no more args */
2181 break; /* start grabbing chars from here */
2182 }
2183
2184 rc = makevec_lx2(w2);
2185 if((!rc)&&(!depth)) /* don't try vectorized if we're re-entrant */
2186 {
2187 char *sp = strchr(w2, ' ');
2188 char *lbrack;
2189
2190 if(sp)
2191 {
2192 *sp = 0;
2193
2194 lbrack = strrchr(w2, '[');
2195
2196 if(lbrack)
2197 {
2198 char *w3;
2199 char *rbrack = strrchr(w2, ']');
2200 char *rightmost_lbrack = strrchr(sp+1, '[');
2201
2202 if(rbrack && rightmost_lbrack)
2203 {
2204 *rbrack = 0;
2205
2206 w3 = malloc_2(strlen(w2) + 1 + strlen(rightmost_lbrack+1) + 1);
2207 sprintf(w3, "%s:%s", w2, rightmost_lbrack+1);
2208
2209 made = maketraces_lx2(w3, alias, 1);
2210 free_2(w3);
2211 }
2212
2213 if(0) /* this is overkill for now with possible delay implications so commented out */
2214 if(!made)
2215 {
2216 *lbrack = 0;
2217
2218 w3 = malloc_2(1 + strlen(w2) + 5);
2219 sprintf(w3, "^%s\\[.*", w2);
2220 maketraces_lx2(w3, alias, 1);
2221 free_2(w3);
2222 }
2223 }
2224 }
2225 }
2226
2227 return(made);
2228 }
2229 else
2230 if(*w2=='!')
2231 {
2232 }
2233 else
2234 if(*w2=='?')
2235 {
2236 }
2237 else if(*w2=='^')
2238 {
2239 }
2240 else
2241 {
2242 made = maketraces_lx2(w, alias, 0);
2243 if(!made)
2244 {
2245 char *newl = synth_blastvec(w);
2246
2247 if(newl)
2248 {
2249 made = parsewavline_lx2(newl, alias, depth+1);
2250 free_2(newl);
2251 }
2252 }
2253 }
2254
2255 return(made);
2256 }
2257
2258 /******************************************************************/
2259
2260 /* GetRelativeFilename(), by Rob Fisher.
2261 * rfisher@iee.org
2262 * http://come.to/robfisher
2263 */
2264
2265 #define MAX_FILENAME_LEN PATH_MAX
2266
2267 /* The number of characters at the start of an absolute filename. e.g. in DOS,
2268 * absolute filenames start with "X:\" so this value should be 3, in UNIX they start
2269 * with "\" so this value should be 1.
2270 */
2271 #if defined _MSC_VER || defined __MINGW32__
2272 #define ABSOLUTE_NAME_START 3
2273 #else
2274 #define ABSOLUTE_NAME_START 1
2275 #endif
2276
2277 /* set this to '\\' for DOS or '/' for UNIX */
2278 #if defined _MSC_VER || defined __MINGW32__
2279 #define SLASH '\\'
2280 #else
2281 #define SLASH '/'
2282 #endif
2283
2284 /* Given the absolute current directory and an absolute file name, returns a relative file name.
2285 * For example, if the current directory is C:\foo\bar and the filename C:\foo\whee\text.txt is given,
2286 * GetRelativeFilename will return ..\whee\text.txt.
2287 */
GetRelativeFilename(char * currentDirectory,char * absoluteFilename,int * dotdot_levels)2288 char* GetRelativeFilename(char *currentDirectory, char *absoluteFilename, int *dotdot_levels)
2289 {
2290 int afMarker = 0, rfMarker = 0;
2291 int cdLen = 0, afLen = 0;
2292 int i = 0;
2293 int levels = 0;
2294 static char relativeFilename[MAX_FILENAME_LEN+1];
2295
2296 *dotdot_levels = 0;
2297
2298 cdLen = strlen(currentDirectory);
2299 afLen = strlen(absoluteFilename);
2300
2301 /* make sure the names are not too long or too short */
2302 if(cdLen > MAX_FILENAME_LEN || cdLen < ABSOLUTE_NAME_START+1 ||
2303 afLen > MAX_FILENAME_LEN || afLen < ABSOLUTE_NAME_START+1)
2304 {
2305 return(NULL);
2306 }
2307
2308 /* Handle DOS names that are on different drives: */
2309 if(currentDirectory[0] != absoluteFilename[0])
2310 {
2311 /* not on the same drive, so only absolute filename will do */
2312 strcpy(relativeFilename, absoluteFilename);
2313 return(relativeFilename);
2314 }
2315
2316 /* they are on the same drive, find out how much of the current directory
2317 * is in the absolute filename
2318 */
2319 i = ABSOLUTE_NAME_START;
2320 while(i < afLen && i < cdLen && currentDirectory[i] == absoluteFilename[i])
2321 {
2322 i++;
2323 }
2324
2325 if(i == cdLen && (absoluteFilename[i] == SLASH || absoluteFilename[i-1] == SLASH))
2326 {
2327 /* the whole current directory name is in the file name,
2328 * so we just trim off the current directory name to get the
2329 * current file name.
2330 */
2331 if(absoluteFilename[i] == SLASH)
2332 {
2333 /* a directory name might have a trailing slash but a relative
2334 * file name should not have a leading one...
2335 */
2336 i++;
2337 }
2338
2339 strcpy(relativeFilename, &absoluteFilename[i]);
2340 return(relativeFilename);
2341 }
2342
2343
2344 /* The file is not in a child directory of the current directory, so we
2345 * need to step back the appropriate number of parent directories by
2346 * using "..\"s. First find out how many levels deeper we are than the
2347 * common directory
2348 */
2349 afMarker = i;
2350 levels = 1;
2351
2352 /* count the number of directory levels we have to go up to get to the
2353 * common directory
2354 */
2355 while(i < cdLen)
2356 {
2357 i++;
2358 if(currentDirectory[i] == SLASH)
2359 {
2360 /* make sure it's not a trailing slash */
2361 i++;
2362 if(currentDirectory[i] != '\0')
2363 {
2364 levels++;
2365 }
2366 }
2367 }
2368
2369 /* move the absolute filename marker back to the start of the directory name
2370 * that it has stopped in.
2371 */
2372 while(afMarker > 0 && absoluteFilename[afMarker-1] != SLASH)
2373 {
2374 afMarker--;
2375 }
2376
2377 /* check that the result will not be too long */
2378 if(levels * 3 + afLen - afMarker > MAX_FILENAME_LEN)
2379 {
2380 return(NULL);
2381 }
2382
2383 /* add the appropriate number of "..\"s. */
2384 rfMarker = 0;
2385 *dotdot_levels = levels;
2386 for(i = 0; i < levels; i++)
2387 {
2388 relativeFilename[rfMarker++] = '.';
2389 relativeFilename[rfMarker++] = '.';
2390 relativeFilename[rfMarker++] = SLASH;
2391 }
2392
2393 /* copy the rest of the filename into the result string */
2394 strcpy(&relativeFilename[rfMarker], &absoluteFilename[afMarker]);
2395
2396 return(relativeFilename);
2397 }
2398
2399 /******************************************************************/
2400
2401 #ifdef __MINGW32__
find_dumpfile_scrub_slashes(char * s)2402 static void find_dumpfile_scrub_slashes(char *s)
2403 {
2404 if(s)
2405 {
2406 while(*s)
2407 {
2408 if(*s == '/') *s = '\\';
2409 s++;
2410 }
2411 }
2412 }
2413 #else
find_dumpfile_scrub_slashes(char * s)2414 static void find_dumpfile_scrub_slashes(char *s)
2415 {
2416 if(s)
2417 {
2418 if(s[0] && s[1] && s[2] && (s[1] == ':') && (s[2] == '\\'))
2419 {
2420 while(*s)
2421 {
2422 if(*s == '\\') *s = '/';
2423 s++;
2424 }
2425 }
2426 }
2427 }
2428 #endif
2429
2430
find_dumpfile_2(char * orig_save,char * orig_dump,char * this_save)2431 char *find_dumpfile_2(char *orig_save, char *orig_dump, char *this_save)
2432 {
2433 char *synth_nam = NULL;
2434
2435 if(orig_save && orig_dump && this_save)
2436 {
2437 char *dup_orig_save;
2438 char *rhs_orig_save_slash;
2439 char *grf = NULL;
2440 int dotdot_levels = 0;
2441
2442 find_dumpfile_scrub_slashes(orig_save);
2443 find_dumpfile_scrub_slashes(orig_dump);
2444 find_dumpfile_scrub_slashes(this_save);
2445
2446 dup_orig_save = strdup_2(orig_save);
2447 rhs_orig_save_slash = strrchr(dup_orig_save, SLASH);
2448
2449 if(rhs_orig_save_slash)
2450 {
2451 *rhs_orig_save_slash = 0;
2452 grf =GetRelativeFilename(dup_orig_save, orig_dump, &dotdot_levels);
2453 if(grf)
2454 {
2455 char *dup_this_save = strdup_2(this_save);
2456 char *rhs_this_save_slash = strrchr(dup_this_save, SLASH);
2457 char *p = dup_this_save;
2458 int levels = 0;
2459
2460 if(rhs_this_save_slash)
2461 {
2462 *(rhs_this_save_slash+1) = 0;
2463
2464 while(*p)
2465 {
2466 if(*p == SLASH) levels++;
2467 p++;
2468 }
2469
2470 if(levels > dotdot_levels) /* > because we left the ending slash on dup_this_save */
2471 {
2472 synth_nam = malloc_2(strlen(dup_this_save) + strlen(grf) + 1);
2473 strcpy(synth_nam, dup_this_save);
2474 strcat(synth_nam, grf);
2475 }
2476 }
2477
2478 free_2(dup_this_save);
2479 }
2480
2481 }
2482
2483 free_2(dup_orig_save);
2484 }
2485
2486 return(synth_nam);
2487 }
2488
2489
find_dumpfile(char * orig_save,char * orig_dump,char * this_save)2490 char *find_dumpfile(char *orig_save, char *orig_dump, char *this_save)
2491 {
2492 char *dfile = NULL;
2493
2494 dfile = find_dumpfile_2(orig_save, orig_dump, this_save);
2495 if(!dfile && orig_save && orig_dump)
2496 {
2497 const char *pfx = "/././";
2498 int pfxlen = strlen(pfx);
2499 char *orig_save2 = malloc_2(strlen(orig_save) + pfxlen + 1);
2500 char *orig_dump2 = malloc_2(strlen(orig_dump) + pfxlen + 1);
2501
2502 strcpy(orig_save2, pfx); strcat(orig_save2, orig_save);
2503 strcpy(orig_dump2, pfx); strcat(orig_dump2, orig_dump);
2504
2505 dfile = find_dumpfile_2(orig_save2, orig_dump2, this_save);
2506 if(!dfile)
2507 {
2508 free_2(orig_dump2);
2509 free_2(orig_save2);
2510 }
2511 }
2512
2513 return(dfile);
2514 }
2515
2516 /******************************************************************/
2517
2518 /*
2519 * deliberately kept outside of GLOBALS control
2520 */
2521 struct finder_file_chain
2522 {
2523 struct finder_file_chain *next;
2524 unsigned queue_warning_presented : 1;
2525 unsigned save_file_only : 1;
2526 char *name;
2527 };
2528
2529 static struct finder_file_chain *finder_name_integration = NULL;
2530
2531 /*
2532 * called in timer routine
2533 */
process_finder_names_queued(void)2534 gboolean process_finder_names_queued(void)
2535 {
2536 return(finder_name_integration != NULL);
2537 }
2538
process_finder_extract_queued_name(void)2539 char *process_finder_extract_queued_name(void)
2540 {
2541 struct finder_file_chain *lc = finder_name_integration;
2542 while(lc)
2543 {
2544 if(!lc->queue_warning_presented)
2545 {
2546 lc->queue_warning_presented = 1;
2547 return(lc->name);
2548 }
2549
2550 lc = lc->next;
2551 }
2552
2553 return(NULL);
2554 }
2555
process_finder_name_integration(void)2556 gboolean process_finder_name_integration(void)
2557 {
2558 static int is_working = 0;
2559 struct finder_file_chain *lc = finder_name_integration;
2560 struct finder_file_chain *lc_next;
2561
2562 if(lc && !is_working)
2563 {
2564 is_working = 1;
2565 finder_name_integration = NULL; /* placed here to avoid race conditions with GLOBALS */
2566
2567 while(lc)
2568 {
2569 char *lcname = lc->name;
2570 int try_to_load_file = 1;
2571 int reload_save_file = 0;
2572 char *dfn = NULL;
2573 char *sfn = NULL;
2574 char *fdf = NULL;
2575 FILE *f;
2576 off_t dumpsiz = -1;
2577 time_t dumptim = -1;
2578 int optimize_vcd = 0;
2579
2580 if ((suffix_check(lcname, ".sav")) || (suffix_check(lcname, ".gtkw")))
2581 {
2582 reload_save_file = 1;
2583 try_to_load_file = 0;
2584
2585 if(!lc->save_file_only)
2586 {
2587 read_save_helper(lcname, &dfn, &sfn, &dumpsiz, &dumptim, &optimize_vcd);
2588
2589 if(dfn)
2590 {
2591 char *old_dfn = dfn;
2592 dfn = wave_alloca(strlen(dfn)+1); /* as context can change on file load */
2593 strcpy(dfn, old_dfn);
2594 free_2(old_dfn);
2595 }
2596
2597 if(sfn)
2598 {
2599 char *old_sfn = sfn;
2600 sfn = wave_alloca(strlen(sfn)+1); /* as context can change on file load */
2601 strcpy(sfn, old_sfn);
2602 free_2(old_sfn);
2603 }
2604
2605
2606 #if defined __USE_BSD || defined __USE_XOPEN_EXTENDED || defined __CYGWIN__ || defined HAVE_REALPATH
2607 if(dfn && sfn)
2608 {
2609 char *can = realpath_2(lcname, NULL);
2610 char *old_fdf = find_dumpfile(sfn, dfn, can);
2611
2612 free(can);
2613 fdf = wave_alloca(strlen(old_fdf)+1);
2614 strcpy(fdf, old_fdf);
2615 free_2(old_fdf);
2616
2617 f = fopen(fdf, "rb");
2618 if(f)
2619 {
2620 fclose(f);
2621 lcname = fdf;
2622 try_to_load_file = 1;
2623 }
2624 }
2625 #endif
2626
2627 if(dfn && !try_to_load_file)
2628 {
2629 f = fopen(dfn, "rb");
2630 if(f)
2631 {
2632 fclose(f);
2633 lcname = dfn;
2634 try_to_load_file = 1;
2635 }
2636 }
2637 }
2638 }
2639
2640 if(try_to_load_file)
2641 {
2642 int plen = strlen(lcname);
2643 char *fni = wave_alloca(plen + 32); /* extra space for message */
2644
2645 sprintf(fni, "Loading %s...", lcname);
2646 wave_gtk_window_set_title(GTK_WINDOW(GLOBALS->mainwindow), fni, GLOBALS->dumpfile_is_modified ? WAVE_SET_TITLE_MODIFIED: WAVE_SET_TITLE_NONE, 0);
2647
2648 strcpy(fni, lcname);
2649
2650 if(!menu_new_viewer_tab_cleanup_2(fni, optimize_vcd))
2651 {
2652 }
2653 else
2654 {
2655 GLOBALS->dumpfile_is_modified = 0;
2656 #ifdef HAVE_SYS_STAT_H
2657 if((dumpsiz != -1) && (dumptim != -1))
2658 {
2659 struct stat sbuf;
2660 if(!stat(fni, &sbuf))
2661 {
2662 GLOBALS->dumpfile_is_modified = (dumpsiz != sbuf.st_size) || (dumptim != sbuf.st_mtime);
2663 }
2664 }
2665 #endif
2666 }
2667
2668 wave_gtk_window_set_title(GTK_WINDOW(GLOBALS->mainwindow), GLOBALS->winname, GLOBALS->dumpfile_is_modified ? WAVE_SET_TITLE_MODIFIED: WAVE_SET_TITLE_NONE, 0);
2669 }
2670
2671 /* now do save file... */
2672 if(reload_save_file)
2673 {
2674 /* let any possible dealloc get taken up by free_outstanding() */
2675 GLOBALS->filesel_writesave = strdup_2(lc->name);
2676 read_save_helper(GLOBALS->filesel_writesave, NULL, NULL, NULL, NULL, NULL);
2677 wave_gconf_client_set_string("/current/savefile", GLOBALS->filesel_writesave);
2678 }
2679
2680 lc_next = lc->next;
2681 g_free(lc->name);
2682 g_free(lc);
2683 lc = lc_next;
2684 }
2685
2686 is_working = 0;
2687 return(TRUE);
2688 }
2689
2690 return(FALSE);
2691 }
2692
2693 /******************************************************************/
2694
2695 /*
2696 * Integration with Finder...
2697 * cache name and load in later off a timer (similar to caching DnD for quartz...)
2698 */
deal_with_rpc_open_2(const gchar * path,gpointer user_data,gboolean is_save_file_only)2699 gboolean deal_with_rpc_open_2(const gchar *path, gpointer user_data, gboolean is_save_file_only)
2700 {
2701 (void)user_data;
2702
2703 const char *suffixes[] =
2704 {
2705 ".vcd", ".evcd", ".dump",
2706 ".lxt", ".lxt2", ".lx2",
2707 ".vzt",
2708 ".fst",
2709 ".ghw",
2710 #ifdef EXTLOAD_SUFFIX
2711 EXTLOAD_SUFFIX,
2712 #endif
2713 #ifdef AET2_IS_PRESENT
2714 ".aet", ".ae2",
2715 #endif
2716 ".gtkw", ".sav"
2717 };
2718
2719 const int num_suffixes = sizeof(suffixes) / sizeof(const char *);
2720 int i, mat = 0;
2721
2722 for(i=0;i<num_suffixes;i++)
2723 {
2724 mat = suffix_check(path, suffixes[i]);
2725 if(mat) break;
2726 }
2727
2728 if(!mat)
2729 {
2730 /* generates requester "gtkwave-bin could not open files in the 'xxx' format" */
2731 return(FALSE);
2732 }
2733
2734 if(is_save_file_only)
2735 {
2736 struct finder_file_chain *p = g_malloc(sizeof(struct finder_file_chain));
2737 p->name = g_strdup(path);
2738 p->queue_warning_presented = 0;
2739 p->save_file_only = 1;
2740 p->next = finder_name_integration;
2741 finder_name_integration = p;
2742 }
2743 else
2744 {
2745 if(!finder_name_integration)
2746 {
2747 finder_name_integration = g_malloc(sizeof(struct finder_file_chain));
2748 finder_name_integration->name = g_strdup(path);
2749 finder_name_integration->queue_warning_presented = 0;
2750 finder_name_integration->save_file_only = 0;
2751 finder_name_integration->next = NULL;
2752 }
2753 else
2754 {
2755 struct finder_file_chain *p = finder_name_integration;
2756 while(p->next) p = p->next;
2757 p->next = g_malloc(sizeof(struct finder_file_chain));
2758 p->next->queue_warning_presented = 0;
2759 p->next->save_file_only = 0;
2760 p->next->name = g_strdup(path);
2761 p->next->next = NULL;
2762 }
2763 }
2764
2765 return(TRUE);
2766 }
2767
deal_with_rpc_open(const gchar * path,gpointer user_data)2768 gboolean deal_with_rpc_open(const gchar *path, gpointer user_data)
2769 {
2770 return(deal_with_rpc_open_2(path, user_data, FALSE));
2771 }
2772
2773
2774 #ifdef MAC_INTEGRATION
2775
2776 /*
2777 * block termination if in the middle of something important
2778 */
deal_with_termination(GtkosxApplication * app,gpointer user_data)2779 gboolean deal_with_termination(GtkosxApplication *app, gpointer user_data)
2780 {
2781 (void)app;
2782 (void)user_data;
2783
2784 gboolean do_not_terminate = FALSE; /* future expansion */
2785
2786 if(do_not_terminate)
2787 {
2788 status_text("GTKWAVE | Busy, quit signal blocked.\n");
2789 }
2790
2791 return(do_not_terminate);
2792 }
2793
2794
2795 /*
2796 * Integration with Finder...
2797 * cache name and load in later off a timer (similar to caching DnD for quartz...)
2798 */
deal_with_finder_open(GtkosxApplication * app,gchar * path,gpointer user_data)2799 gboolean deal_with_finder_open(GtkosxApplication *app, gchar *path, gpointer user_data)
2800 {
2801 (void)app;
2802
2803 return(deal_with_rpc_open(path, user_data));
2804 }
2805
2806 #endif
2807
2808
suffix_check(const char * s,const char * sfx)2809 int suffix_check(const char *s, const char *sfx)
2810 {
2811 unsigned int sfxlen = strlen(sfx);
2812 return((strlen(s)>=sfxlen)&&(!strcasecmp(s+strlen(s)-sfxlen,sfx)));
2813 }
2814
2815