/*************************************************************************\ * Copyright (c) 2002 The University of Chicago, as Operator of Argonne * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. * This file is distributed subject to a Software License Agreement found * in the file LICENSE that is included with this distribution. \*************************************************************************/ /* program: sddschanges * purpose: analyse data from columns of a SDDS file to get changes * from the first page. * * Michael Borland, 1995 $Log: sddschanges.c,v $ Revision 1.19 2006/12/14 22:21:57 soliday Updated a bunch of programs because SDDS_SaveLayout is now called by SDDS_WriteLayout and it is no longer required to be called directly. Also the AutoCheckMode is turned off by default now so I removed calls to SDDS_SetAutoCheckMode that would attempt to turn it off. It is now up to the programmer to turn it on in new programs until debugging is completed and then remove the call to SDDS_SetAutoCheckMode. Revision 1.18 2005/11/07 21:48:10 soliday Updated to remove Linux compiler warnings. Revision 1.17 2005/11/04 22:46:12 soliday Updated code to be compiled by a 64 bit processor. Revision 1.16 2004/06/16 22:08:33 borland Fixed bug that resulted in segmentation violation when the number of rows changed between pages in parallel pages mode, or when there were zero rows. Revision 1.15 2003/10/21 14:52:41 soliday Added the ability to exclude columns that may otherwise be included with a wildcard. Revision 1.14 2003/06/19 18:21:07 borland Added -pass option. This allows the user to ask for data to be passed from the input to the output file. It is different from -copy, which transfers data from the reference page (or file) to each output page. Revision 1.13 2003/06/18 18:35:32 soliday Fixed a problem with multiple pages. Revision 1.12 2002/12/07 00:17:23 borland For backward compatibility, default behavior is not to emit empty pages. To force this, use the new option -keepEmpties. Also, updated and expanded the usage message. Revision 1.11 2002/12/07 00:05:57 borland Pages with zero rows are no longer deleted from the output. If the data and baseline pages both have zero rows, the program no longer exits with an error. Revision 1.10 2002/08/14 17:12:40 soliday Added Open License Revision 1.9 2002/01/16 18:35:46 soliday Added missing SDDS_Terminate functions. Revision 1.8 2001/01/10 19:35:32 soliday Standardized usage message. Revision 1.7 1999/12/05 16:26:24 borland Updated version message. Revision 1.6 1999/12/03 14:28:33 borland Added -parallelPages option, which essentially allows subtracting two files page-by-page. Revision 1.5 1999/05/25 19:05:38 soliday Removed compiler warning on linux. Revision 1.4 1999/01/06 19:54:38 borland Fixed the version number in the usage message. * Revision 1.3 1995/09/06 14:56:09 saunders * First test release of SDDS1.5 * */ #include "mdb.h" #include "scan.h" #include "SDDS.h" #include "match_string.h" #include #define SET_COPY 0 #define SET_CHANGESIN 1 #define SET_PASS 2 #define SET_BASELINE 3 #define SET_PIPE 4 #define SET_PARALLELPAGES 5 #define SET_KEEPEMPTIES 6 #define N_OPTIONS 7 char *option[N_OPTIONS] = { "copy", "changesin", "pass", "baseline", "pipe", "parallelpages", "keepempties", } ; char *optionSuffix[3] = { "", "ChangeIn", "", } ; typedef struct { char *columnName; long optionCode; char *excludeName; } CHANGE_REQUEST; /* this structure stores data necessary for accessing/creating SDDS columns and * for computing a statistic */ typedef struct { char *sourceColumn, *resultColumn; long optionCode; /* these store intermediate values during processing */ double *baseline, *change; void *copy; void *pass; long type; } CHANGE_DEFINITION; long addChangeRequests(CHANGE_REQUEST **request, long requests, char **item, long items, long code, char *excludeName); CHANGE_DEFINITION *compileChangeDefinitions(SDDS_DATASET *inSet, long *changes, CHANGE_REQUEST *request, long requests); long setupOutputFile(SDDS_DATASET *outSet, char *output, SDDS_DATASET *inSet, CHANGE_DEFINITION *change, long changes); long addBaselineData(CHANGE_DEFINITION *change, long changes, char *baseline, long page, long lastRows); long copyBaselineData(CHANGE_DEFINITION *change, long changes, SDDS_DATASET *dataset); void computeChanges(CHANGE_DEFINITION *change, long changes, SDDS_DATASET *inSet, long rows); void outputChanges(CHANGE_DEFINITION *change, long changes, SDDS_DATASET *outSet, long rows, SDDS_DATASET *inSet); long transferDefinitions(SDDS_DATASET *outSet, SDDS_DATASET *inSet, CHANGE_DEFINITION *change, long changes, long optionCode); static char *USAGE="sddschanges [-pipe=[input][,output]] [] []\n\ -changesIn=[exclude=,] [-copy=]\n\ [-baseline= [-parallelPages]] [-keepEmpties]\n\n\ Computes the changes in the named columns from the baseline data or\n\ from the first page. \n\n\ changesIn Specifies list of optionally wildcarded column names for \n\ which to compute changes.\n\ copy Specifies list of optionally wildcarded column names to copy\n\ from the first page of to all pages of . By \n\ default only the requested changes appear in . \n\ pass Specifies list of optionally wildcarded column names to copy\n\ from the each page of to each page of . By \n\ default only the requested changes appear in . \n\ baseline Specifies optional second file from which to take baseline \n\ data for computation of changes. If not given, the first\n\ page of is used as the reference.\n\ parallelPages\n\ Used with -baseline, specifies that and baseline\n\ should be compared page-by-page. Otherwise, is compared\n\ to the first page of the baseline data.\n\ keepEmpties\n\ By default, empty pages in do not appear in .\n\ Giving this option causes empty pages to be emitted to .\n\n\ Program by Michael Borland. (This is version 5, December 6, 2002.)"; int main(int argc, char **argv) { CHANGE_DEFINITION *change; long changes, requests; CHANGE_REQUEST *request; SCANNED_ARG *scanned; /* structure for scanned arguments */ SDDS_DATASET inSet, outSet; long i_arg, code, rows, lastRows, baselineRows, parallelPages, keepEmpties, i; char *input, *baseline, *output; unsigned long pipeFlags; char *excludeName=NULL; char *ptr=NULL; SDDS_RegisterProgramName(argv[0]); argc = scanargs(&scanned, argc, argv); if (argc<3) bomb(NULL, USAGE); input = output = baseline = NULL; change = NULL; request = NULL; changes = requests = baselineRows = 0; pipeFlags = 0; parallelPages = keepEmpties = 0; for (i_arg=1; i_arg0) { rows = SDDS_CountRowsOfInterest(&inSet); if (baseline && parallelPages) baselineRows = addBaselineData(change, changes, baseline, code, lastRows); if (!baseline && code==1) { baselineRows = copyBaselineData(change, changes, &inSet); continue; } if (rows!=baselineRows) SDDS_Bomb("number of rows in file changed"); if (rows) computeChanges(change, changes, &inSet, rows); if (rows || keepEmpties) outputChanges(change, changes, &outSet, rows, &inSet); lastRows = rows; } if (!SDDS_Terminate(&inSet) || !SDDS_Terminate(&outSet)) { SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors); exit(1); } if (change) { for (i = 0; i < changes; i++) { if (change[i].baseline) free(change[i].baseline); if (change[i].change) free(change[i].change); } free(change); } if (input) free(input); if (output) free(output); if (baseline) free(baseline); if (request) free(request); free_scanargs(&scanned,argc); return(0); } long addBaselineData(CHANGE_DEFINITION *change, long changes, char *baseline, long page, long lastRows) { static SDDS_DATASET dataset; long i, rows, code; rows = 0; if (page==0 || page==1) { if (!SDDS_InitializeInput(&dataset, baseline)) SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors|SDDS_EXIT_PrintErrors); } if ((code=SDDS_ReadPage(&dataset))<=0 || (rows = SDDS_CountRowsOfInterest(&dataset))<0) { SDDS_SetError("Problem reading (next) page of baseline data file"); SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors|SDDS_EXIT_PrintErrors); } if (page && code!=page) SDDS_Bomb("page mixup in baseline file"); for (i=0; i1) free(change[i].baseline); change[i].baseline = NULL; } if (rows && !(change[i].baseline=SDDS_GetColumnInDoubles(&dataset, change[i].sourceColumn))) { fprintf(stderr, "problem reading baseline data\n"); SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors|SDDS_EXIT_PrintErrors); } } else if (change[i].optionCode==SET_COPY) { if (change[i].copy) { if (page>1) { if (change[i].type==SDDS_STRING && lastRows) SDDS_FreeStringArray(change[i].copy, lastRows); } free(change[i].copy); change[i].copy = NULL; } if (rows && !(change[i].copy=SDDS_GetColumn(&dataset, change[i].sourceColumn))) { fprintf(stderr, "problem reading baseline data\n"); SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors|SDDS_EXIT_PrintErrors); } } } return rows; } long copyBaselineData(CHANGE_DEFINITION *change, long changes, SDDS_DATASET *dataset) { long i, rows; if (!(rows = SDDS_CountRowsOfInterest(dataset))) SDDS_Bomb("no data in first page of input file"); for (i=0; i=*changes) change = SDDS_Realloc(change, sizeof(*change)*(*changes+=10)); if (!has_wildcards(request[iReq].columnName)) { if ((index=SDDS_GetColumnIndex(inSet, request[iReq].columnName))<0) { sprintf(s, "error: column %s not found input file", request[iReq].columnName); SDDS_SetError(s); SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors|SDDS_EXIT_PrintErrors); } change[iChange].sourceColumn = request[iReq].columnName; change[iChange].optionCode = request[iReq].optionCode; change[iChange].change = change[iChange].baseline = NULL; change[iChange].type = SDDS_GetColumnType(inSet, index); if (change[iChange].optionCode==SET_CHANGESIN && !SDDS_NUMERIC_TYPE(SDDS_GetColumnType(inSet, index))) { fprintf(stderr, "error: column %s is nonnumeric. Can't compute changes.\n", change[iChange].sourceColumn); exit(1); } change[iChange].copy = change[iChange].pass = NULL; change[iChange].baseline = change[iChange].change = NULL; iChange++; } else { SDDS_SetColumnFlags(inSet, 0); if (!SDDS_SetColumnsOfInterest(inSet, SDDS_MATCH_STRING, request[iReq].columnName, SDDS_OR)) SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors|SDDS_EXIT_PrintErrors); if (request[iReq].excludeName) { if (!SDDS_SetColumnsOfInterest(inSet, SDDS_MATCH_STRING, request[iReq].excludeName, SDDS_NEGATE_MATCH|SDDS_AND)) SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors|SDDS_EXIT_PrintErrors); } if (!(columnName = SDDS_GetColumnNames(inSet, &columnNames))) { sprintf(s, "no columns selected for wildcard sequence %s", request[iReq].columnName); SDDS_SetError(s); SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors|SDDS_EXIT_PrintErrors); } if (iChange+columnNames>*changes) change = SDDS_Realloc(change, sizeof(*change)*(*changes=iChange+columnNames+10)); for (iName=0; iName