/* file: pbsqs.h G. Moody 7 February 2012 Last revised: 13 May 2012 ------------------------------------------------------------------------------- Includes, enums, structures, typedefs, macros, constants, externs for pbsqs Copyright (C) 2012 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. You may contact the author by e-mail (george@mit.edu) 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 #include #include #include /* Define LOCAL to read local copies of the PhysioBank Index and the help files for this program. */ #ifdef LOCAL /* The local directory where the PhysioBank Index and help files are kept. */ #define PBROOT "file:///home/physionet/html/physiobank/database/" #else /* The PhysioNet server directory where the Index and help files are kept. */ #define PBROOT "http://physionet.org/physiobank/database/" #endif /* PBI_URL is the URL of the PhysioBank Index. pbsqs reads the latest version of the entire index into idxarray (a buffer in memory) once at startup, using libcurl to get it from the web server. */ #define PBI_URL PBROOT "physiobank-index" /* HELP_URL and SHORT_HELP_URL are user help files for this program. They are read from physionet.org into memory once when first needed. */ #define HELP_URL PBROOT "pbs/pbsqs-help.txt" #define SHORTHELP_URL PBROOT "pbs/pbsqs-short-help.txt" /* Match macros. These accept three arguments: S (subject), C (comparison operator), and P (pattern), and they return 1 (true) if there is a match and 0 (false) otherwise. In a search, one of these macros is invoked for each of the index entries to be tested. The values of S come from successive index entries, and the value of P is the pattern or threshold with which successive values of S are to be compared. The comparison operator must belong to the set of operators in the query_comp enumeration (defined below). Example: NMATCH(1, qc_gt, 0) = 1. */ /* Numeric match */ #define NMATCH(S, C, P) \ ((C == qc_lt && S < P) || \ (C == qc_le && S <= P) || \ (C == qc_eq && S == P) || \ (C == qc_ge && S >= P) || \ (C == qc_gt && S > P) || \ (C == qc_ne && S != P) || \ (C == qc_sim && (10*S >= 9*P && 10*S <= 11*P)) || \ (C == qc_dif && (10*S < 9*P || 10*S > 11*P)) || \ (C == qc_def)) /* String match */ #define SMATCH(S, C, P) \ ((C == qc_eq && strcmp(S, P) == 0) || \ (C == qc_ne && strcmp(S, P) != 0) || \ (C == qc_sim && strstr(S, P) != NULL) || \ (C == qc_dif && strstr(S, P) == NULL) || \ (C == qc_lt && strcmp(S, P) < 0) || \ (C == qc_le && strcmp(S, P) <= 0) || \ (C == qc_ge && strcmp(S, P) >= 0) || \ (C == qc_gt && strcmp(S, P) > 0) || \ (C == qc_def)) /* Case-insensitive string match */ #define SCMATCH(S, C, P) \ ((C == qc_eq && strcasecmp(S, P) == 0) || \ (C == qc_ne && strcasecmp(S, P) != 0) || \ (C == qc_sim && strcasestr(S, P) != NULL) || \ (C == qc_dif && strcasestr(S, P) == NULL) || \ (C == qc_lt && strcasecmp(S, P) < 0) || \ (C == qc_le && strcasecmp(S, P) <= 0) || \ (C == qc_ge && strcasecmp(S, P) >= 0) || \ (C == qc_gt && strcasecmp(S, P) > 0) || \ (C == qc_def)) /* Output macros. These accept 2, 3, or 4 arguments: F (a printf format string), A (output 1), B (output 2), and C (output 3). */ #define OUT2(F, A) \ switch (showlist) { \ case 0: if (r != ie->IX_RECORD) { r = ie->IX_RECORD, matches++; } break; \ case 1: if (r != ie->IX_RECORD) { r = ie->IX_RECORD; matches++; \ if (verbose) { fprintf(ofile, "%s", r); newline(); } } break; \ case 2: matches++; \ if (verbose) { fprintf(ofile, "%s\t" F, ie->IX_RECORD, A); newline(); } \ break; \ } #define OUT3(F, A, B) \ switch (showlist) { \ case 0: if (r != ie->IX_RECORD) { r = ie->IX_RECORD, matches++; } break; \ case 1: if (r != ie->IX_RECORD) { r = ie->IX_RECORD; matches++; \ if (verbose) { fprintf(ofile, "%s", r); newline(); } } break; \ case 2: matches++; \ if (verbose) { fprintf(ofile, "%s\t" F, ie->IX_RECORD, A, B); newline(); } \ break; \ } #define OUT4(F, A, B, C) \ switch (showlist) { \ case 0: if (r != ie->IX_RECORD) { r = ie->IX_RECORD, matches++; } break; \ case 1: if (r != ie->IX_RECORD) { r = ie->IX_RECORD; matches++; \ if (verbose) { fprintf(ofile, "%s", r); newline(); } } break; \ case 2: matches++; \ if (verbose) { fprintf(ofile, "%s\t" F, ie->IX_RECORD, A, B, C); newline(); }\ break; \ } /* Query types */ enum query_type { qt_null, /* no-op */ qt_count, /* request count of matches */ qt_list, /* request list of matches */ qt_long, /* request list of matches and matching fields */ qt_help, /* summarize how to use this program */ qt_exit /* force exit */ }; typedef enum query_type QueryType; /* Query items */ enum query_item { qi_age, /* ival: age */ qi_ann, /* iname: annotator name */ qi_ann_d, /* iname: annotator name, ival: duration */ qi_ann_f, /* iname: annotator name, fval: sampling frequency */ qi_ann_n, /* iname: annotator name, ival: number of annotations */ qi_ant, /* iname: annotation type */ qi_ant_d, /* iname: annotation type,ival: duration */ qi_ant_f, /* iname: annotation type,fval: sampling frequency */ qi_ant_n, /* iname: annotation type,ival: number of annotations */ qi_cls, /* iname: class name */ qi_cls_d, /* iname: class name, ival: duration */ qi_cls_f, /* iname: class name, fval: sampling frequency */ qi_cls_g, /* iname: class name, fval: gain, sval: units */ qi_diag, /* sval: diagnosis */ qi_info, /* sval: info */ qi_med, /* sval: medication */ qi_rec, /* iname: record name */ qi_rec_d, /* iname: record name, ival: duration */ qi_rec_f, /* iname: record name, fval: sampling frequency */ qi_rec_g, /* iname: record name, fval: gain, sval: units */ qi_sex, /* sval: M or F */ qi_sig, /* iname: signal name */ qi_sig_d, /* iname: signal name, ival: duration */ qi_sig_f, /* iname: signal name, fval: sampling frequency */ qi_sig_g /* iname: signal name, fval: gain, sval: units */ }; typedef enum query_item QueryItem; /* Query comparison operators */ enum query_comp { qc_lt, /* < (less than) */ qc_le, /* <= (less than or equal to) */ qc_eq, /* = (equal to) */ qc_ge, /* >= (greater than or equal to) */ qc_gt, /* > (greater than) */ qc_sim, /* ~ (similar to: within 10% for numeric comparisons, contained within for string comparisons) */ qc_dif, /* !~ (different: by >10% for numeric comparisons, not contained within for string comparisons) */ qc_ne, /* != (not equal to) */ qc_def /* ? (defined) */ }; typedef enum query_comp QueryComp; /* Class IDs */ enum class_id { AnnM, /* machine-generated annotations */ AnnR, /* reference annotations [must be last in this group] */ AgeSex, /* age and sex */ Med, /* medications */ Diag, /* diagnoses */ Info, /* other metadata [must be last in this group] */ BP, /* blood pressure */ CO2, /* carbon dioxide [must precede CO] */ CO, /* cardiac output */ ECG, /* electrocardiogram */ EEG, /* electroencephalogram */ EMG, /* electromyogram */ EOG, /* electrooculogram */ EP, /* evoked potential */ Flow, /* air flow */ HR, /* heart rate */ Noise, /* for stress testing */ O2, /* oxygen */ PLETH, /* plethysmogram */ Pos, /* body position */ Resp, /* respiration */ Sound, /* sound */ ST, /* ECG ST segment level */ Status, /* of patient or monitor */ Stim, /* stimulus */ SV, /* stroke volume */ Temp, /* temperature */ Unknown, /* unknown */ INVALID }; typedef enum class_id ClassID; /* Data structure definitions. */ struct ramfile_struct { char *memory; /* in-memory copy of file contents */ size_t size; /* length of file in bytes */ }; typedef struct ramfile_struct RAMFile; struct interval_struct { int tstart; /* elapsed time to start of interval (seconds) */ int tend; /* elapsed time to end of interval (seconds) */ }; typedef struct interval_struct Interval; struct indexentry_struct { char *field[7]; /* pointers to fields (columns) in idximage */ char *units; /* pointer to signal units within field[4] */ int i[4]; /* up to 4 integer parameters */ float f[2]; /* up to 2 floating-point parameters */ } *ie, *ie0, *iee; typedef struct indexentry_struct IndexEntry; /* Index entry element aliases. Those in this group point into idximage. */ #define IX_RECORD field[0] #define IX_CLASS field[1] #define IX_SIGNAL field[2] #define IX_ANAME field[2] #define IX_AGE field[2] #define IX_INFO field[2] #define IX_SEX field[3] #define IX_FREQ field[3] #define IX_GAIN field[4] #define IX_UNITS units #define IX_ANTYPE units #define IX_NANN field[4] #define IX_DUR field[5] #define IX_INTRVLS field[6] /* More index entry element aliases. These are for the int and float params. */ #define IP_CLASST i[0] #define IP_CLASSI i[1] #define IP_AGE i[1] #define IP_ANN i[1] #define IP_FREQ f[0] #define IP_GAIN f[1] #define IP_DUR i[2] #define IP_NINTRVL i[3] struct query_struct { QueryType type; /* qt_null, qt_count, qt_list */ QueryItem item; /* qi_record, qi_age ... */ enum class_id id; /* AnnM, AnnR, BP, ... */ int inst; /* item instance */ QueryComp comp; /* qc_lt, qc_le, ... */ int ival; /* value to be matched (as integer) */ float fval; /* value to be matched (as float) */ char *sval; /* value to be matched (as string) */ char *iname; /* item name */ }; typedef struct query_struct Query; struct classname_struct { ClassID id; char *name; }; typedef struct classname_struct Classname; struct compname_struct { QueryComp id; char *name; }; typedef struct compname_struct Compname; size_t geturl(char *url, RAMFile *rf); void cleanup(void); int parsepbi(void); Query parsequery(char *querystring); int search(Query q); void help(Query q); extern Compname rn[]; extern FILE *ifile, *ofile, *efile; extern RAMFile indeximg; extern int lines, nie, nrec, showlist, verbose;