/* file: analyze.c G. Moody 10 August 1990 Last revised: 26 November 2001 Functions for the analysis panel of WAVE ------------------------------------------------------------------------------- WAVE: Waveform analyzer, viewer, and editor Copyright (C) 2001 George B. Moody This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . You may contact the author by e-mail (wfdb@physionet.org) or postal mail (MIT Room E25-505A, Cambridge, MA 02139 USA). For updates to this software, please visit PhysioNet (http://www.physionet.org/). _______________________________________________________________________________ */ #include "wave.h" #include "xvwave.h" #include #include #include #include #include #ifndef MENUDIR #define MENUDIR "/usr/local/lib" #endif #define MENUFILE "wavemenu.def" /* name of the default menu file (to be found in MENUDIR) */ #define MAXLL 1024 /* maximum length of a line in the menu file including continuation lines */ void do_analysis(), edit_menu_file(), set_signal(), set_start(), set_stop(), set_back(), set_ahead(), set_siglist(), set_siglist_from_string(), show_command_window(), add_signal_choice(), delete_signal_choice(); char *wavemenu; Frame analyze_frame, tty_frame; Panel analyze_panel; Panel_item start_item, astart_item, dstart_item, end_item, aend_item, dend_item, signal_item, signal_name_item, siglist_item; Termsw tty; int analyze_popup_active = -1; struct MenuEntry { char *label; char *command; struct MenuEntry *nme; } menu_head, *mep; static char *menudir; char *print_command = NULL; int menu_read = 0; void print_proc() { char default_print_command[256]; void read_menu(); if (menu_read == 0) read_menu(); if (print_command == NULL) { sprintf(default_print_command, "echo $RECORD $LEFT-$RIGHT |\ pschart -a $ANNOTATOR -g -l -L -n 0 -R -t 20 -v 8 - | %s\n", psprint); print_command = default_print_command; } do_command(print_command); } char *open_url_command = NULL; void open_url() { char default_open_url_command[256]; void read_menu(); if (menu_read == 0) read_menu(); if (open_url_command == NULL) { sprintf(default_open_url_command, "url_view $URL\n"); open_url_command = default_open_url_command; } do_command(open_url_command); } void read_menu() { char linebuf[MAXLL+1], *p, *p2, *getenv(), *strtok(); int l; FILE *ifile = NULL; /* Record that an attempt has been made to read the menu. */ menu_read = 1; /* Clear the menu entry list. */ mep = &menu_head; mep->label = mep->command = (char *)NULL; mep->nme = (struct MenuEntry *)NULL; /* Try to open the user's menu file, if one is specified. */ if ((wavemenu != NULL || (wavemenu = getenv("WAVEMENU"))) && (ifile = fopen(wavemenu, "r")) == NULL) { #ifdef NOTICE Xv_notice notice = xv_create((Frame)frame, NOTICE, XV_SHOW, TRUE, #else notice_prompt((Frame)frame, (Event *)NULL, #endif NOTICE_MESSAGE_STRINGS, "Can't read menu file:", wavemenu, 0, NOTICE_BUTTON_YES, "Continue", 0); #ifdef NOTICE xv_destroy_safe(notice); #endif } /* If no user menu was specified, try to open "wavemenu" in the current directory. */ if (ifile == NULL && (ifile = fopen("wavemenu", "r")) != NULL) wavemenu = "wavemenu"; /* If the user's file wasn't specified or can't be read, and "wavemenu" can't be read in the current directory, try to open the default menu file. */ if (ifile == NULL) { if ((menudir = getenv("MENUDIR")) == NULL) menudir = MENUDIR; if (wavemenu = malloc(strlen(menudir)+strlen(MENUFILE)+2)) { sprintf(wavemenu, "%s/%s", menudir, MENUFILE); if ((ifile = fopen(wavemenu, "r")) == NULL) { #ifdef NOTICE Xv_notice notice = xv_create((Frame)frame, NOTICE, XV_SHOW, TRUE, #else (void)notice_prompt((Frame)frame, (Event *)NULL, #endif NOTICE_MESSAGE_STRINGS, "Can't read default menu file:", wavemenu, 0, NOTICE_BUTTON_YES, "Continue", 0); #ifdef NOTICE xv_destroy_safe(notice); #endif } free(wavemenu); wavemenu = NULL; } } /* Give up if no menu file can be opened. In this case, commands may still be typed into the tty subwindow directly. */ if (ifile == NULL) return; /* Read the menu file. */ while (fgets(linebuf, MAXLL+1, ifile)) { /* read the next line */ while ((l = strlen(linebuf)) > 1 && l < MAXLL && linebuf[l-2]=='\\' && fgets(&linebuf[l-2], MAXLL+1 - (l-2), ifile)) /* append continuation line(s), if any */ if (linebuf[l-2] == '\t' || linebuf[l-2] == ' ') { /* discard initial whitespace in continuation lines, if any */ char *p, *q; for (p = q = linebuf+l-2; *p == '\t' || *p == ' '; p++) ; while (*p) *q++ = *p++; *q = '\0'; } /* Find the first non-whitespace character (the beginning of the button label). */ for (p = linebuf; *p; p++) { if (*p == '#') { *p = '\0'; break; } else if (*p != ' ' && *p != '\t') break; } /* Skip comments and empty lines. */ if (*p == '\0') continue; /* Find the first embedded tab (the end of the button label). */ for (p2 = p; *p2 && *p2 != '\t'; p2++) ; /* Skip lines without an embedded tab. */ if (*p2 == '\0') continue; *p2++ = '\0'; /* Replace the embedded tab with a null. */ /* Find the next non-whitespace character (the beginning of the command). */ for ( ; *p2 == '\t' || *p2 == ' '; p2++) ; /* Skip lines without a command. */ if (*p2 == '\n') continue; /* Test for special command definition. */ if (strcmp(p, "") == 0) { if (p = (char *)malloc((unsigned)(strlen(p2)+1))) { strcpy(p, p2); print_command = p; } continue; } /* Test for special command definition. */ if (strcmp(p, "") == 0) { if (p = (char *)malloc((unsigned)(strlen(p2)+1))) { strcpy(p, p2); open_url_command = p; } continue; } /* Allocate storage for the menu entry, button label, and command. */ if (!(mep->nme=(struct MenuEntry *)malloc(sizeof(struct MenuEntry))) || !(mep->nme->label = (char *)malloc((unsigned)(strlen(p)+1))) || !(mep->nme->command = (char *)malloc((unsigned)(strlen(p2)+1)))) { #ifdef NOTICE Xv_notice notice = xv_create((Frame)frame, NOTICE, XV_SHOW, TRUE, #else (void)notice_prompt((Frame)frame, (Event *)NULL, #endif NOTICE_MESSAGE_STRINGS, "Out of memory while reading menu file", NOTICE_BUTTON_YES, "Continue", 0); #ifdef NOTICE xv_destroy_safe(notice); #endif mep->nme = NULL; break; } strcpy(mep->nme->label, p); strcpy(mep->nme->command, p2); mep = mep->nme; mep->nme = NULL; } fclose(ifile); } int xaf = -1, yaf = -1; /* Set up analyze menu and terminal emulator windows. */ void create_analyze_popup() { int i; Icon menu_icon, tty_icon; void recreate_analyze_popup(), reload(); if (menu_read == 0) read_menu(); analyze_popup_active = 0; menu_icon = xv_create(XV_NULL, ICON, ICON_IMAGE, icon_image, ICON_LABEL, "Analyze", NULL); analyze_frame = xv_create(frame, FRAME, XV_LABEL, "Analyze", FRAME_ICON, menu_icon, 0); /* if (xaf >= 0 || yaf >= 0) xv_set(analyze_frame, XV_X, xaf, XV_Y, yaf); */ analyze_panel = xv_create(analyze_frame, PANEL, XV_WIDTH, mmx(225), 0); xv_create(analyze_panel, PANEL_BUTTON, PANEL_LABEL_STRING, "<", XV_HELP_DATA, "wave:file.analyze.<", PANEL_NOTIFY_PROC, set_back, 0); start_item = xv_create(analyze_panel, PANEL_TEXT, PANEL_LABEL_STRING, "Start (elapsed): ", XV_HELP_DATA, "wave:file.analyze.start", PANEL_VALUE_DISPLAY_LENGTH, 13, PANEL_CLIENT_DATA, (caddr_t)'e', PANEL_NOTIFY_PROC, set_start, 0); end_item = xv_create(analyze_panel, PANEL_TEXT, PANEL_LABEL_STRING, "End (elapsed): ", XV_HELP_DATA, "wave:file.analyze.end", PANEL_VALUE_DISPLAY_LENGTH, 13, PANEL_CLIENT_DATA, (caddr_t)'e', PANEL_NOTIFY_PROC, set_stop, 0); xv_create(analyze_panel, PANEL_BUTTON, PANEL_LABEL_STRING, ">", XV_HELP_DATA, "wave:file.analyze.<", PANEL_NOTIFY_PROC, set_ahead, 0); signal_item = xv_create(analyze_panel, PANEL_NUMERIC_TEXT, PANEL_LABEL_STRING, "Signal: ", XV_HELP_DATA, "wave:file.analyze.signal", PANEL_VALUE_DISPLAY_LENGTH, 3, PANEL_VALUE, signal_choice, PANEL_MIN_VALUE, 0, PANEL_MAX_VALUE, nsig > 0 ? nsig-1 : 0, PANEL_INACTIVE, nsig > 0 ? FALSE : TRUE, PANEL_NOTIFY_PROC, set_signal, 0); signal_name_item = xv_create(analyze_panel, PANEL_MESSAGE, PANEL_LABEL_STRING, "xxxxxxxxxxxxxx", 0); astart_item= xv_create(analyze_panel, PANEL_TEXT, PANEL_NEXT_ROW, -1, PANEL_LABEL_STRING, "From: ", XV_HELP_DATA, "wave:file.analyze.astart", PANEL_VALUE_DISPLAY_LENGTH, 13, PANEL_CLIENT_DATA, (caddr_t)'a', PANEL_NOTIFY_PROC, set_start, 0); dstart_item= xv_create(analyze_panel, PANEL_TEXT, XV_HELP_DATA, "wave:file.analyze.dstart", PANEL_VALUE_DISPLAY_LENGTH, 11, PANEL_CLIENT_DATA, (caddr_t)'d', PANEL_NOTIFY_PROC, set_start, 0); reset_start(); aend_item= xv_create(analyze_panel, PANEL_TEXT, PANEL_LABEL_STRING, "To: ", XV_HELP_DATA, "wave:file.analyze.aend", PANEL_VALUE_DISPLAY_LENGTH, 13, PANEL_CLIENT_DATA, (caddr_t)'a', PANEL_NOTIFY_PROC, set_stop, 0); dend_item= xv_create(analyze_panel, PANEL_TEXT, XV_HELP_DATA, "wave:file.analyze.dend", PANEL_VALUE_DISPLAY_LENGTH, 13, PANEL_CLIENT_DATA, (caddr_t)'d', PANEL_NOTIFY_PROC, set_stop, 0); reset_stop(); siglist_item = xv_create(analyze_panel, PANEL_TEXT, PANEL_LABEL_STRING, "Signal list: ", XV_HELP_DATA, "wave:file.analyze.signal_list", PANEL_VALUE_DISPLAY_LENGTH, 15, PANEL_VALUE_STORED_LENGTH, 1024, PANEL_INACTIVE, nsig > 0 ? FALSE : TRUE, PANEL_NOTIFY_PROC, set_siglist, 0); reset_siglist(); xv_create(analyze_panel, PANEL_BUTTON, PANEL_NEXT_ROW, -1, PANEL_LABEL_STRING, "Show scope window", XV_HELP_DATA, "wave:file.analyze.show_scope_window", PANEL_NOTIFY_PROC, show_scope_window, 0); xv_create(analyze_panel, PANEL_BUTTON, PANEL_LABEL_STRING, "Show command window", XV_HELP_DATA, "wave:file.analyze.show_command_window", PANEL_NOTIFY_PROC, show_command_window, 0); xv_create(analyze_panel, PANEL_BUTTON, PANEL_LABEL_STRING, "Edit menu", XV_HELP_DATA, "wave:file.analyze.edit_menu", PANEL_NOTIFY_PROC, edit_menu_file, 0); xv_create(analyze_panel, PANEL_BUTTON, PANEL_LABEL_STRING, "Reread menu", XV_HELP_DATA, "wave:file.analyze.reread_menu", PANEL_NOTIFY_PROC, recreate_analyze_popup, 0); xv_create(analyze_panel, PANEL_BUTTON, PANEL_LABEL_STRING, "Reload", XV_HELP_DATA, "wave:file.analyze.reload", PANEL_NOTIFY_PROC, reload, 0); for (i = 0, mep = &menu_head; mep->nme != NULL; mep = mep->nme, i++) { if (i == 0) xv_create(analyze_panel, PANEL_BUTTON, PANEL_NEXT_ROW, -1, PANEL_LABEL_STRING, mep->nme->label, XV_HELP_DATA, "wave:file.analyze.analysis_button", PANEL_NOTIFY_PROC, do_analysis, PANEL_CLIENT_DATA, (caddr_t) i, 0); else xv_create(analyze_panel, PANEL_BUTTON, PANEL_LABEL_STRING, mep->nme->label, XV_HELP_DATA, "wave:file.analyze.analysis_button", PANEL_NOTIFY_PROC, do_analysis, PANEL_CLIENT_DATA, (caddr_t) i, 0); } window_fit(analyze_panel); window_fit(analyze_frame); /* It appears to be necessary to create the signal name item with a dummy value as above to reserve space for it in case signame[signal_choice] is shorter than some other current or future entry in signame[]. Here we reset the value to the correct string. */ xv_set(signal_name_item, PANEL_LABEL_STRING, signame[signal_choice], 0); /* The current version of XView allows us to create a Termsw at most once per process, so we have to be careful not to attempt to execute the following code more than once. */ if (tty == XV_NULL) { int x, y; x = (int)xv_get(analyze_frame, XV_X); y = (int)xv_get(analyze_frame, XV_Y) + (int)xv_get(analyze_frame, XV_HEIGHT) + 75; tty_icon = xv_create(XV_NULL, ICON, ICON_IMAGE, icon_image, ICON_LABEL, "Commands", NULL); tty_frame = xv_create(frame, FRAME, XV_LABEL, "Analysis commands", XV_X, x, XV_Y, y, FRAME_ICON, tty_icon, 0); tty = (Termsw)xv_create(tty_frame, TERMSW, /* XV_X, mmx(1), */ WIN_ROWS, 10, 0); window_fit(tty); window_fit(tty_frame); } } /* Recreate analyze popup (if reread menu button was selected). */ void recreate_analyze_popup() { if (analyze_frame) { xaf = (int)xv_get(analyze_frame, XV_X); yaf = (int)xv_get(analyze_frame, XV_Y); if (xv_destroy_safe(analyze_frame) == XV_OK) { struct MenuEntry *tmep; mep = menu_head.nme; while (mep != NULL) { tmep = mep->nme; free(mep->command); free(mep->label); free(mep); mep = tmep; } menu_read = 0; create_analyze_popup(); xv_set(analyze_frame, WIN_MAP, TRUE, 0); } } } /* Make the analysis menu window appear. */ void analyze_proc() { if (analyze_popup_active < 0) create_analyze_popup(); wmgr_top(tty_frame); xv_set(tty_frame, WIN_MAP, TRUE, 0); wmgr_top(analyze_frame); xv_set(analyze_frame, WIN_MAP, TRUE, 0); analyze_popup_active = 1; } /* Edit the menu file. */ void edit_menu_file() { char *edit_command, *editor, *menu_filename, *getenv(); int clen, elen, result; if ((editor = getenv("EDITOR")) == NULL) editor = defaults_get_string("wave.texteditor", "Wave.TextEditor", EDITOR); elen = strlen(editor); if (wavemenu == NULL) { #ifdef NOTICE Xv_notice notice = xv_create((Frame)frame, NOTICE, XV_SHOW, TRUE, NOTICE_STATUS, &result, #else result = notice_prompt((Frame)frame, (Event *)NULL, #endif NOTICE_MESSAGE_STRINGS, "You are now using the system default menu file,", "which you may not edit directly.", "Press `Copy' to copy it into the current directory", "as `wavemenu' (and remember to set the WAVEMENU", "environment variable next time),", "- or -", "Press `Quit' if you prefer not to edit a menu file.", 0, NOTICE_BUTTON_YES, "Copy", NOTICE_BUTTON_NO, "Quit", 0); #ifdef NOTICE xv_destroy_safe(notice); #endif if (result != NOTICE_YES) return; clen = strlen(menudir) + strlen(MENUFILE) + 4; /* "cp ... " */ if (clen < elen) clen = elen; if (edit_command = malloc(clen + 10)) { /* "wavemenu\n" + null */ sprintf(edit_command, "cp %s/%s wavemenu\n", menudir, MENUFILE); do_command(edit_command); wavemenu = "wavemenu"; } } else edit_command = malloc(elen + strlen(wavemenu) + 3); if (edit_command) { sprintf(edit_command, "%s %s\n", editor, wavemenu); show_command_window(); do_command(edit_command); free(edit_command); } } /* Make the analysis command window appear. */ void show_command_window() { wmgr_top(tty_frame); xv_set(tty_frame, WIN_MAP, TRUE, 0); } /* Set variables needed for analysis routines. */ void set_signal() { signal_choice = (int)xv_get(signal_item, PANEL_VALUE); xv_set(signal_name_item, PANEL_LABEL_STRING, signame[signal_choice], 0); sig_highlight(signal_choice); } void set_signal_choice(i) int i; { int j; if (sig_mode == 0) j = i; else if (0 <= i && i < siglistlen) j = siglist[i]; if (0 <= j && j < nsig) { signal_choice = j; if (analyze_popup_active >= 0) { xv_set(signal_item, PANEL_VALUE, signal_choice, 0); xv_set(signal_name_item, PANEL_LABEL_STRING, signame[signal_choice], 0); } sig_highlight(signal_choice); } } void set_siglist() { set_siglist_from_string((char *)xv_get(siglist_item, PANEL_VALUE)); } void set_siglist_from_string(s) char *s; { char *p; /* Count the number of signals named in the string (s). */ for (p = s, siglistlen = 0; *p; ) { while (*p && (*p == ' ' || *p == '\t')) p++; if (*p) siglistlen++; while (*p && (*p != ' ' && *p != '\t')) p++; } /* Allocate storage for siglist. */ if (siglistlen > maxsiglistlen) { siglist = realloc(siglist, siglistlen * sizeof(int)); base = realloc(base, siglistlen * sizeof(int)); level = realloc(level, siglistlen * sizeof(XSegment)); maxsiglistlen = siglistlen; } /* Now store the signal numbers in siglist. */ for (p = s, siglistlen = 0; *p && siglistlen < maxsiglistlen; ) { while (*p && (*p == ' ' || *p == '\t')) p++; if (*p) siglist[siglistlen++] = atoi(p); while (*p && (*p != ' ' && *p != '\t')) p++; } reset_siglist(); } void set_start(item, event) Panel_item item; Event *event; { struct ap *a; char *start_string, *astart_string, *dstart_string, *p, buf[30]; int i; WFDB_Time t; i = (int)xv_get(item, PANEL_CLIENT_DATA); if (a = get_ap()) { int redraw; redraw = (display_start_time <= begin_analysis_time && begin_analysis_time < display_start_time + nsamp); switch (i) { case 'e': start_string = (char *)xv_get(start_item, PANEL_VALUE); t = strtim(start_string); p = mstimstr(-t); if (*p == '[') { *(p+13) = *(p+24) = '\0'; xv_set(astart_item, PANEL_VALUE, p+1, PANEL_INACTIVE, FALSE, 0); xv_set(dstart_item, PANEL_VALUE, p+14, PANEL_INACTIVE, FALSE, 0); } else { xv_set(astart_item, PANEL_VALUE, "", PANEL_INACTIVE, TRUE, 0); xv_set(dstart_item, PANEL_VALUE, "", PANEL_INACTIVE, TRUE, 0); } break; case 'a': astart_string = (char *)xv_get(astart_item, PANEL_VALUE); dstart_string = (char *)xv_get(dstart_item, PANEL_VALUE); sprintf(buf, "[%s %s]", astart_string, dstart_string); if ((t = -strtim(buf)) <= 0L) { /* tried to set a time before the beginning of the record */ t = 0L; /* go to the beginning instead */ xv_set(start_item, PANEL_VALUE, "beginning", 0); } else xv_set(start_item, PANEL_VALUE, mstimstr(t), 0); set_start(start_item, (Event *)NULL); break; case 'd': dstart_string = (char *)xv_get(dstart_item, PANEL_VALUE); /* changed the date -- try to go to midnight on that date */ sprintf(buf, "[0:0:0 %s]", dstart_string); if ((t = -strtim(buf)) <= 0L) { /* tried to set a time before the beginning of the record */ t = 0L; /* go to the beginning instead */ xv_set(start_item, PANEL_VALUE, "beginning", 0); } else xv_set(start_item, PANEL_VALUE, mstimstr(t), 0); set_start(start_item, (Event *)NULL); break; } a->this.anntyp = BEGIN_ANALYSIS; a->this.subtyp = a->this.num = 0; a->this.chan = 127; a->this.aux = NULL; a->this.time = t; insert_annotation(a); if (redraw || (display_start_time <= begin_analysis_time && begin_analysis_time < display_start_time + nsamp)) { clear_annotation_display(); show_annotations(display_start_time, nsamp); } } } void set_stop(item, event) Panel_item item; Event *event; { struct ap *a; char *end_string, *aend_string, *dend_string, *p, buf[30]; int i; WFDB_Time t; i = (int)xv_get(item, PANEL_CLIENT_DATA); if (a = get_ap()) { int redraw; redraw = (display_start_time <= end_analysis_time && end_analysis_time < display_start_time + nsamp); switch (i) { case 'e': end_string = (char *)xv_get(end_item, PANEL_VALUE); t = strtim(end_string); p = mstimstr(-t); if (*p == '[') { *(p+13) = *(p+24) = '\0'; xv_set(aend_item, PANEL_VALUE, p+1, PANEL_INACTIVE, FALSE, 0); xv_set(dend_item, PANEL_VALUE, p+14, PANEL_INACTIVE, FALSE, 0); } else { xv_set(aend_item, PANEL_VALUE, "", PANEL_INACTIVE, TRUE, 0); xv_set(dend_item, PANEL_VALUE, "", PANEL_INACTIVE, TRUE, 0); } break; case 'a': aend_string = (char *)xv_get(aend_item, PANEL_VALUE); dend_string = (char *)xv_get(dend_item, PANEL_VALUE); sprintf(buf, "[%s %s]", aend_string, dend_string); if ((t = -strtim(buf)) <= 0L) { /* tried to set a time before the beginning of the record */ t = 0L; /* go to the beginning instead */ xv_set(end_item, PANEL_VALUE, "beginning", 0); } else xv_set(end_item, PANEL_VALUE, mstimstr(t), 0); set_stop(end_item, (Event *)NULL); break; case 'd': dend_string = (char *)xv_get(dend_item, PANEL_VALUE); /* changed the date -- try to go to midnight on that date */ sprintf(buf, "[0:0:0 %s]", dend_string); if ((t = -strtim(buf)) <= 0L) { /* tried to set a time before the beginning of the record */ t = 0L; /* go to the beginning instead */ xv_set(end_item, PANEL_VALUE, "beginning", 0); } else xv_set(end_item, PANEL_VALUE, mstimstr(t), 0); set_stop(end_item, (Event *)NULL); break; } a->this.anntyp = END_ANALYSIS; a->this.subtyp = a->this.num = 0; a->this.chan = 127; a->this.aux = NULL; a->this.time = t; insert_annotation(a); if (redraw || (display_start_time <= end_analysis_time && end_analysis_time < display_start_time + nsamp)) { clear_annotation_display(); show_annotations(display_start_time, nsamp); } } } void set_back() { long step = end_analysis_time - begin_analysis_time, t0, t1; if (begin_analysis_time <= 0L || step <= 0L) return; if ((t0 = begin_analysis_time - step) < 0L) t0 = 0L; t1 = t0 + step; xv_set(start_item, PANEL_VALUE, mstimstr(t0), NULL); set_start(start_item, (Event *)NULL); xv_set(end_item, PANEL_VALUE, mstimstr(t1), NULL); set_stop(end_item, (Event *)NULL); } void set_ahead() { long step = end_analysis_time - begin_analysis_time, t0, t1, te = strtim("e"); if ((te > 0L && end_analysis_time >= te) || step <= 0L) return; t0 = begin_analysis_time + step; t1 = t0 + step; xv_set(end_item, PANEL_VALUE, mstimstr(t1), NULL); set_stop(end_item, (Event *)NULL); xv_set(start_item, PANEL_VALUE, mstimstr(t0), NULL); set_start(start_item, (Event *)NULL); } void reset_start() { if (analyze_popup_active >= 0) { char *p; if (begin_analysis_time == -1L) begin_analysis_time = 0L; xv_set(start_item, PANEL_VALUE, begin_analysis_time == 0L ? "beginning" : mstimstr(begin_analysis_time), NULL); p = mstimstr(-begin_analysis_time); if (*p == '[') { *(p+13) = *(p+24) = '\0'; xv_set(astart_item, PANEL_VALUE, p+1, PANEL_INACTIVE, FALSE, 0); xv_set(dstart_item, PANEL_VALUE, p+14, PANEL_INACTIVE, FALSE, 0); } else { xv_set(astart_item, PANEL_VALUE, "", PANEL_INACTIVE, TRUE, 0); xv_set(dstart_item, PANEL_VALUE, "", PANEL_INACTIVE, TRUE, 0); } } } void reset_stop() { if (analyze_popup_active >= 0) { char *p; if (end_analysis_time == -1L) end_analysis_time = strtim("e"); xv_set(end_item, PANEL_VALUE, end_analysis_time == 0L ? "end" : mstimstr(end_analysis_time), NULL); p = mstimstr(-end_analysis_time); if (*p == '[') { *(p+13) = *(p+24) = '\0'; xv_set(aend_item, PANEL_VALUE, p+1, PANEL_INACTIVE, FALSE, 0); xv_set(dend_item, PANEL_VALUE, p+14, PANEL_INACTIVE, FALSE, 0); } else { xv_set(aend_item, PANEL_VALUE, "", PANEL_INACTIVE, TRUE, 0); xv_set(dend_item, PANEL_VALUE, "", PANEL_INACTIVE, TRUE, 0); } } } void reset_siglist() { if (analyze_popup_active >= 0) { char *p; int i; static char *sigliststring; static int maxrssiglistlen; if (siglistlen > maxrssiglistlen) { sigliststring = realloc(sigliststring, 8 * siglistlen); maxrssiglistlen = siglistlen; } p = sigliststring; if (p) *p = '\0'; for (i = 0; i < siglistlen; i++) { sprintf(p, "%d ", siglist[i]); p += strlen(p); } xv_set(siglist_item, PANEL_VALUE, sigliststring, NULL); } if (sig_mode) set_baselines(); } void reset_maxsig() { if (analyze_popup_active >= 0) { xv_set(signal_item, PANEL_INACTIVE, nsig > 0 ? FALSE : TRUE, 0); xv_set(signal_item, PANEL_MAX_VALUE, nsig > 0 ? nsig-1 : 0, 0); if (signal_choice >= nsig || signal_choice < 0) xv_set(signal_item, PANEL_VALUE, signal_choice = 0, 0); xv_set(signal_name_item, PANEL_INACTIVE, nsig > 0 ? FALSE : TRUE, 0); xv_set(signal_name_item, PANEL_LABEL_STRING,signame[signal_choice], 0); } } /* Signal-list manipulation. */ void add_to_siglist(i) int i; { if (0 <= i && i < nsig) { if (++siglistlen >= maxsiglistlen) { siglist = realloc(siglist, siglistlen * sizeof(int)); base = realloc(base, nsig * sizeof(int)); level = realloc(level, nsig * sizeof(XSegment)); maxsiglistlen = siglistlen; } siglist[siglistlen-1] = i; } reset_siglist(); } void delete_from_siglist(i) int i; { int nsl; for (nsl = 0; nsl < siglistlen; nsl++) { if (siglist[nsl] == i) { siglistlen--; for ( ; nsl < siglistlen; nsl++) siglist[nsl] = siglist[nsl+1]; reset_siglist(); } } } void add_signal_choice() { add_to_siglist(signal_choice); } void delete_signal_choice() { delete_from_siglist(signal_choice); } /* This function executes the command string provided as its argument, after substituting for WAVE's internal variables (RECORD, ANNOTATOR, etc.). */ void do_command(p1) char *p1; { char *p2, *tp; post_changes(); /* make sure that the annotation file is up-to-date */ finish_log(); /* make sure that the log file is up-to-date */ if (analyze_popup_active < 0) create_analyze_popup(); for (p2 = p1; *p2; p2++) { if (*p2 == '$') { ttysw_input(tty, p1, p2-p1); p1 = ++p2; if (strncmp(p1, "RECORD", 6) == 0) { ttysw_input(tty, record, strlen(record)); p1 = p2 += 6; } else if (strncmp(p1, "ANNOTATOR", 9) == 0) { if (annotator[0]) ttysw_input(tty, annotator, strlen(annotator)); else ttysw_input(tty, "\"\"", 2); p1 = p2 += 9; } else if (strncmp(p1, "START", 5) == 0) { if (begin_analysis_time != -1L && begin_analysis_time != 0L) { tp = mstimstr(begin_analysis_time); while (*tp == ' ') tp++; } else tp = "0"; ttysw_input(tty, tp, strlen(tp)); p1 = p2 += 5; } else if (strncmp(p1, "END", 3) == 0) { if (end_analysis_time != -1L) tp = mstimstr(end_analysis_time); else if (end_analysis_time == 0L) tp = "0"; else tp = mstimstr(strtim("e")); while (*tp == ' ') tp++; ttysw_input(tty, tp, strlen(tp)); p1 = p2 += 3; } else if (strncmp(p1, "DURATION", 8) == 0) { long t0 = begin_analysis_time, t1 = end_analysis_time; /* If end_analysis_time is unspecified, determine the record length. */ if (t1 == -1L) t1 = strtim("e"); /* If the record length is also unspecified, use zero in place of the duration. Programs that accept duration arguments must be written to accept zero as meaning "unspecified". */ if (t1 == 0L) ttysw_input(tty, "0", 1); else { if (t0 == -1L) t0 = 0L; tp = mstimstr(t1-t0); while (*tp == ' ') tp++; ttysw_input(tty, tp, strlen(tp)); } p1 = p2 += 8; } else if (strncmp(p1, "SIGNALS", 7) == 0) { char s[4]; int nsl; for (nsl = 0; nsl < siglistlen; nsl++) { sprintf(s, "%d%s", siglist[nsl], nsl < siglistlen ? " " : ""); ttysw_input(tty, s, strlen(s)); } p1 = p2 += 7; } else if (strncmp(p1, "SIGNAL", 6) == 0) { char s[3]; sprintf(s, "%d", signal_choice); ttysw_input(tty, s, strlen(s)); p1 = p2 += 6; } else if (strncmp(p1, "LEFT", 4) == 0) { if (display_start_time < 1L) tp = "0"; else { tp = mstimstr(display_start_time); while (*tp == ' ') tp++; } ttysw_input(tty, tp, strlen(tp)); p1 = p2 += 4; } else if (strncmp(p1, "RIGHT", 5) == 0) { tp = mstimstr(display_start_time + nsamp); while (*tp == ' ') tp++; ttysw_input(tty, tp, strlen(tp)); p1 = p2 += 5; } else if (strncmp(p1, "WIDTH", 5) == 0) { tp = mstimstr(nsamp); while (*tp == ' ') tp++; ttysw_input(tty, tp, strlen(tp)); p1 = p2 += 5; } else if (strncmp(p1, "LOG", 3) == 0) { if (*log_file_name == '0') sprintf(log_file_name, "log.%s", record); ttysw_input(tty, log_file_name, strlen(log_file_name)); p1 = p2 += 3; } else if (strncmp(p1, "WFDBCAL", 7) == 0) { ttysw_input(tty, cfname, strlen(cfname)); p1 = p2 += 7; } else if (strncmp(p1, "WFDB", 4) == 0) { ttysw_input(tty, getwfdb(), strlen(getwfdb())); p1 = p2 += 4; } else if (strncmp(p1, "TSCALE", 6) == 0) { char s[10]; sprintf(s, "%g", mmpersec); ttysw_input(tty, s, strlen(s)); p1 = p2 += 6; } else if (strncmp(p1, "VSCALE", 6) == 0) { char s[10]; sprintf(s, "%g", mmpermv); ttysw_input(tty, s, strlen(s)); p1 = p2 += 6; } else if (strncmp(p1, "DISPMODE", 8) == 0) { char s[3]; sprintf(s, "%d", (ann_mode << 1) | show_marker); ttysw_input(tty, s, strlen(s)); p1 = p2 += 8; } else if (strncmp(p1, "PSPRINT", 7) == 0) { ttysw_input(tty, psprint, strlen(psprint)); p1 = p2 += 7; } else if (strncmp(p1, "TEXTPRINT", 7) == 0) { ttysw_input(tty, textprint, strlen(textprint)); p1 = p2 += 9; } else if (strncmp(p1, "URL", 3) == 0) { ttysw_input(tty, url, strlen(url)); p1 = p2 += 3; } else p1--; } } ttysw_input(tty, p1, p2-p1); } void do_analysis(item, event) Panel_item item; Event *event; { char *p1, *p2, *tp; int i, j; i = (int)xv_get(item, PANEL_CLIENT_DATA); for (j=0, mep = &menu_head; jnme != NULL; j++, mep = mep->nme) ; if (j == i && mep->nme != NULL && mep->nme->command != NULL) do_command(mep->nme->command); } static char fname[20]; /* This function gets called once per second while the timer is running. Once the temporary file named by fname contains readable data, it waits one more second, turns off the timer, and then deletes the file. */ Notify_value check_if_done() { FILE *tfile; static int file_ready; void reinitialize(); if (file_ready) { notify_set_itimer_func(analyze_frame, NOTIFY_FUNC_NULL, ITIMER_REAL, NULL, NULL); unlink(fname); file_ready = 0; reinitialize(); set_start(start_item, (Event *)NULL); set_stop(end_item, (Event *)NULL); return (NOTIFY_DONE); } if ((tfile = fopen(fname, "r")) == NULL) return (NOTIFY_DONE); fclose(tfile); file_ready++; return (NOTIFY_DONE); } void reload() { static char command[80]; static struct itimerval timer; if (fname[0] == '\0') { sprintf(fname, "/tmp/wave.XXXXXX"); mkstemp(fname); sprintf(command, "touch %s\n", fname); } do_command(command); timer.it_value.tv_sec = timer.it_interval.tv_sec = 1; notify_set_itimer_func(analyze_frame, check_if_done, ITIMER_REAL, &timer, NULL); }