64#include "match_string.h"
80char *option[N_OPTIONS] = {
94 long optionCode, typeCode;
103 char *sourceColumn, *resultColumn;
104 long optionCode, typeCode;
106 double *baseline, *change;
112long addChangeRequests(
CHANGE_REQUEST **request,
long requests,
char **item,
long items,
long code,
char *excludeName,
char *newType);
115int64_t addBaselineData(
CHANGE_DEFINITION *change,
long changes,
char *baseline,
long page, int64_t lastRows);
122 "sddschanges [<input>] [<output>]\n"
123 " [-pipe=[input][,output]]\n"
124 " -changesIn=[exclude=<wildcard>,][,newType=<string>]<column-names>\n"
125 " [-copy=<column-names>]\n"
126 " [-pass=<column-names>]\n"
127 " [-baseline=<filename>]\n"
128 " [-parallelPages] \n"
130 " [-majorOrder=row|column] \n"
132 " -pipe=[input][,output]\n"
133 " Use standard input/output for input and/or output.\n"
134 " -changesIn=[exclude=<wildcard>,][,newType=<string>,]<column-names>\n"
135 " Specify columns to compute changes for. Optionally exclude certain columns\n"
136 " using wildcards and set a new data type for the resulting change columns.\n"
137 " -copy=<column-names>\n"
138 " Specify columns to copy from the first page of the input to all pages of the output.\n"
139 " By default, only requested changes appear in the output.\n"
140 " -pass=<column-names>\n"
141 " Specify columns to pass through from each page of the input to each page of the output.\n"
142 " By default, only requested changes appear in the output.\n"
143 " -baseline=<filename>\n"
144 " Specify a baseline SDDS file to compute changes against. If not provided,\n"
145 " the first page of the input file is used as the baseline.\n"
147 " When used with -baseline, compares the input and baseline files page-by-page.\n"
148 " Otherwise, compares all input pages to the first page of the baseline data.\n"
150 " By default, empty pages in the input do not appear in the output.\n"
151 " This option ensures that empty pages are emitted to the output.\n"
152 " -majorOrder=row|column\n"
153 " Specify the major order for writing the output file, either row-major or column-major.\n"
154 "Program by Michael Borland. (" __DATE__
" " __TIME__
", SVN revision: " SVN_VERSION
")\n";
156int main(
int argc,
char **argv) {
158 long changes, requests;
160 SCANNED_ARG *scanned;
162 long i_arg, code, parallelPages, keepEmpties, i;
163 int64_t baselineRows, rows, lastRows;
164 char *input, *baseline, *output;
165 unsigned long pipeFlags, majorOrderFlag;
166 char *excludeName = NULL;
168 short columnMajorOrder = -1;
171 argc =
scanargs(&scanned, argc, argv);
176 input = output = baseline = NULL;
179 changes = requests = baselineRows = 0;
181 parallelPages = keepEmpties = 0;
183 for (i_arg = 1; i_arg < argc; i_arg++) {
184 if (scanned[i_arg].arg_type == OPTION) {
186 switch (code =
match_string(scanned[i_arg].list[0], option, N_OPTIONS, 0)) {
187 case SET_MAJOR_ORDER:
189 scanned[i_arg].n_items -= 1;
190 if (scanned[i_arg].n_items > 0 &&
191 (!
scanItemList(&majorOrderFlag, scanned[i_arg].list + 1, &scanned[i_arg].n_items,
192 0,
"row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
193 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL))) {
194 SDDS_Bomb(
"Invalid -majorOrder syntax/values");
196 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
197 columnMajorOrder = 1;
198 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
199 columnMajorOrder = 0;
204 if (scanned[i_arg].n_items < 2) {
205 fprintf(stderr,
"Error: Invalid -%s syntax\n", option[code]);
208 if (code == SET_CHANGESIN) {
211 char *changeOption[2] = {
"exclude",
"newtype"};
212#define CHANGE_EXCLUDE 0
213#define CHANGE_NEWTYPE 1
214#define N_CHANGE_OPTIONS 2
215 excludeName = newTypeName = NULL;
216 for (offset = 1; offset < scanned[i_arg].n_items; offset++) {
217 if ((ptr = strchr(scanned[i_arg].list[offset],
'='))) {
219 switch (
match_string(scanned[i_arg].list[offset], changeOption, N_CHANGE_OPTIONS, 0)) {
233 requests = addChangeRequests(&request, requests, scanned[i_arg].list + offset,
234 scanned[i_arg].n_items - offset, code, excludeName, newTypeName);
236 requests = addChangeRequests(&request, requests, scanned[i_arg].list + 1,
237 scanned[i_arg].n_items - 1, code, NULL, NULL);
241 if (scanned[i_arg].n_items != 2)
246 if (!
processPipeOption(scanned[i_arg].list + 1, scanned[i_arg].n_items - 1, &pipeFlags))
249 case SET_PARALLELPAGES:
252 case SET_KEEPEMPTIES:
256 fprintf(stderr,
"Error: Unknown option '%s' given\n", scanned[i_arg].list[0]);
267 SDDS_Bomb(
"Too many filenames provided");
271 if (parallelPages && !baseline)
272 SDDS_Bomb(
"-parallelPages only makes sense with -baseline");
282 if (!(change = compileChangeDefinitions(&inSet, &changes, request, requests)))
283 SDDS_Bomb(
"Unable to compile definitions");
285 if (!setupOutputFile(&outSet, output, &inSet, change, changes, columnMajorOrder)) {
287 SDDS_Bomb(
"Unable to setup output file");
290 if (baseline && !parallelPages)
291 baselineRows = addBaselineData(change, changes, baseline, 0, 0);
296 if (baseline && parallelPages)
297 baselineRows = addBaselineData(change, changes, baseline, code, lastRows);
298 if (!baseline && code == 1) {
299 baselineRows = copyBaselineData(change, changes, &inSet);
302 if (rows != baselineRows)
303 SDDS_Bomb(
"Number of rows in file changed");
305 computeChanges(change, changes, &inSet, rows);
306 if (rows || keepEmpties)
307 outputChanges(change, changes, &outSet, rows, &inSet);
315 for (i = 0; i < changes; i++) {
316 if (change[i].baseline)
317 free(change[i].baseline);
318 if (change[i].change)
319 free(change[i].change);
335int64_t addBaselineData(
CHANGE_DEFINITION *change,
long changes,
char *baseline,
long page, int64_t lastRows) {
341 if (page == 0 || page == 1) {
346 SDDS_SetError(
"Problem reading (next) page of baseline data file");
349 if (page && code != page)
350 SDDS_Bomb(
"Page mixup in baseline file");
351 for (i = 0; i < changes; i++) {
352 if (change[i].optionCode == SET_CHANGESIN) {
353 if (change[i].baseline) {
355 free(change[i].baseline);
356 change[i].baseline = NULL;
359 fprintf(stderr,
"Problem reading baseline data\n");
362 }
else if (change[i].optionCode == SET_COPY) {
363 if (change[i].copy) {
368 free(change[i].copy);
369 change[i].copy = NULL;
371 if (rows && !(change[i].copy =
SDDS_GetColumn(&dataset, change[i].sourceColumn))) {
372 fprintf(stderr,
"Problem reading baseline data\n");
385 SDDS_Bomb(
"No data in first page of input file");
386 for (i = 0; i < changes; i++) {
387 if (change[i].optionCode == SET_CHANGESIN) {
389 fprintf(stderr,
"Problem reading baseline data\n");
392 }
else if (change[i].optionCode == SET_COPY) {
393 if (!(change[i].copy =
SDDS_GetColumn(dataset, change[i].sourceColumn))) {
394 fprintf(stderr,
"Problem reading baseline data\n");
407 for (i = 0; i < changes; i++) {
408 switch (change[i].optionCode) {
415 fprintf(stderr,
"Problem reading input data\n");
418 if (change[i].change)
419 free(change[i].change);
420 change[i].change = (
double *)
tmalloc(
sizeof(*(change[i].change)) * rows);
421 for (j = 0; j < rows; j++) {
422 change[i].change[j] = data[j] - change[i].baseline[j];
441 for (i = 0; i < changes; i++) {
442 switch (change[i].optionCode) {
448 if (!
SDDS_SetColumn(outSet, SDDS_SET_BY_NAME, change[i].copy, rows, change[i].resultColumn))
453 !
SDDS_SetColumn(outSet, SDDS_SET_BY_NAME, data, rows, change[i].resultColumn))
463long addChangeRequests(
CHANGE_REQUEST **request,
long requests,
char **item,
long items,
long code,
char *excludeName,
char *newTypeName) {
465 *request =
SDDS_Realloc(*request,
sizeof(**request) * (requests + items));
466 for (i = 0; i < items; i++) {
467 (*request)[i + requests].columnName = item[i];
468 (*request)[i + requests].optionCode = code;
469 (*request)[i + requests].excludeName = excludeName;
473 snprintf(buffer,
sizeof(buffer),
"Unknown type given: %s", newTypeName);
477 (*request)[i + requests].typeCode = -1;
480 return items + requests;
485 long iReq, iChange, iName, index;
487 char s[SDDS_MAXLINE];
490 change =
tmalloc(
sizeof(*change) * requests);
491 *changes = iChange = 0;
492 for (iReq = 0; iReq < requests; iReq++) {
493 if (iChange >= *changes)
494 change =
SDDS_Realloc(change,
sizeof(*change) * (*changes += 10));
497 sprintf(s,
"Error: Column '%s' not found in input file", request[iReq].columnName);
501 change[iChange].sourceColumn = request[iReq].columnName;
502 change[iChange].optionCode = request[iReq].optionCode;
503 change[iChange].change = change[iChange].baseline = NULL;
506 fprintf(stderr,
"Error: Column '%s' is non-numeric. Cannot compute changes.\n", change[iChange].sourceColumn);
509 change[iChange].copy = change[iChange].pass = NULL;
510 change[iChange].baseline = change[iChange].change = NULL;
511 change[iChange].newType = request[iReq].typeCode;
517 if (request[iReq].excludeName) {
522 sprintf(s,
"No columns selected for wildcard sequence '%s'", request[iReq].columnName);
526 if (iChange + columnNames > *changes)
527 change =
SDDS_Realloc(change,
sizeof(*change) * (*changes = iChange + columnNames + 10));
528 for (iName = 0; iName < columnNames; iName++) {
529 change[iChange + iName].sourceColumn = columnName[iName];
530 change[iChange + iName].optionCode = request[iReq].optionCode;
531 change[iChange + iName].change = change[iChange + iName].baseline = NULL;
534 fprintf(stderr,
"Error: Column '%s' is non-numeric. Cannot compute changes.\n", change[iChange].sourceColumn);
537 change[iChange].copy = change[iChange].pass = NULL;
538 change[iChange].baseline = change[iChange].change = NULL;
539 change[iChange].newType = request[iReq].typeCode;
541 iChange += columnNames;
547 for (iChange = 0; iChange < *changes; iChange++) {
548 switch (change[iChange].optionCode) {
551 strcpy(s, change[iChange].sourceColumn);
554 sprintf(s,
"ChangeIn%s", change[iChange].sourceColumn);
566 char **parameter = NULL, s[SDDS_MAXLINE];
570 if (columnMajorOrder != -1)
571 outSet->layout.data_mode.column_major = columnMajorOrder;
573 outSet->layout.data_mode.column_major = inSet->layout.data_mode.column_major;
574 if (!transferDefinitions(outSet, inSet, change, changes, SET_CHANGESIN))
576 if (!transferDefinitions(outSet, inSet, change, changes, SET_COPY))
578 if (!transferDefinitions(outSet, inSet, change, changes, SET_PASS))
581 for (i = 0; i < parameters; i++)
584 for (i = 0; i < parameters; i++)
589 sprintf(s,
"Unable to complete setup of output file");
598 char s[SDDS_MAXLINE], *symbol;
600 for (column = 0; column < changes; column++) {
601 if (optionCode != change[column].optionCode)
604 sprintf(s,
"Problem transferring definition of column '%s'", change[column].sourceColumn);
622 sprintf(s,
"Unable to get/modify column '%s' information", change[column].sourceColumn);
628 switch (change[column].optionCode) {
634 sprintf(s,
"ChangeIn[%s]", symbol);
637 SDDS_Bomb(
"Invalid option code in transferDefinitions");
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t SDDS_CopyParameters(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source)
int32_t SDDS_StartPage(SDDS_DATASET *SDDS_dataset, int64_t expected_n_rows)
int32_t SDDS_SetColumnFromDoubles(SDDS_DATASET *SDDS_dataset, int32_t mode, double *data, int64_t rows,...)
Sets the values for a single data column using double-precision floating-point numbers.
int32_t SDDS_SetColumn(SDDS_DATASET *SDDS_dataset, int32_t mode, void *data, int64_t rows,...)
Sets the values for one data column in the current data table of an SDDS dataset.
int32_t SDDS_ChangeColumnInformation(SDDS_DATASET *SDDS_dataset, char *field_name, void *memory, int32_t mode,...)
Modifies a specific field in a column definition within the SDDS dataset.
int32_t SDDS_GetColumnInformation(SDDS_DATASET *SDDS_dataset, char *field_name, void *memory, int32_t mode,...)
Retrieves information about a specified column in the SDDS dataset.
int32_t SDDS_InitializeOutput(SDDS_DATASET *SDDS_dataset, int32_t data_mode, int32_t lines_per_row, const char *description, const char *contents, const char *filename)
Initializes the SDDS output dataset.
int32_t SDDS_WritePage(SDDS_DATASET *SDDS_dataset)
Writes the current data table to the output file.
int32_t SDDS_WriteLayout(SDDS_DATASET *SDDS_dataset)
Writes the SDDS layout header to the output file.
int32_t SDDS_TransferColumnDefinition(SDDS_DATASET *target, SDDS_DATASET *source, char *name, char *newName)
Transfers a column definition from a source dataset to a target dataset.
int32_t SDDS_TransferParameterDefinition(SDDS_DATASET *target, SDDS_DATASET *source, char *name, char *newName)
Transfers a parameter definition from a source dataset to a target dataset.
int32_t SDDS_FreeStringArray(char **string, int64_t strings)
Frees an array of strings by deallocating each individual string.
int32_t SDDS_GetNamedColumnType(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the data type of a column in the SDDS dataset by its name.
void SDDS_SetError(char *error_text)
Records an error message in the SDDS error stack.
char ** SDDS_GetParameterNames(SDDS_DATASET *SDDS_dataset, int32_t *number)
Retrieves the names of all parameters in the SDDS dataset.
int32_t SDDS_GetColumnIndex(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the index of a named column in the SDDS dataset.
char ** SDDS_GetColumnNames(SDDS_DATASET *SDDS_dataset, int32_t *number)
Retrieves the names of all columns in the SDDS dataset.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
int32_t SDDS_IdentifyType(char *typeName)
Identifies the SDDS data type based on its string name.
int32_t SDDS_GetColumnType(SDDS_DATASET *SDDS_dataset, int32_t index)
Retrieves the data type of a column in the SDDS dataset by its index.
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
int32_t SDDS_CopyString(char **target, const char *source)
Copies a source string to a target string with memory allocation.
void * SDDS_Realloc(void *old_ptr, size_t new_size)
Reallocates memory to a new size.
#define SDDS_STRING
Identifier for the string data type.
#define SDDS_NUMERIC_TYPE(type)
Checks if the given type identifier corresponds to any numeric type.
void * tmalloc(uint64_t size_of_block)
Allocates a memory block of the specified size with zero initialization.
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
long match_string(char *string, char **option, long n_options, long mode)
Matches a given string against an array of option strings based on specified modes.
int scanargs(SCANNED_ARG **scanned, int argc, char **argv)
long processPipeOption(char **item, long items, unsigned long *flags)
void processFilenames(char *programName, char **input, char **output, unsigned long pipeFlags, long noWarnings, long *tmpOutputUsed)
void free_scanargs(SCANNED_ARG **scanned, int argc)
long scanItemList(unsigned long *flags, char **item, long *items, unsigned long mode,...)
Scans a list of items and assigns values based on provided keywords and types.
int has_wildcards(char *template)
Check if a template string contains any wildcard characters.