/* file: rdsamp.c G. Moody 23 June 1983 Last revised: 11 December 2017 ------------------------------------------------------------------------------- rdsamp: Print an arbitrary number of samples from each signal Copyright (C) 1983-2010 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 #include /* values for timeunits */ #define SECONDS 1 #define MINUTES 2 #define HOURS 3 #define TIMSTR 4 #define MSTIMSTR 5 #define SHORTTIMSTR 6 #define HHMMSS 7 #define SAMPLES 8 #define WFDBXMLPROLOG "\n" \ "\n" \ "\n" char *pname; main(argc, argv) int argc; char *argv[]; { char *record = NULL, *search = NULL, *escapify(), *prog_name(); char *invalid, *snfmt, *tfmt, *tnfmt, *tufmt, *vfmt, speriod[16], tustr[16]; int cflag = 0, highres = 0, i, isiglist, nsig, nosig = 0, pflag = 0, s, *sig = NULL, timeunits = SECONDS, vflag = 0, xflag = 0; WFDB_Frequency freq; WFDB_Sample *v; WFDB_Siginfo *si; WFDB_Time from = 0L, maxl = 0L, to = 0L; void help(); pname = prog_name(argv[0]); for (i = 1 ; i < argc; i++) { if (*argv[i] == '-') switch (*(argv[i]+1)) { case 'c': /* output in CSV format */ cflag = 1; break; case 'f': /* starting time */ if (++i >= argc) { (void)fprintf(stderr, "%s: time must follow -f\n", pname); exit(1); } from = i; break; case 'h': /* help requested */ help(); exit(0); break; case 'H': /* select high-resolution mode */ highres = 1; break; case 'l': /* maximum length of output follows */ if (++i >= argc) { (void)fprintf(stderr, "%s: max output length must follow -l\n", pname); exit(1); } maxl = i; break; case 'P': /* output in high-precision physical units */ ++pflag; /* (fall through to case 'p') */ case 'p': /* output in physical units specified */ ++pflag; if (*(argv[i]+2) == 'd') timeunits = TIMSTR; else if (*(argv[i]+2) == 'e') timeunits = HHMMSS; else if (*(argv[i]+2) == 'h') timeunits = HOURS; else if (*(argv[i]+2) == 'm') timeunits = MINUTES; else if (*(argv[i]+2) == 'S') timeunits = SAMPLES; else timeunits = SECONDS; break; case 'r': /* record name */ if (++i >= argc) { (void)fprintf(stderr, "%s: record name must follow -r\n", pname); exit(1); } record = argv[i]; break; case 's': /* signal list follows */ isiglist = i+1; /* index of first argument containing a signal # */ while (i+1 < argc && *argv[i+1] != '-') { i++; nosig++; /* number of elements in signal list */ } if (nosig == 0) { (void)fprintf(stderr, "%s: signal list must follow -s\n", pname); exit(1); } break; case 'S': /* search for valid sample of specified signal */ if (++i >= argc) { (void)fprintf(stderr, "%s: signal name or number must follow -S\n", pname); exit(1); } search = argv[i]; break; case 't': /* end time */ if (++i >= argc) { (void)fprintf(stderr, "%s: time must follow -t\n",pname); exit(1); } to = i; break; case 'v': /* verbose output -- include column headings */ vflag = 1; break; case 'X': /* output in WFDB-XML format */ xflag = cflag = vflag = 1; /* format is CSV inside an XML wrapper */ break; default: (void)fprintf(stderr, "%s: unrecognized option %s\n", pname, argv[i]); exit(1); } else { (void)fprintf(stderr, "%s: unrecognized argument %s\n", pname, argv[i]); exit(1); } } if (record == NULL) { help(); exit(1); } if ((nsig = isigopen(record, NULL, 0)) <= 0) exit(2); if ((v = malloc(nsig * sizeof(WFDB_Sample))) == NULL || (si = malloc(nsig * sizeof(WFDB_Siginfo))) == NULL) { (void)fprintf(stderr, "%s: insufficient memory\n", pname); exit(2); } if ((nsig = isigopen(record, si, nsig)) <= 0) exit(2); for (i = 0; i < nsig; i++) if (si[i].gain == 0.0) si[i].gain = WFDB_DEFGAIN; if (highres) setgvmode(WFDB_HIGHRES); freq = sampfreq(NULL); if (from > 0L && (from = strtim(argv[from])) < 0L) from = -from; if (isigsettime(from) < 0) exit(2); if (to > 0L && (to = strtim(argv[to])) < 0L) to = -to; if (nosig) { /* print samples only from specified signals */ if ((sig = (int *)malloc((unsigned)nosig*sizeof(int))) == NULL) { (void)fprintf(stderr, "%s: insufficient memory\n", pname); exit(2); } for (i = 0; i < nosig; i++) { if ((s = findsig(argv[isiglist+i])) < 0) { (void)fprintf(stderr, "%s: can't read signal '%s'\n", pname, argv[isiglist+i]); exit(2); } sig[i] = s; } nsig = nosig; } else { /* print samples from all signals */ if ((sig = (int *)malloc((unsigned)nsig*sizeof(int))) == NULL) { (void)fprintf(stderr, "%s: insufficient memory\n", pname); exit(2); } for (i = 0; i < nsig; i++) sig[i] = i; } /* Reset 'from' if a search was requested. */ if (search && ((s = findsig(search)) < 0 || (from = tnextvec(s, from)) < 0)) { (void)fprintf(stderr, "%s: can't read signal '%s'\n", pname, search); exit(2); } /* Reset 'to' if a duration limit was specified. */ if (maxl > 0L && (maxl = strtim(argv[maxl])) < 0L) maxl = -maxl; if (maxl && (to == 0L || to > from + maxl)) to = from + maxl; /* Adjust timeunits if starting time or date is undefined. */ if (timeunits == TIMSTR) { char *p = timstr(0L); if (*p != '[') timeunits = HHMMSS; else if (strlen(p) < 16) timeunits = SHORTTIMSTR; else if (freq > 1.0) timeunits = MSTIMSTR; } if (timeunits == HOURS) freq *= 3600.; else if (timeunits == MINUTES) freq *= 60.; /* Set formats for output. */ if (cflag) { /* CSV output selected */ snfmt = ",'%s'"; if (pflag) { /* output in physical units */ switch (timeunits) { case SAMPLES: tnfmt = "'sample interval'"; sprintf(tustr, "'%g sec'", 1./freq); tufmt = tustr; break; case SHORTTIMSTR: tnfmt = "'Time'"; tufmt = "'hh:mm:ss.mmm'"; break; case TIMSTR: tnfmt = "'Time and date'"; tufmt = "'hh:mm:ss dd/mm/yyyy'"; break; case MSTIMSTR: tnfmt = "'Time and date'"; tufmt = "'hh:mm:ss.mmm dd/mm/yyyy'"; break; case HHMMSS: tnfmt = "'Elapsed time'"; tufmt = "'hh:mm:ss.mmm'"; break; case HOURS: tnfmt = "'Elapsed time'"; tufmt = "'hours'"; break; case MINUTES: tnfmt = "'Elapsed time'"; tufmt = "'minutes'"; break; default: case SECONDS: tnfmt = "'Elapsed time'"; tufmt = "'seconds'"; break; } invalid = ",-"; if (pflag > 1) /* output in high-precision physical units */ vfmt = ",%.8lf"; else vfmt = ",%.3lf"; } else { /* output in raw units */ tnfmt = "'sample #'"; tfmt = "%ld"; vfmt = ",%d"; } } else { /* output in tab-separated columns selected */ if (pflag) { /* output in physical units */ switch (timeunits) { case SAMPLES: tnfmt = "sample interval"; sprintf(speriod, "(%g", 1./freq); speriod[10] = '\0'; sprintf(tustr, "%10s sec)", speriod); tufmt = tustr; break; case SHORTTIMSTR: tnfmt = " Time"; tufmt = "(hh:mm:ss.mmm)"; break; case TIMSTR: tnfmt = " Time Date "; tufmt = "(hh:mm:ss dd/mm/yyyy)"; break; case MSTIMSTR: tnfmt = " Time Date "; tufmt = "(hh:mm:ss.mmm dd/mm/yyyy)"; break; case HHMMSS: tnfmt = " Elapsed time"; tufmt = " hh:mm:ss.mmm"; break; case HOURS: tnfmt = " Elapsed time"; tufmt = " (hours)"; break; case MINUTES: tnfmt = " Elapsed time"; tufmt = " (minutes)"; break; default: case SECONDS: tnfmt = " Elapsed time"; tufmt = " (seconds)"; break; } if (pflag > 1) { /* output in high-precision physical units */ snfmt = "\t%15s"; invalid = "\t -"; vfmt = "\t%15.8lf"; } else { snfmt = "\t%7s"; invalid = "\t -"; vfmt = "\t%7.3lf"; } } else { /* output in raw units */ snfmt = "\t%7s"; tnfmt = " sample #"; tfmt = "%15ld"; vfmt = "\t%7d"; } } /* Print WFDB-XML prolog if '-x' option selected. */ if (xflag) { printf(WFDBXMLPROLOG); printf("\n" "%g\n" "%d\n", freq, nsig); } /* Print column headers if '-v' option selected. */ if (vflag) { char *p, *t; int j, l; (void)printf("%s", tnfmt); for (i = 0; i < nsig; i++) { /* Check if a default signal description was provided by looking for the string ", signal " in the desc field. If so, replace it with a shorter string. */ p = si[sig[i]].desc; if (strstr(p, ", signal ")) { char *t; if (t = malloc(10*sizeof(char))) { (void)sprintf(t, "sig %d", sig[i]); p = t; } } if (cflag == 0) { l = strlen(p); if (pflag > 1) { if (l > 15) p += l - 15; } else { if (l > 7) p+= l - 7; } } else p = escapify(p); (void)printf(snfmt, p); } if (xflag) (void)printf(""); (void)printf("\n"); } /* Print data in physical units if '-p' option selected. */ if (pflag) { char *p; /* Print units as a second line of column headers if '-v' selected. */ if (vflag) { char s[12]; if (xflag) (void)printf(""); (void)printf("%s", tufmt); for (i = 0; i < nsig; i++) { p = si[sig[i]].units; if (p == NULL) p = "mV"; if (cflag == 0) { char ustring[16]; int len; len = strlen(p); if (pflag > 1) { if (len > 13) len = 13; } else if (len > 5) len = 5; ustring[0] = '('; strncpy(ustring+1, p, len); ustring[len+1] = '\0'; (void)printf(pflag > 1 ? "\t%14s)" : "\t%6s)", ustring); } else { p = escapify(p); (void)printf(",'%s'", p); } } if (xflag) (void)printf(""); (void)printf("\n"); } if (xflag) (void)printf("\n"); while ((to == 0L || from < to) && getvec(v) >= 0) { if (cflag == 0) { switch (timeunits) { case TIMSTR: (void)printf("%s", timstr(-from)); break; case SHORTTIMSTR: case MSTIMSTR: (void)printf("%s", mstimstr(-from)); break; case HHMMSS: (void)printf("%15s", from == 0L ? "0:00.000" : mstimstr(from)); break; case SAMPLES: (void)printf("%15ld", from); break; default: case SECONDS: (void)printf("%15.3lf",(double)from/freq); break; case MINUTES: (void)printf("%15.5lf",(double)from/freq); break; case HOURS: (void)printf("%15.7lf",(double)from/freq); break; } } else { switch (timeunits) { case TIMSTR: for (p = timstr(-from); *p == ' '; p++) ; (void)printf("'%s'", p); break; case SHORTTIMSTR: case MSTIMSTR: for (p = mstimstr(-from); *p == ' '; p++) ; (void)printf("'%s'", p); break; case HHMMSS: if (from == 0L) printf("'0:00.000'"); else { for (p = mstimstr(from); *p == ' '; p++) ; (void)printf("'%s'", p); break; } break; case SAMPLES: (void)printf("%ld", from); break; default: case SECONDS: (void)printf("%.3lf",(double)from/freq); break; case MINUTES: (void)printf("%.5lf",(double)from/freq); break; case HOURS: (void)printf("%.7lf",(double)from/freq); break; } } from++; for (i = 0; i < nsig; i++) { if (v[sig[i]] != WFDB_INVALID_SAMPLE) (void)printf(vfmt, ((double)v[sig[i]] - si[sig[i]].baseline)/si[sig[i]].gain); else (void)printf("%s", invalid); } (void)printf("\n"); } } else { /* output in raw units */ if (xflag) (void)printf("\n"); while ((to == 0L || from < to) && getvec(v) >= 0) { (void)printf(tfmt, from++); for (i = 0; i < nsig; i++) (void)printf(vfmt, v[sig[i]]); (void)printf("\n"); } } if (xflag) /* print trailer if WFDB-XML output was selected */ printf("\n\n"); exit(0); } char *escapify(char *s) { char *p = s, *q = s, *r; int c = 0; while (*p) { if (*p == '\'' || *p == '\\') c++; p++; } if (c > 0 && (p = r = calloc(p-s+c, sizeof(char))) != NULL) { while (*q) { if (*q == '\'' || *q == '\\') *q++ = '\\'; *p++ = *q; } q = r; } return (q); } char *prog_name(s) char *s; { char *p = s + strlen(s); #ifdef MSDOS while (p >= s && *p != '\\' && *p != ':') { if (*p == '.') *p = '\0'; /* strip off extension */ if ('A' <= *p && *p <= 'Z') *p += 'a' - 'A'; /* convert to lower case */ p--; } #else while (p >= s && *p != '/') p--; #endif return (p+1); } static char *help_strings[] = { "usage: %s -r RECORD [OPTIONS ...]\n", "where RECORD is the name of the input record, and OPTIONS may include:", " -c use CSV (comma-separated value) output format", " -f TIME begin at specified time", " -h print this usage summary", " -H read multifrequency signals in high resolution mode", " -l INTERVAL truncate output after the specified time interval (hh:mm:ss)", " -p print times and samples in physical units (default: raw units)", " -P same as -p, but with greater precision", " -p and -P may be followed by a character to choose a time", " format; choices are:", " -pd (or -Pd) print time of day and date if known", " -pe (or -Pe) print elapsed time as ::", " -ph (or -Ph) print elapsed time in hours", " -pm (or -Pm) print elapsed time in minutes", " -ps (or -Ps) print elapsed time in seconds", " -pS (or -PS) print elapsed time in sample intervals", " -s SIGNAL [SIGNAL ...] print only the specified signal(s)", " -S SIGNAL search for a valid sample of the specified SIGNAL at or after", " the time specified with -f, and begin printing then", " -t TIME stop at specified time", " -v print column headings", " -X output in WFDB-XML format", NULL }; void help() { int i; (void)fprintf(stderr, help_strings[0], pname); for (i = 1; help_strings[i] != NULL; i++) (void)fprintf(stderr, "%s\n", help_strings[i]); }