65#include "match_string.h"
81char *option[N_OPTIONS] = {
95 long optionCode, typeCode;
104 char *sourceColumn, *resultColumn;
105 long optionCode, typeCode;
107 double *baseline, *change;
113long addChangeRequests(
CHANGE_REQUEST **request,
long requests,
char **item,
long items,
long code,
char *excludeName,
char *newType);
116int64_t addBaselineData(
CHANGE_DEFINITION *change,
long changes,
char *baseline,
long page, int64_t lastRows);
123 "Usage: sddschanges [OPTIONS] [<input>] [<output>]\n"
126 " -pipe=[input][,output]\n"
127 " Use standard input/output for input and/or output.\n"
129 " -changesIn=[exclude=<wildcard>,][,newType=<string>,]<column-names>\n"
130 " Specify columns to compute changes for. Optionally exclude certain columns\n"
131 " using wildcards and set a new data type for the resulting change columns.\n"
133 " -copy=<column-names>\n"
134 " Specify columns to copy from the first page of the input to all pages of the output.\n"
135 " By default, only requested changes appear in the output.\n"
137 " -pass=<column-names>\n"
138 " Specify columns to pass through from each page of the input to each page of the output.\n"
139 " By default, only requested changes appear in the output.\n"
141 " -baseline=<filename>\n"
142 " Specify a baseline SDDS file to compute changes against. If not provided,\n"
143 " the first page of the input file is used as the baseline.\n"
146 " When used with -baseline, compares the input and baseline files page-by-page.\n"
147 " 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"
153 " -majorOrder=row|column\n"
154 " Specify the major order for writing the output file, either row-major or column-major.\n"
156 "Program by Michael Borland. (" __DATE__
" " __TIME__
", SVN revision: " SVN_VERSION
")\n";
158int main(
int argc,
char **argv) {
160 long changes, requests;
162 SCANNED_ARG *scanned;
164 long i_arg, code, parallelPages, keepEmpties, i;
165 int64_t baselineRows, rows, lastRows;
166 char *input, *baseline, *output;
167 unsigned long pipeFlags, majorOrderFlag;
168 char *excludeName = NULL;
170 short columnMajorOrder = -1;
173 argc =
scanargs(&scanned, argc, argv);
178 input = output = baseline = NULL;
181 changes = requests = baselineRows = 0;
183 parallelPages = keepEmpties = 0;
185 for (i_arg = 1; i_arg < argc; i_arg++) {
186 if (scanned[i_arg].arg_type == OPTION) {
188 switch (code =
match_string(scanned[i_arg].list[0], option, N_OPTIONS, 0)) {
189 case SET_MAJOR_ORDER:
191 scanned[i_arg].n_items -= 1;
192 if (scanned[i_arg].n_items > 0 &&
193 (!
scanItemList(&majorOrderFlag, scanned[i_arg].list + 1, &scanned[i_arg].n_items,
194 0,
"row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
195 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL))) {
196 SDDS_Bomb(
"Invalid -majorOrder syntax/values");
198 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
199 columnMajorOrder = 1;
200 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
201 columnMajorOrder = 0;
206 if (scanned[i_arg].n_items < 2) {
207 fprintf(stderr,
"Error: Invalid -%s syntax\n", option[code]);
210 if (code == SET_CHANGESIN) {
213 char *changeOption[2] = {
"exclude",
"newtype"};
214#define CHANGE_EXCLUDE 0
215#define CHANGE_NEWTYPE 1
216#define N_CHANGE_OPTIONS 2
217 excludeName = newTypeName = NULL;
218 for (offset = 1; offset < scanned[i_arg].n_items; offset++) {
219 if ((ptr = strchr(scanned[i_arg].list[offset],
'='))) {
221 switch (
match_string(scanned[i_arg].list[offset], changeOption, N_CHANGE_OPTIONS, 0)) {
235 requests = addChangeRequests(&request, requests, scanned[i_arg].list + offset,
236 scanned[i_arg].n_items - offset, code, excludeName, newTypeName);
238 requests = addChangeRequests(&request, requests, scanned[i_arg].list + 1,
239 scanned[i_arg].n_items - 1, code, NULL, NULL);
243 if (scanned[i_arg].n_items != 2)
248 if (!
processPipeOption(scanned[i_arg].list + 1, scanned[i_arg].n_items - 1, &pipeFlags))
251 case SET_PARALLELPAGES:
254 case SET_KEEPEMPTIES:
258 fprintf(stderr,
"Error: Unknown option '%s' given\n", scanned[i_arg].list[0]);
269 SDDS_Bomb(
"Too many filenames provided");
273 if (parallelPages && !baseline)
274 SDDS_Bomb(
"-parallelPages only makes sense with -baseline");
284 if (!(change = compileChangeDefinitions(&inSet, &changes, request, requests)))
285 SDDS_Bomb(
"Unable to compile definitions");
287 if (!setupOutputFile(&outSet, output, &inSet, change, changes, columnMajorOrder)) {
289 SDDS_Bomb(
"Unable to setup output file");
292 if (baseline && !parallelPages)
293 baselineRows = addBaselineData(change, changes, baseline, 0, 0);
298 if (baseline && parallelPages)
299 baselineRows = addBaselineData(change, changes, baseline, code, lastRows);
300 if (!baseline && code == 1) {
301 baselineRows = copyBaselineData(change, changes, &inSet);
304 if (rows != baselineRows)
305 SDDS_Bomb(
"Number of rows in file changed");
307 computeChanges(change, changes, &inSet, rows);
308 if (rows || keepEmpties)
309 outputChanges(change, changes, &outSet, rows, &inSet);
317 for (i = 0; i < changes; i++) {
318 if (change[i].baseline)
319 free(change[i].baseline);
320 if (change[i].change)
321 free(change[i].change);
337int64_t addBaselineData(
CHANGE_DEFINITION *change,
long changes,
char *baseline,
long page, int64_t lastRows) {
343 if (page == 0 || page == 1) {
348 SDDS_SetError(
"Problem reading (next) page of baseline data file");
351 if (page && code != page)
352 SDDS_Bomb(
"Page mixup in baseline file");
353 for (i = 0; i < changes; i++) {
354 if (change[i].optionCode == SET_CHANGESIN) {
355 if (change[i].baseline) {
357 free(change[i].baseline);
358 change[i].baseline = NULL;
361 fprintf(stderr,
"Problem reading baseline data\n");
364 }
else if (change[i].optionCode == SET_COPY) {
365 if (change[i].copy) {
370 free(change[i].copy);
371 change[i].copy = NULL;
373 if (rows && !(change[i].copy =
SDDS_GetColumn(&dataset, change[i].sourceColumn))) {
374 fprintf(stderr,
"Problem reading baseline data\n");
387 SDDS_Bomb(
"No data in first page of input file");
388 for (i = 0; i < changes; i++) {
389 if (change[i].optionCode == SET_CHANGESIN) {
391 fprintf(stderr,
"Problem reading baseline data\n");
394 }
else if (change[i].optionCode == SET_COPY) {
395 if (!(change[i].copy =
SDDS_GetColumn(dataset, change[i].sourceColumn))) {
396 fprintf(stderr,
"Problem reading baseline data\n");
409 for (i = 0; i < changes; i++) {
410 switch (change[i].optionCode) {
417 fprintf(stderr,
"Problem reading input data\n");
420 if (change[i].change)
421 free(change[i].change);
422 change[i].change = (
double *)
tmalloc(
sizeof(*(change[i].change)) * rows);
423 for (j = 0; j < rows; j++) {
424 change[i].change[j] = data[j] - change[i].baseline[j];
443 for (i = 0; i < changes; i++) {
444 switch (change[i].optionCode) {
450 if (!
SDDS_SetColumn(outSet, SDDS_SET_BY_NAME, change[i].copy, rows, change[i].resultColumn))
455 !
SDDS_SetColumn(outSet, SDDS_SET_BY_NAME, data, rows, change[i].resultColumn))
465long addChangeRequests(
CHANGE_REQUEST **request,
long requests,
char **item,
long items,
long code,
char *excludeName,
char *newTypeName) {
467 *request =
SDDS_Realloc(*request,
sizeof(**request) * (requests + items));
468 for (i = 0; i < items; i++) {
469 (*request)[i + requests].columnName = item[i];
470 (*request)[i + requests].optionCode = code;
471 (*request)[i + requests].excludeName = excludeName;
475 snprintf(buffer,
sizeof(buffer),
"Unknown type given: %s", newTypeName);
479 (*request)[i + requests].typeCode = -1;
482 return items + requests;
487 long iReq, iChange, iName, index;
489 char s[SDDS_MAXLINE];
492 change =
tmalloc(
sizeof(*change) * requests);
493 *changes = iChange = 0;
494 for (iReq = 0; iReq < requests; iReq++) {
495 if (iChange >= *changes)
496 change =
SDDS_Realloc(change,
sizeof(*change) * (*changes += 10));
499 sprintf(s,
"Error: Column '%s' not found in input file", request[iReq].columnName);
503 change[iChange].sourceColumn = request[iReq].columnName;
504 change[iChange].optionCode = request[iReq].optionCode;
505 change[iChange].change = change[iChange].baseline = NULL;
508 fprintf(stderr,
"Error: Column '%s' is non-numeric. Cannot compute changes.\n", change[iChange].sourceColumn);
511 change[iChange].copy = change[iChange].pass = NULL;
512 change[iChange].baseline = change[iChange].change = NULL;
513 change[iChange].newType = request[iReq].typeCode;
519 if (request[iReq].excludeName) {
524 sprintf(s,
"No columns selected for wildcard sequence '%s'", request[iReq].columnName);
528 if (iChange + columnNames > *changes)
529 change =
SDDS_Realloc(change,
sizeof(*change) * (*changes = iChange + columnNames + 10));
530 for (iName = 0; iName < columnNames; iName++) {
531 change[iChange + iName].sourceColumn = columnName[iName];
532 change[iChange + iName].optionCode = request[iReq].optionCode;
533 change[iChange + iName].change = change[iChange + iName].baseline = NULL;
536 fprintf(stderr,
"Error: Column '%s' is non-numeric. Cannot compute changes.\n", change[iChange].sourceColumn);
539 change[iChange].copy = change[iChange].pass = NULL;
540 change[iChange].baseline = change[iChange].change = NULL;
541 change[iChange].newType = request[iReq].typeCode;
543 iChange += columnNames;
549 for (iChange = 0; iChange < *changes; iChange++) {
550 switch (change[iChange].optionCode) {
553 strcpy(s, change[iChange].sourceColumn);
556 sprintf(s,
"ChangeIn%s", change[iChange].sourceColumn);
568 char **parameter = NULL, s[SDDS_MAXLINE];
572 if (columnMajorOrder != -1)
573 outSet->layout.data_mode.column_major = columnMajorOrder;
575 outSet->layout.data_mode.column_major = inSet->layout.data_mode.column_major;
576 if (!transferDefinitions(outSet, inSet, change, changes, SET_CHANGESIN))
578 if (!transferDefinitions(outSet, inSet, change, changes, SET_COPY))
580 if (!transferDefinitions(outSet, inSet, change, changes, SET_PASS))
583 for (i = 0; i < parameters; i++)
586 for (i = 0; i < parameters; i++)
591 sprintf(s,
"Unable to complete setup of output file");
600 char s[SDDS_MAXLINE], *symbol;
602 for (column = 0; column < changes; column++) {
603 if (optionCode != change[column].optionCode)
606 sprintf(s,
"Problem transferring definition of column '%s'", change[column].sourceColumn);
624 sprintf(s,
"Unable to get/modify column '%s' information", change[column].sourceColumn);
630 switch (change[column].optionCode) {
636 sprintf(s,
"ChangeIn[%s]", symbol);
639 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.