add g-wrap patch and discussion of it in INSTALL instructions.
[gwave-svn.git] / src / wavelist.c
blob969d362014f418ad587d404872703d75a170da14
1 /*
2 * wavelist.c - part of gwave
3 * routines to handle the scrolling list of potentialy-displayable waveforms,
4 * and other stuff related to loading of data files.
6 * Copyright (C) 1998, 1999 Stephen G. Tell
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public
19 * License along with this software; if not, write to the Free
20 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include <ctype.h>
25 #include <math.h>
26 #include <setjmp.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <errno.h>
33 #include <sys/time.h>
35 #include <gtk/gtk.h>
36 #include <guile-gnome-gobject/gobject.h>
38 #include <config.h>
39 #include <scwm_guile.h>
40 #include <gwave.h>
42 #define WAVELIST_IMPLEMENTATION
43 #include <wavelist.h>
44 #include <wavewin.h>
45 #include <measurebtn.h>
46 #include <dnd.h>
48 GList *wdata_list = NULL;
49 static char file_tag_chars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
50 static const int n_file_tags = sizeof(file_tag_chars)/sizeof(char);
51 static int next_file_tagno = 0;
53 static GtkWidget *create_wavelist_menu(GWDataFile *wdata);
54 void gwfile_add_wv_to_list(gpointer d /*WaveVar* */,
55 gpointer p /*GWDataFile */);
57 void wavelist_button_click(GtkWidget *widget,
58 GdkEventButton *event, gpointer data);
60 XSCM_HOOK(new_wavefile_hook,"new-wavefile-hook", 1, (SCM DF),
61 "This hook is invoked when a new waveform file is successfully loaded."
62 "It is called with the new GWDataFile, DF, as its only argument.");
64 XSCM_HOOK(new_wavelist_hook,"new-wavelist-hook", 1, (SCM DF),
65 "This hook is invoked when the variable list window for a"
66 "GWDataFile is created. The GWDataFile object, DF, is passed as an"
67 "argument. Note that variable-list windows can be created and"
68 "destroyed many times during the life of a GWDataFile. One of the principle"
69 "uses of this hook is creating the menus such for the variable-list window.");
72 * Load a waveform file, adding it to the list of files from which
73 * variables can be chosen to add to the display.
75 GWDataFile *
76 load_wave_file(char *fname, char *ftype)
78 GWDataFile *wdata;
79 SCM swdata;
80 int i;
82 wdata = g_new0(GWDataFile, 1);
83 wdata->wf = wf_read(fname, ftype);
85 if(wdata->wf == NULL) {
86 g_free(wdata);
87 return NULL;
89 wdata->wf->udata = wdata;
91 /* give the file a short (fow now, 1-character) "tag" to identify it
92 * in the menu and variable labels.
94 wdata->ftag = g_new(char, 2);
95 wdata->ftag[0] = file_tag_chars[next_file_tagno];
96 wdata->ftag[1] = '\0';
97 next_file_tagno = (next_file_tagno + 1) % n_file_tags;
98 wdata->ndv = wdata->wf->wf_ndv;
99 wdata->wvhl = NULL; /* empty GSList of WaveVarH* */
101 wdata_list = g_list_append(wdata_list, wdata);
102 wdata->outstanding_smob = 1;
103 SGT_NEWCELL_SMOB(wdata->smob, GWDataFile, wdata);
104 call1_hooks(new_wavefile_hook, wdata->smob);
106 if(wtable->window)
107 cmd_show_wave_list(NULL, wdata);
109 return wdata;
112 SCM_DEFINE(load_wavefile_x, "load-wavefile!", 1, 1, 0, (SCM file, SCM filetype),
113 "Load waveform data from FILE into memory, and make it available for"
114 "display. If FILETYPE is specified, it indicates the format of the file"
115 "and which wavefile reader to use, otherwise the format is inferred"
116 "from the filename and file contents. Returns a GWDataFile object"
117 "which can be used to refer to the loaded data.")
118 #define FUNC_NAME s_load_wavefile_x
120 char *fname, *ftype;
121 GWDataFile *df;
123 VALIDATE_ARG_STR_NEWCOPY(1, file, fname);
124 VALIDATE_ARG_STR_NEWCOPY_USE_NULL(2, filetype, ftype);
125 df = load_wave_file(fname, ftype);
126 g_free(fname);
127 if(ftype)
128 g_free(ftype);
129 if(df)
130 return df->smob;
131 else
132 return SCM_BOOL_F;
134 #undef FUNC_NAME
137 * Delete a wave file.
138 * callback from menu: wavelist->file->delete
140 void
141 delete_wave_file(GtkWidget *w, GWDataFile *wdata)
143 int i;
144 GSList *list;
145 /* remove references from displayed waves */
146 remove_wfile_waves(wdata);
148 /* remove per-file GUI stuff */
149 if(wdata->wlist_win && GTK_WIDGET_VISIBLE(wdata->wlist_win))
150 gtk_widget_destroy(wdata->wlist_win);
152 /* invalidate WaveVar pointers in handles.
153 * Can't free WaveVar because un-GCed smobs may point to them
155 for(list = wdata->wvhl; list; list = list->next) {
156 WaveVarH *wvh = (WaveVarH *)list->data;
157 wvh->wv = NULL;
160 /* now nuke the data */
161 wf_free(wdata->wf);
162 wdata->wf = NULL;
163 wdata_list = g_list_remove(wdata_list, wdata);
165 if(wdata->outstanding_smob) {
166 if(v_flag)
167 fprintf(stderr, "defering free of GWDataFile\n");
168 } else {
169 if(v_flag)
170 fprintf(stderr, "free GWDataFile 0x%x\n", wdata);
171 g_free(wdata);
175 SCM_DEFINE(datafile_delete_x, "wavefile-delete!", 1, 0, 0,
176 (SCM obj),
177 "Delete from memory the waveform data from OBJ.")
178 #define FUNC_NAME s_datafile_delete_x
180 GWDataFile *wdata;
181 VALIDATE_ARG_GWDataFile_COPY(1, obj, wdata);
183 if(wdata->wf)
184 delete_wave_file(NULL, wdata);
185 return SCM_UNSPECIFIED;
187 #undef FUNC_NAME
190 * command or callback from menu: wavelist->file->reload
192 void
193 reload_wave_file(GtkWidget *w, GWDataFile *wdata)
195 int i;
196 WaveFile *new_wf;
197 WaveFile *old_wf;
199 /* FIXME:sgt: get file type from old file, if it was specified
200 * when loading it originaly
202 new_wf = wf_read(wdata->wf->wf_filename, NULL);
203 if(new_wf == NULL) {
204 fprintf(stderr, "reload_wave_file: failed to read %s\n", wdata->wf->wf_filename);
205 /* FIXME:sgt put up error message in window */
206 return;
208 old_wf = wdata->wf;
209 wdata->wf = new_wf;
210 wdata->wf->udata = wdata;
211 /* printf("reload_wave_file(%s) old=%lx new=%lx\n",
212 wdata->wf->wf_filename, old_wf, new_wf); */
214 update_wfile_waves(wdata);
216 /* remove old buttons from list, and add new ones */
217 if(wdata->wlist_win && GTK_WIDGET_VISIBLE(wdata->wlist_win)) {
218 gtk_container_foreach(GTK_CONTAINER(wdata->wlist_box),
219 (GtkCallback) gtk_widget_destroy, NULL);
220 wf_foreach_wavevar(wdata->wf, gwfile_add_wv_to_list, (gpointer)wdata);
223 wf_free(old_wf);
224 mbtn_update_all();
227 void
228 reload_wave_file_w(gpointer p, gpointer d)
230 GWDataFile *wdata = (GWDataFile *)p;
231 reload_wave_file(NULL, wdata);
235 * Reload all files.
236 * plan: replace this with update_all_wave_files(), which checks
237 * file dates/sizes and only reloads those that need it.
239 void
240 reload_all_wave_files(GtkWidget *w)
242 WaveFile *wf;
243 g_list_foreach(wdata_list, reload_wave_file_w, NULL);
246 SCM_DEFINE(reload_all_files_x, "reload-all-files!", 0, 0, 0, (),
247 "Reload all files")
248 #define FUNC_NAME s_reload_all_files_x
250 WaveFile *wf;
251 g_list_foreach(wdata_list, reload_wave_file_w, NULL);
252 return SCM_UNSPECIFIED;
254 #undef FUNC_NAME
256 SCM_DEFINE(datafile_reload_x, "wavefile-reload!", 1, 0, 0,
257 (SCM obj),
258 "Reread the data file for OBJ. Useful for updating the display"
259 " after simulation has been rerun.")
260 #define FUNC_NAME s_datafile_reload_x
262 GWDataFile *wdata;
263 VALIDATE_ARG_GWDataFile_COPY(1, obj, wdata);
265 if(wdata->wf)
266 reload_wave_file(NULL, wdata);
267 return SCM_UNSPECIFIED;
269 #undef FUNC_NAME
272 * Callback for use with wv_foreach_wavevar:
274 * Add a button for each variable in the file to the win_wlist box for it.
275 * Arrange for the buttons to be drag-and-drop sources for placing the
276 * variables into wavepanels.
278 * formerly add_variables_to_list(GWDataFile *wdata)
280 void
281 gwfile_add_wv_to_list(gpointer d, gpointer p)
283 WaveVar *wv = (WaveVar *)d;
284 GWDataFile *wdata = (GWDataFile *)p;
285 int i;
286 GtkWidget *button;
288 if(wv_is_multisweep(wv)) {
289 char lab[4096];
290 sprintf(lab, "%s @ %s=%g", wv->wv_name,
291 wv->wtable->name, wv->wtable->swval);
292 button = gtk_button_new_with_label(lab);
293 } else {
294 button = gtk_button_new_with_label(wv->wv_name);
297 gtk_box_pack_start (GTK_BOX (wdata->wlist_box), button, FALSE, FALSE, 0);
298 gtk_widget_show (button);
300 if(GTK_IS_TOOLTIPS(wtable->ttips))
301 gtk_tooltips_set_tip(GTK_TOOLTIPS(wtable->ttips), button,
302 "Wavefile Variable.\nDrag-and-Drop to a WavePanel.", "");
304 dnd_setup_source(GTK_WINDOW(wdata->wlist_win), button, wv);
306 gtk_signal_connect (GTK_OBJECT(button), "button-press-event",
307 GTK_SIGNAL_FUNC(wavelist_button_click),
308 (gpointer) wv);
312 * Show the variable-list window for a waveform data file.
313 * If the window already exists, simply raise it to the top.
315 void
316 cmd_show_wave_list(GtkWidget *w, GWDataFile *wdata)
318 GtkWidget *box1;
319 GtkWidget *box2;
320 GtkWidget *scrolled_window;
321 GtkWidget *button;
322 GtkWidget *label;
323 int i;
325 if(!wdata) {
326 fprintf(stderr, "cmd_show_wave_list: wdata is NULL");
327 return;
330 if(!wdata->wlist_win) {
331 char buf[256];
333 wdata->wlist_win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
334 gtk_widget_set_name(wdata->wlist_win, "data list window");
335 sprintf(buf, "gwave: %.64s", wdata->wf->wf_filename);
336 gtk_window_set_title(GTK_WINDOW(wdata->wlist_win), buf);
337 gtk_widget_set_usize(wdata->wlist_win, 150, 300);
338 { /* suggest that the window manager try to put the wavelist
339 * window somewhere to the left of the main window.
340 * This nonsense really belongs in a smarter window manager,
341 * but users are demanding somthing.
343 static int diddle=0;
344 int x, y;
345 x = 200+175;
346 y = 200;
347 if(wtable
348 && wtable->window && wtable->window->window) {
349 gdk_window_get_position(wtable->window->window,
350 &x, &y);
351 y += diddle * 25;
352 x -= diddle * 20;
353 diddle = (diddle + 1) % 4;
355 gtk_widget_set_uposition(wdata->wlist_win, x-175, y);
357 gtk_signal_connect (GTK_OBJECT (wdata->wlist_win), "destroy",
358 GTK_SIGNAL_FUNC(gtk_widget_destroyed),
359 &(wdata->wlist_win));
361 box1 = gtk_vbox_new(FALSE, 0);
362 gtk_container_add(GTK_CONTAINER(wdata->wlist_win), box1);
363 gtk_widget_show(box1);
364 wdata->wlist_menubar = gtk_menu_bar_new();
365 gtk_widget_show(wdata->wlist_menubar);
366 gtk_box_pack_start (GTK_BOX (box1), wdata->wlist_menubar, FALSE, FALSE, 0);
368 if(strlen(wdata->wf->wf_filename) > 16) {
369 char *cp = strrchr(wdata->wf->wf_filename, '/');
370 if(cp)
371 sprintf(buf, "%s: .../%.64s", wdata->ftag, cp+1);
372 else
373 sprintf(buf, "%s: .../%.64s", wdata->ftag, wdata->wf->wf_filename);
374 } else {
375 sprintf(buf, "%s: %.64s", wdata->ftag, wdata->wf->wf_filename);
377 label = gtk_label_new(buf);
378 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
379 gtk_widget_show(label);
380 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
384 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
385 gtk_container_border_width (GTK_CONTAINER (scrolled_window), 10);
386 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
387 GTK_POLICY_AUTOMATIC,
388 GTK_POLICY_ALWAYS);
389 GTK_WIDGET_UNSET_FLAGS (GTK_SCROLLED_WINDOW (scrolled_window)->vscrollbar, GTK_CAN_FOCUS);
390 gtk_box_pack_start(GTK_BOX (box1), scrolled_window,
391 TRUE, TRUE, 0);
392 gtk_widget_show (scrolled_window);
394 wdata->wlist_box = gtk_vbox_new (FALSE, 0);
395 gtk_container_border_width (GTK_CONTAINER (wdata->wlist_box), 10);
396 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window),
397 wdata->wlist_box);
398 gtk_container_set_focus_vadjustment(
399 GTK_CONTAINER (wdata->wlist_box),
400 gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scrolled_window)));
401 gtk_widget_show (wdata->wlist_box);
403 dnd_init(wdata->wlist_win);
404 wf_foreach_wavevar(wdata->wf, gwfile_add_wv_to_list, (gpointer)wdata);
406 call1_hooks(new_wavelist_hook, wdata->smob);
408 gtk_widget_show(wdata->wlist_win);
409 } else {
410 gdk_window_raise(wdata->wlist_win->window);
415 * Called for all button presses on wavelist button.
416 * If it is a doubleclick, add variable to the "current" wavepanel immediately.
418 void
419 wavelist_button_click(GtkWidget *widget,
420 GdkEventButton *bevent,
421 gpointer data)
423 WaveVar *dv = (WaveVar *)data;
424 if(bevent->type == GDK_2BUTTON_PRESS) {
425 /* printf("doubleclicked %s %s\n", dv->wfile->ss->filename,
426 dv->sv->name); */
427 add_var_to_panel(NULL, dv);
431 SCM_DEFINE(wavefile_show_listwin_x, "wavefile-show-listwin!", 1, 0, 0,
432 (SCM obj),
433 "Displays the scrolling list of the variables in OBJ, from which they"
434 "can be dragged into a waveform display panel.")
435 #define FUNC_NAME s_wavefile_show_listwin_x
437 GWDataFile *wdata;
438 VALIDATE_ARG_GWDataFile_COPY(1, obj, wdata);
440 if(v_flag)
441 fprintf(stderr, "%s wdata=0x%x\n", FUNC_NAME, wdata);
442 if(wdata->wf)
443 cmd_show_wave_list(NULL, wdata);
444 return SCM_UNSPECIFIED;
447 #undef FUNC_NAME
449 /* maybe I should just expose the GTkWindow itself, and destroy from guile */
450 SCM_DEFINE(wavefile_remove_listwin_x, "wavefile-remove-listwin!", 1, 0, 0,
451 (SCM obj),
452 "Removes the variable-list window for OBJ")
453 #define FUNC_NAME s_wavefile_remove_listwin_x
455 GWDataFile *wdata;
456 VALIDATE_ARG_GWDataFile_COPY(1, obj, wdata);
458 if(wdata->wf && wdata->wlist_win)
459 gtk_widget_destroy(wdata->wlist_win);
460 return SCM_UNSPECIFIED;
463 #undef FUNC_NAME
465 /* Primitives for accessing GWDataFile info from scheme */
467 SCM_DEFINE(wavefile_file_name, "wavefile-file-name", 1, 0, 0,
468 (SCM obj),
469 "Returns the filename from which the GWDataFile OBJ was loaded."
470 "If OBJ is invalid because the datafile has been deleted,"
471 "#f is returned.")
472 #define FUNC_NAME s_wavefile_file_name
474 GWDataFile *wdata;
475 VALIDATE_ARG_GWDataFile_COPY(1, obj, wdata);
477 if(wdata->wf)
478 return scm_makfrom0str(wdata->wf->wf_filename);
479 else
480 return SCM_BOOL_F;
483 #undef FUNC_NAME
485 SCM_DEFINE(wavefile_nsweeps, "wavefile-nsweeps", 1, 0, 0,
486 (SCM df),
487 "Returns the number of sweeps for which data is present in GWDataFile DF.")
488 #define FUNC_NAME s_wavefile_nsweeps
490 GWDataFile *wdata;
491 VALIDATE_ARG_GWDataFile_COPY(1, df, wdata);
493 return scm_long2num(wdata->wf->wf_ntables);
495 #undef FUNC_NAME
497 SCM_DEFINE(wavefile_sweeps, "wavefile-sweeps", 1, 0, 0,
498 (SCM df),
499 "Returns a list of sweeps contained in GWDataFile DF. Each element of the list is a pair, of the form (sweepname . sweepvalue)")
500 #define FUNC_NAME s_wavefile_nsweeps
502 GWDataFile *wdata;
503 SCM result = SCM_EOL;
504 SCM p;
505 WvTable *wt;
506 WaveFile *wf;
507 int i, j;
508 VALIDATE_ARG_GWDataFile_COPY(1, df, wdata);
510 if(!wdata->wf)
511 return result;
513 wf = wdata->wf;
514 for(i = 0; i < wf->wf_ntables; i++) {
515 wt = wf_wtable(wf, i);
516 p = scm_cons(scm_makfrom0str(wt->name), scm_make_real(wt->swval));
517 result = scm_cons(p, result);
519 return scm_reverse(result);
521 #undef FUNC_NAME
523 SCM_DEFINE(wavefile_tag, "wavefile-tag", 1, 0, 0,
524 (SCM obj),
525 "Returns the short identifying tag for the GWDataFile OBJ.")
526 #define FUNC_NAME s_wavefile_tag
528 GWDataFile *wdata;
529 VALIDATE_ARG_GWDataFile_COPY(1, obj, wdata);
531 return scm_makfrom0str(wdata->ftag);
533 #undef FUNC_NAME
535 SCM_DEFINE(wavefile_set_tag_x, "wavefile-set-tag!", 2, 0, 0,
536 (SCM obj, SCM str),
537 "Set the short identifying tag for the GWDataFile OBJ to STR.")
538 #define FUNC_NAME s_wavefile_set_tag_x
540 GWDataFile *wdata;
541 char *s;
542 VALIDATE_ARG_GWDataFile_COPY(1, obj, wdata);
543 VALIDATE_ARG_STR_NEWCOPY(1, str, s);
544 g_free(wdata->ftag);
545 wdata->ftag = s;
546 return SCM_UNSPECIFIED;
547 /* BUG: any visiblewave button labels and wavelist menu entries
548 * won't be affected by the change in ftag */
550 #undef FUNC_NAME
552 SCM_DEFINE(wavefile_listwin_menubar, "wavefile-listwin-menubar", 1, 0, 0,
553 (SCM obj),
554 "Returns the GTK Menubar for the variable-list window of the"
555 " * GWDataFile OBJ, or #f if the window doesn't exist.")
556 #define FUNC_NAME s_wavefile_listwin_menubar
558 GWDataFile *wdata;
559 VALIDATE_ARG_GWDataFile_COPY(1, obj, wdata);
561 if(wdata->wlist_win && wdata->wlist_menubar)
562 return scm_c_gtype_instance_to_scm(GTK_OBJECT(wdata->wlist_menubar));
563 else
564 return SCM_BOOL_F;
566 #undef FUNC_NAME
569 wavefile_to_scm(void *vp)
571 GWDataFile *wdata = (GWDataFile *)vp;
572 return wdata->smob;
576 glist2scm(GList *list, SCM (*toscm)(void*))
578 SCM result = SCM_EOL;
579 while(list) {
580 result = scm_cons(toscm(list->data), result);
581 list = list->next;
583 return result;
586 SCM_DEFINE(wavefile_list, "wavefile-list", 0, 0, 0, (),
587 "Returns a list containing all waveform data files")
588 #define FUNC_NAME s_wavefile_list
590 return glist2scm(wdata_list, wavefile_to_scm);
592 #undef FUNC_NAME
595 SCM_DEFINE(wavefile_all_variables, "wavefile-all-variables", 1, 0, 0, (SCM df),
596 "Returns a list of WaveVars, composed of all variables in the GWDataFile DF.")
597 #define FUNC_NAME s_wavefile_all_variables
599 GWDataFile *wdata;
600 SCM result = SCM_EOL;
601 SCM wvsmob;
603 WaveFile *wf;
604 WvTable *wt;
605 int i, j;
606 VALIDATE_ARG_GWDataFile_COPY(1, df, wdata);
608 if(!wdata->wf)
609 return result;
611 wf = wdata->wf;
612 for(i = 0; i < wf->wf_ntables; i++) {
613 wt = wf_wtable(wf, i);
614 for(j = 0; j < wf->wf_ndv; j++) {
615 WaveVar *wv;
616 WaveVarH *wvh;
617 wv = &wt->dv[j];
618 if(!wv->udata) {
619 wvh = g_new0(WaveVarH, 1);
620 wvh->wv = wv;
621 wvh->df = wdata;
622 wv->udata = wvh;
623 wdata->wvhl = g_slist_prepend(wdata->wvhl, wvh);
624 SGT_NEWCELL_SMOB(wvsmob, WaveVar, wvh);
625 wvh->smob = wvsmob;
626 } else {
627 wvh = (WaveVarH *)wv->udata;
628 wvsmob = wvh->smob;
630 result = scm_cons(wvsmob, result);
633 return scm_reverse(result);
635 #undef FUNC_NAME
638 SCM_DEFINE(wavefile_variable, "wavefile-variable", 3, 0, 0,
639 (SCM df, SCM vname, SCM swindex),
640 "Returns a WaveVar representing the variable named VNAME in sweep/table/segment SWINDEX in the GWDataFile DF. Return #f if there is no variable named VNAME")
641 #define FUNC_NAME s_wavefile_variable
643 GWDataFile *wdata;
644 SCM result = SCM_BOOL_F;
645 char *s;
646 int i;
647 int swp;
648 VALIDATE_ARG_GWDataFile_COPY(1, df, wdata);
649 VALIDATE_ARG_STR_NEWCOPY(2, vname, s);
650 VALIDATE_ARG_INT_MIN_COPY(3, swindex, 0, swp);
652 if(wdata->wf && swp < wdata->wf->wf_ntables) {
653 WaveVar *wv = wf_find_variable(wdata->wf, s, swp);
654 if(wv) {
655 WaveVarH *wvh;
656 if(!wv->udata) {
657 wvh = g_new0(WaveVarH, 1);
658 wvh->wv = wv;
659 wvh->df = wdata;
660 wv->udata = wvh;
661 wdata->wvhl = g_slist_prepend(wdata->wvhl, wvh);
662 SGT_NEWCELL_SMOB(result, WaveVar, wvh);
663 wvh->smob = result;
664 } else {
665 wvh = (WaveVarH *)wv->udata;
666 result = wvh->smob;
670 g_free(s);
671 return result;
673 #undef FUNC_NAME
675 SCM_DEFINE(variable_signame, "variable-signame", 1, 0, 0,
676 (SCM var),
677 "Return the signal name for the variable VAR.")
678 #define FUNC_NAME s_variable_signame
680 WaveVar *wv;
681 VALIDATE_ARG_VisibleWaveOrWaveVar_COPY(1,var,wv);
683 if(wv)
684 return scm_makfrom0str(wv->sv->name);
685 else
686 return SCM_BOOL_F;
688 #undef FUNC_NAME
691 SCM_DEFINE(variable_sweepname, "variable-sweepname", 1, 0, 0,
692 (SCM var),
693 "Return the sweep name or table name for the variable VAR.")
694 #define FUNC_NAME s_variable_sweepname
696 WaveVar *wv;
697 VALIDATE_ARG_VisibleWaveOrWaveVar_COPY(1,var,wv);
699 if(wv)
700 return scm_makfrom0str(wv->wtable->name);
701 else
702 return SCM_BOOL_F;
704 #undef FUNC_NAME
707 SCM_DEFINE(variable_sweepindex, "variable-sweepindex", 1, 0, 0,
708 (SCM var),
709 "Return the sweep table index for the variable VAR. Sweeps/tables are numbered starting with 0. ")
710 #define FUNC_NAME s_variable_sweepindex
712 WaveVar *wv;
713 VALIDATE_ARG_VisibleWaveOrWaveVar_COPY(1,var,wv);
715 if(wv)
716 return scm_long2num(wv->wtable->swindex);
717 else
718 return SCM_BOOL_F;
720 #undef FUNC_NAME
723 SCM_DEFINE(variable_wavefile, "variable-wavefile", 1, 0, 0,
724 (SCM var),
725 "Return the WaveFile that the variable VAR is contained in.")
726 // Really, the GWDataFile smob.
727 #define FUNC_NAME s_variable_wavefile
729 WaveVar *wv;
730 VALIDATE_ARG_VisibleWaveOrWaveVar_COPY(1,var,wv);
732 if(wv) {
733 GWDataFile *df = wvar_gwdatafile(wv);
734 df->outstanding_smob = 1;
735 return df->smob;
736 } else
737 return SCM_BOOL_F;
739 #undef FUNC_NAME
741 SCM_DEFINE(export_variables, "export-variables", 2, 2, 0,
742 (SCM varlist, SCM port, SCM from, SCM to),
743 "Write the data for all variables in VARLIST to PORT in tabular ascii form"
744 "If FROM and TO are specified, writes only data points for which the"
745 "independent variable is between FROM and TO includsive."
746 "All variables in VARLIST must share the same independent variable")
747 #define FUNC_NAME s_export_variables
749 SCM l, v;
750 WaveVar *wv;
751 WaveVar *iv = NULL;
752 double from_val, to_val;
753 int starti, endi, i;
754 double x,y;
755 int idx;
756 char buf[128];
757 SCM_ASYNC_TICK;
758 /* validate varlist and count elements */
759 for (l = varlist; SCM_NNULLP(l); l = SCM_CDR (l)) {
760 v = SCM_CAR(l);
761 VALIDATE_ARG_VisibleWaveOrWaveVar_COPY(1,v,wv);
762 if(!wv) {
763 scm_misc_error(FUNC_NAME, "invalid WaveVar ~s", SCM_LIST1(v));
765 if(iv == NULL)
766 iv = wv->wv_iv;
767 else if(iv != wv->wv_iv) {
768 scm_misc_error(FUNC_NAME, "All WaveVars in VARLIST must relate to the same independent variable", SCM_UNDEFINED);
771 VALIDATE_ARG_DBL_COPY_USE_DEF(3,from,from_val, iv->wds[0].min);
772 VALIDATE_ARG_DBL_COPY_USE_DEF(4,to,to_val, iv->wds[0].max);
774 if(from_val > to_val)
775 return SCM_UNSPECIFIED;
776 starti = wf_find_point(iv, from_val);
777 endi = wf_find_point(iv, to_val);
779 for(i = starti; i <= endi; i++) {
780 x = wds_get_point(&iv->wds[0], i);
781 sprintf(buf, "%g", x);
782 scm_puts(buf, port);
783 for (l = varlist; SCM_NNULLP(l); l = SCM_CDR (l)) {
784 v = SCM_CAR(l);
785 VALIDATE_ARG_VisibleWaveOrWaveVar_COPY(1,v,wv);
786 g_assert(wv); /* should have been checked above */
787 y = wds_get_point(&wv->wds[0], i);
788 sprintf(buf, " %g", y);
789 scm_puts(buf, port);
791 scm_puts("\n", port);
794 return SCM_UNSPECIFIED;
796 #undef FUNC_NAME
799 * On the C side we never free WaveVars without freeing the whole
800 * WaveFile structure. When guile GC's one, we invalidate the pointer
801 * in the handle, and then check to see if we can dump the whole
802 * structure.
803 * Methinks we need a more formal reference-counting scheme instead of
804 * all this ad-hockery.
806 int wavefile_try_free(GWDataFile *wdata)
808 int i, n;
809 if(wdata->outstanding_smob)
810 return 0;
811 if(wdata->wf)
812 return 0;
813 if(wdata->wvhl) /* nonempty list means outstanding handles remain */
814 return 0;
816 if(gwave_debug)
817 printf("free GWDataFile 0x%x during gc\n", wdata);
818 n = wdata->ndv;
819 g_free(wdata);
820 return sizeof(GWDataFile);
823 /* standard SMOB functions for GWDataFile: free, mark, print, GWDataFile? */
824 scm_sizet
825 free_GWDataFile(SCM obj)
827 GWDataFile *wdata =GWDataFile(obj);
828 wdata->outstanding_smob = 0;
829 return wavefile_try_free(wdata);
832 static void mark_GWDataFile_wvh(void *p, void *d)
834 WaveVarH *wvh = (WaveVarH *)p;
835 if(wvh->wv)
836 scm_gc_mark(wvh->smob);
840 mark_GWDataFile(SCM obj)
842 GWDataFile *wdata = GWDataFile(obj);
843 g_slist_foreach(wdata->wvhl, mark_GWDataFile_wvh, NULL);
845 return SCM_BOOL_F;
848 int
849 print_GWDataFile(SCM obj, SCM port, scm_print_state *ARG_IGNORE(pstate))
851 scm_puts("#<GWDataFile ", port);
852 if(GWDataFile(obj)->wf)
853 scm_puts(GWDataFile(obj)->wf->wf_filename, port);
854 else
855 scm_puts("invalid", port);
856 scm_putc('>', port);
857 return 1;
860 SCM_DEFINE(GWDataFile_p, "GWDataFile?", 1, 0, 0,
861 (SCM obj),
862 "Returns #t if OBJ is a gwave data file object, otherwise #f.")
863 #define FUNC_NAME s_GWDataFile_p
865 return SCM_BOOL_FromBool(GWDataFile_P(obj));
867 #undef FUNC_NAME
869 /* standard SMOB functions for WaveVar: free, mark, print, WaveVar? */
871 scm_sizet
872 free_WaveVar(SCM obj)
874 WaveVarH *wvh = WaveVarH(obj);
875 GWDataFile *df;
876 scm_sizet fsize;
877 df = wvh->df;
879 if(gwave_debug)
880 printf("free_WaveVar(wvh=%lx wv=%lx)\n", wvh, wvh->wv);
881 df->wvhl = g_slist_remove(df->wvhl, wvh);
882 fsize = wavefile_try_free(wvh->df);
883 wvh->wv = NULL;
884 wvh->df = NULL;
885 g_free(wvh);
887 return fsize + sizeof(WaveVarH);
891 mark_WaveVar(SCM obj)
893 return SCM_BOOL_F;
896 int
897 print_WaveVar(SCM obj, SCM port, scm_print_state *ARG_IGNORE(pstate))
899 WaveVarH *wvh = WaveVarH(obj);
900 char buf[128];
902 scm_puts("#<WaveVar ", port);
903 if(wvh->wv) {
904 scm_puts(wvh->df->wf->wf_filename, port);
905 scm_puts(",", port);
906 sprintf(buf, "%d", wvh->wv->wtable->swindex);
907 scm_puts(buf,port);
908 scm_puts(",", port);
909 scm_puts(wvh->wv->sv->name, port);
910 scm_puts(",", port);
911 scm_intprint((long)wvh->wv, 16, port);
912 } else
913 scm_puts("invalid", port);
915 scm_putc('>', port);
916 return 1;
919 SCM_DEFINE(WaveVar_p, "WaveVar?", 1, 0, 0,
920 (SCM obj),
921 "Returns #t if OBJ is a wave-file variable object, otherwise #f.")
922 #define FUNC_NAME s_WaveVar_p
924 return SCM_BOOL_FromBool(WaveVarH_P(obj));
926 #undef FUNC_NAME
928 /* guile initialization */
930 MAKE_SMOBFUNS(GWDataFile);
931 MAKE_SMOBFUNS(WaveVar);
933 void init_wavelist()
935 REGISTER_SCWMSMOBFUNS(GWDataFile);
936 REGISTER_SCWMSMOBFUNS(WaveVar);
938 #ifndef SCM_MAGIC_SNARF_INITS
939 #include "wavelist.x"
940 #endif