SDDS ToolKit Programs and Libraries for C and Python
All Classes Files Functions Variables Macros Pages
sddschanges.c
Go to the documentation of this file.
1/**
2 * @file sddschanges.c
3 * @brief Analyze data from columns of an SDDS file to determine changes from the first page.
4 *
5 * @details
6 * This program processes an SDDS (Self Describing Data Set) file to compute changes
7 * in specified columns relative to baseline data, which can be provided either
8 * as a separate file or implicitly as the first page of the input file. The program
9 * supports various options to copy columns, pass data through, and configure output
10 * formatting.
11 *
12 * ### Key Features
13 * - Compute changes in specified columns based on baseline data.
14 * - Optionally copy or pass through additional columns.
15 * - Support for parallel page processing and maintaining empty pages.
16 * - Configurable output order (row-major or column-major).
17 *
18 * @section Usage
19 * ```
20 * sddschanges [<inputfile>] [<outputfile>]
21 * [-pipe=[input][,output]]
22 * -changesIn=[exclude=<wildcard>,][,newType=<string>]<column-names>
23 * [-copy=<column-names>]
24 * [-pass=<column-names>]
25 * [-baseline=<filename>]
26 * [-parallelPages]
27 * [-keepEmpties]
28 * [-majorOrder=row|column]
29 * ```
30 *
31 * @section Options
32 * | Required | Description |
33 * |-----------|-----------------------------------------------------------------------------|
34 * | `-changesIn` | Specify columns to compute changes for. Supports wildcards and type overrides. |
35 *
36 * | Optional | Description |
37 * |-----------------------------|-------------------------------------------------------------------------|
38 * | `-pipe` | Use standard input/output for input and/or output. |
39 * | `-copy` | Specify columns to copy from the first page to all pages of the output. |
40 * | `-pass` | Specify columns to pass through from each page of the input to the output. |
41 * | `-baseline` | Specify a baseline SDDS file to compute changes against. |
42 * | `-parallelPages` | Compares input and baseline files page-by-page. |
43 * | `-keepEmpties` | Ensures that empty pages are emitted to the output. |
44 * | `-majorOrder` | Specify the major order for writing the output file (row|column). |
45 *
46 * @subsection Incompatibilities
47 * - `-parallelPages` requires `-baseline`.
48 *
49 * @copyright
50 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
51 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
52 *
53 * @license
54 * This file is distributed under the terms of the Software License Agreement
55 * found in the file LICENSE included with this distribution.
56 *
57 * @authors
58 * M. Borland, C. Saunders, R. Soliday, H. Shang
59 */
60
61#include "mdb.h"
62#include "scan.h"
63#include "SDDS.h"
64#include "match_string.h"
65#include <ctype.h>
66
67/* Enumeration for option types */
68enum option_type {
69 SET_COPY,
70 SET_CHANGESIN,
71 SET_PASS,
72 SET_BASELINE,
73 SET_PIPE,
74 SET_PARALLELPAGES,
75 SET_KEEPEMPTIES,
76 SET_MAJOR_ORDER,
77 N_OPTIONS
78};
79
80char *option[N_OPTIONS] = {
81 "copy",
82 "changesin",
83 "pass",
84 "baseline",
85 "pipe",
86 "parallelpages",
87 "keepempties",
88 "majorOrder",
89};
90
91typedef struct
92{
93 char *columnName;
94 long optionCode, typeCode;
95 char *excludeName;
97
98/* This structure stores data necessary for accessing/creating SDDS columns and
99 * for computing a statistic.
100 */
101typedef struct
102{
103 char *sourceColumn, *resultColumn;
104 long optionCode, typeCode;
105 /* These store intermediate values during processing */
106 double *baseline, *change;
107 void *copy;
108 void *pass;
109 long type, newType;
111
112long addChangeRequests(CHANGE_REQUEST **request, long requests, char **item, long items, long code, char *excludeName, char *newType);
113CHANGE_DEFINITION *compileChangeDefinitions(SDDS_DATASET *inSet, long *changes, CHANGE_REQUEST *request, long requests);
114long setupOutputFile(SDDS_DATASET *outSet, char *output, SDDS_DATASET *inSet, CHANGE_DEFINITION *change, long changes, short columnMajorOrder);
115int64_t addBaselineData(CHANGE_DEFINITION *change, long changes, char *baseline, long page, int64_t lastRows);
116int64_t copyBaselineData(CHANGE_DEFINITION *change, long changes, SDDS_DATASET *dataset);
117void computeChanges(CHANGE_DEFINITION *change, long changes, SDDS_DATASET *inSet, int64_t rows);
118void outputChanges(CHANGE_DEFINITION *change, long changes, SDDS_DATASET *outSet, int64_t rows, SDDS_DATASET *inSet);
119long transferDefinitions(SDDS_DATASET *outSet, SDDS_DATASET *inSet, CHANGE_DEFINITION *change, long changes, long optionCode);
120
121static char *USAGE =
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"
129 " [-keepEmpties] \n"
130 " [-majorOrder=row|column] \n"
131 "Options:\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"
146 " -parallelPages\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"
149 " -keepEmpties\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";
155
156int main(int argc, char **argv) {
157 CHANGE_DEFINITION *change;
158 long changes, requests;
159 CHANGE_REQUEST *request;
160 SCANNED_ARG *scanned; /* structure for scanned arguments */
161 SDDS_DATASET inSet, outSet;
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;
167 char *ptr = NULL;
168 short columnMajorOrder = -1;
169
171 argc = scanargs(&scanned, argc, argv);
172 if (argc < 3) {
173 bomb(NULL, USAGE);
174 }
175
176 input = output = baseline = NULL;
177 change = NULL;
178 request = NULL;
179 changes = requests = baselineRows = 0;
180 pipeFlags = 0;
181 parallelPages = keepEmpties = 0;
182
183 for (i_arg = 1; i_arg < argc; i_arg++) {
184 if (scanned[i_arg].arg_type == OPTION) {
185 /* Process options here */
186 switch (code = match_string(scanned[i_arg].list[0], option, N_OPTIONS, 0)) {
187 case SET_MAJOR_ORDER:
188 majorOrderFlag = 0;
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");
195 }
196 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
197 columnMajorOrder = 1;
198 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
199 columnMajorOrder = 0;
200 break;
201 case SET_COPY:
202 case SET_CHANGESIN:
203 case SET_PASS:
204 if (scanned[i_arg].n_items < 2) {
205 fprintf(stderr, "Error: Invalid -%s syntax\n", option[code]);
206 exit(EXIT_FAILURE);
207 }
208 if (code == SET_CHANGESIN) {
209 long offset;
210 char *newTypeName;
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], '='))) {
218 *ptr = '\0';
219 switch (match_string(scanned[i_arg].list[offset], changeOption, N_CHANGE_OPTIONS, 0)) {
220 case CHANGE_EXCLUDE:
221 SDDS_CopyString(&excludeName, ++ptr);
222 break;
223 case CHANGE_NEWTYPE:
224 SDDS_CopyString(&newTypeName, ++ptr);
225 break;
226 default:
227 break;
228 }
229 } else {
230 break;
231 }
232 }
233 requests = addChangeRequests(&request, requests, scanned[i_arg].list + offset,
234 scanned[i_arg].n_items - offset, code, excludeName, newTypeName);
235 } else {
236 requests = addChangeRequests(&request, requests, scanned[i_arg].list + 1,
237 scanned[i_arg].n_items - 1, code, NULL, NULL);
238 }
239 break;
240 case SET_BASELINE:
241 if (scanned[i_arg].n_items != 2)
242 SDDS_Bomb("Invalid -baseline syntax");
243 SDDS_CopyString(&baseline, scanned[i_arg].list[1]);
244 break;
245 case SET_PIPE:
246 if (!processPipeOption(scanned[i_arg].list + 1, scanned[i_arg].n_items - 1, &pipeFlags))
247 SDDS_Bomb("Invalid -pipe syntax");
248 break;
249 case SET_PARALLELPAGES:
250 parallelPages = 1;
251 break;
252 case SET_KEEPEMPTIES:
253 keepEmpties = 1;
254 break;
255 default:
256 fprintf(stderr, "Error: Unknown option '%s' given\n", scanned[i_arg].list[0]);
257 exit(EXIT_FAILURE);
258 break;
259 }
260 } else {
261 /* Argument is filename */
262 if (!input)
263 SDDS_CopyString(&input, scanned[i_arg].list[0]);
264 else if (!output)
265 SDDS_CopyString(&output, scanned[i_arg].list[0]);
266 else
267 SDDS_Bomb("Too many filenames provided");
268 }
269 }
270
271 if (parallelPages && !baseline)
272 SDDS_Bomb("-parallelPages only makes sense with -baseline");
273
274 processFilenames("sddschanges", &input, &output, pipeFlags, 0, NULL);
275
276 if (!requests)
277 SDDS_Bomb("No changes requested");
278
279 if (!SDDS_InitializeInput(&inSet, input))
280 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
281
282 if (!(change = compileChangeDefinitions(&inSet, &changes, request, requests)))
283 SDDS_Bomb("Unable to compile definitions");
284
285 if (!setupOutputFile(&outSet, output, &inSet, change, changes, columnMajorOrder)) {
286 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
287 SDDS_Bomb("Unable to setup output file");
288 }
289
290 if (baseline && !parallelPages)
291 baselineRows = addBaselineData(change, changes, baseline, 0, 0);
292
293 lastRows = 0;
294 while ((code = SDDS_ReadPage(&inSet)) > 0) {
295 rows = SDDS_CountRowsOfInterest(&inSet);
296 if (baseline && parallelPages)
297 baselineRows = addBaselineData(change, changes, baseline, code, lastRows);
298 if (!baseline && code == 1) {
299 baselineRows = copyBaselineData(change, changes, &inSet);
300 continue;
301 }
302 if (rows != baselineRows)
303 SDDS_Bomb("Number of rows in file changed");
304 if (rows)
305 computeChanges(change, changes, &inSet, rows);
306 if (rows || keepEmpties)
307 outputChanges(change, changes, &outSet, rows, &inSet);
308 lastRows = rows;
309 }
310 if (!SDDS_Terminate(&inSet) || !SDDS_Terminate(&outSet)) {
311 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
312 exit(EXIT_FAILURE);
313 }
314 if (change) {
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);
320 }
321 free(change);
322 }
323 if (input)
324 free(input);
325 if (output)
326 free(output);
327 if (baseline)
328 free(baseline);
329 if (request)
330 free(request);
331 free_scanargs(&scanned, argc);
332 return EXIT_SUCCESS;
333}
334
335int64_t addBaselineData(CHANGE_DEFINITION *change, long changes, char *baseline, long page, int64_t lastRows) {
336 static SDDS_DATASET dataset;
337 long i, code;
338 int64_t rows;
339 rows = 0;
340
341 if (page == 0 || page == 1) {
342 if (!SDDS_InitializeInput(&dataset, baseline))
343 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
344 }
345 if ((code = SDDS_ReadPage(&dataset)) <= 0 || (rows = SDDS_CountRowsOfInterest(&dataset)) < 0) {
346 SDDS_SetError("Problem reading (next) page of baseline data file");
347 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
348 }
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) {
354 if (page > 1)
355 free(change[i].baseline);
356 change[i].baseline = NULL;
357 }
358 if (rows && !(change[i].baseline = SDDS_GetColumnInDoubles(&dataset, change[i].sourceColumn))) {
359 fprintf(stderr, "Problem reading baseline data\n");
360 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
361 }
362 } else if (change[i].optionCode == SET_COPY) {
363 if (change[i].copy) {
364 if (page > 1) {
365 if (change[i].type == SDDS_STRING && lastRows)
366 SDDS_FreeStringArray(change[i].copy, lastRows);
367 }
368 free(change[i].copy);
369 change[i].copy = NULL;
370 }
371 if (rows && !(change[i].copy = SDDS_GetColumn(&dataset, change[i].sourceColumn))) {
372 fprintf(stderr, "Problem reading baseline data\n");
373 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
374 }
375 }
376 }
377 return rows;
378}
379
380int64_t copyBaselineData(CHANGE_DEFINITION *change, long changes, SDDS_DATASET *dataset) {
381 long i;
382 int64_t rows;
383
384 if (!(rows = SDDS_CountRowsOfInterest(dataset)))
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) {
388 if (!(change[i].baseline = SDDS_GetColumnInDoubles(dataset, change[i].sourceColumn))) {
389 fprintf(stderr, "Problem reading baseline data\n");
390 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
391 }
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");
395 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
396 }
397 }
398 }
399 return rows;
400}
401
402void computeChanges(CHANGE_DEFINITION *change, long changes, SDDS_DATASET *inSet, int64_t rows) {
403 double *data;
404 long i;
405 int64_t j;
406
407 for (i = 0; i < changes; i++) {
408 switch (change[i].optionCode) {
409 case SET_COPY:
410 break;
411 case SET_PASS:
412 break;
413 case SET_CHANGESIN:
414 if (!(data = SDDS_GetColumnInDoubles(inSet, change[i].sourceColumn))) {
415 fprintf(stderr, "Problem reading input data\n");
416 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
417 }
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];
423 }
424 free(data);
425 break;
426 }
427 }
428}
429
430void outputChanges(CHANGE_DEFINITION *change, long changes, SDDS_DATASET *outSet, int64_t rows, SDDS_DATASET *inSet) {
431 long i;
432 void *data;
433
434 if (!SDDS_StartPage(outSet, rows))
435 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
436
437 if (!SDDS_CopyParameters(outSet, inSet))
438 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
439
440 if (rows) {
441 for (i = 0; i < changes; i++) {
442 switch (change[i].optionCode) {
443 case SET_CHANGESIN:
444 if (!SDDS_SetColumnFromDoubles(outSet, SDDS_SET_BY_NAME, change[i].change, rows, change[i].resultColumn))
445 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
446 break;
447 case SET_COPY:
448 if (!SDDS_SetColumn(outSet, SDDS_SET_BY_NAME, change[i].copy, rows, change[i].resultColumn))
449 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
450 break;
451 case SET_PASS:
452 if (!(data = SDDS_GetInternalColumn(inSet, change[i].resultColumn)) ||
453 !SDDS_SetColumn(outSet, SDDS_SET_BY_NAME, data, rows, change[i].resultColumn))
454 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
455 break;
456 }
457 }
458 }
459 if (!SDDS_WritePage(outSet))
460 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
461}
462
463long addChangeRequests(CHANGE_REQUEST **request, long requests, char **item, long items, long code, char *excludeName, char *newTypeName) {
464 long i;
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;
470 if (newTypeName) {
471 if (((*request)[i + requests].typeCode = SDDS_IdentifyType(newTypeName)) == 0) {
472 char buffer[16384];
473 snprintf(buffer, sizeof(buffer), "Unknown type given: %s", newTypeName);
474 SDDS_Bomb(buffer);
475 }
476 } else {
477 (*request)[i + requests].typeCode = -1;
478 }
479 }
480 return items + requests;
481}
482
483CHANGE_DEFINITION *compileChangeDefinitions(SDDS_DATASET *inSet, long *changes, CHANGE_REQUEST *request, long requests) {
484 CHANGE_DEFINITION *change;
485 long iReq, iChange, iName, index;
486 int32_t columnNames;
487 char s[SDDS_MAXLINE];
488 char **columnName;
489
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));
495 if (!has_wildcards(request[iReq].columnName)) {
496 if ((index = SDDS_GetColumnIndex(inSet, request[iReq].columnName)) < 0) {
497 sprintf(s, "Error: Column '%s' not found in input file", request[iReq].columnName);
498 SDDS_SetError(s);
499 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
500 }
501 change[iChange].sourceColumn = request[iReq].columnName;
502 change[iChange].optionCode = request[iReq].optionCode;
503 change[iChange].change = change[iChange].baseline = NULL;
504 change[iChange].type = SDDS_GetColumnType(inSet, index);
505 if (change[iChange].optionCode == SET_CHANGESIN && !SDDS_NUMERIC_TYPE(SDDS_GetColumnType(inSet, index))) {
506 fprintf(stderr, "Error: Column '%s' is non-numeric. Cannot compute changes.\n", change[iChange].sourceColumn);
507 exit(EXIT_FAILURE);
508 }
509 change[iChange].copy = change[iChange].pass = NULL;
510 change[iChange].baseline = change[iChange].change = NULL;
511 change[iChange].newType = request[iReq].typeCode;
512 iChange++;
513 } else {
514 SDDS_SetColumnFlags(inSet, 0);
515 if (!SDDS_SetColumnsOfInterest(inSet, SDDS_MATCH_STRING, request[iReq].columnName, SDDS_OR))
516 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
517 if (request[iReq].excludeName) {
518 if (!SDDS_SetColumnsOfInterest(inSet, SDDS_MATCH_STRING, request[iReq].excludeName, SDDS_NEGATE_MATCH | SDDS_AND))
519 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
520 }
521 if (!(columnName = SDDS_GetColumnNames(inSet, &columnNames))) {
522 sprintf(s, "No columns selected for wildcard sequence '%s'", request[iReq].columnName);
523 SDDS_SetError(s);
524 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
525 }
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;
532 change[iChange + iName].type = SDDS_GetNamedColumnType(inSet, change[iChange].sourceColumn);
533 if (change[iChange].optionCode == SET_CHANGESIN && !SDDS_NUMERIC_TYPE(SDDS_GetNamedColumnType(inSet, change[iChange].sourceColumn))) {
534 fprintf(stderr, "Error: Column '%s' is non-numeric. Cannot compute changes.\n", change[iChange].sourceColumn);
535 exit(EXIT_FAILURE);
536 }
537 change[iChange].copy = change[iChange].pass = NULL;
538 change[iChange].baseline = change[iChange].change = NULL;
539 change[iChange].newType = request[iReq].typeCode;
540 }
541 iChange += columnNames;
542 free(columnName);
543 }
544 }
545
546 *changes = iChange;
547 for (iChange = 0; iChange < *changes; iChange++) {
548 switch (change[iChange].optionCode) {
549 case SET_COPY:
550 case SET_PASS:
551 strcpy(s, change[iChange].sourceColumn);
552 break;
553 case SET_CHANGESIN:
554 sprintf(s, "ChangeIn%s", change[iChange].sourceColumn);
555 break;
556 }
557 if (!SDDS_CopyString(&change[iChange].resultColumn, s))
558 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
559 }
560 return change;
561}
562
563long setupOutputFile(SDDS_DATASET *outSet, char *output, SDDS_DATASET *inSet, CHANGE_DEFINITION *change, long changes, short columnMajorOrder) {
564 long i;
565 int32_t parameters;
566 char **parameter = NULL, s[SDDS_MAXLINE];
567
568 if (!SDDS_InitializeOutput(outSet, SDDS_BINARY, 0, NULL, "sddschanges output", output))
569 return 0;
570 if (columnMajorOrder != -1)
571 outSet->layout.data_mode.column_major = columnMajorOrder;
572 else
573 outSet->layout.data_mode.column_major = inSet->layout.data_mode.column_major;
574 if (!transferDefinitions(outSet, inSet, change, changes, SET_CHANGESIN))
575 return 0;
576 if (!transferDefinitions(outSet, inSet, change, changes, SET_COPY))
577 return 0;
578 if (!transferDefinitions(outSet, inSet, change, changes, SET_PASS))
579 return 0;
580 if ((parameter = SDDS_GetParameterNames(inSet, &parameters)) && parameters) {
581 for (i = 0; i < parameters; i++)
582 if (!SDDS_TransferParameterDefinition(outSet, inSet, parameter[i], NULL))
583 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
584 for (i = 0; i < parameters; i++)
585 free(parameter[i]);
586 free(parameter);
587 }
588 if (!SDDS_WriteLayout(outSet)) {
589 sprintf(s, "Unable to complete setup of output file");
590 SDDS_SetError(s);
591 return 0;
592 }
593 return 1;
594}
595
596long transferDefinitions(SDDS_DATASET *outSet, SDDS_DATASET *inSet, CHANGE_DEFINITION *change, long changes, long optionCode) {
597 long column;
598 char s[SDDS_MAXLINE], *symbol;
599
600 for (column = 0; column < changes; column++) {
601 if (optionCode != change[column].optionCode)
602 continue;
603 if (!SDDS_TransferColumnDefinition(outSet, inSet, change[column].sourceColumn, change[column].resultColumn)) {
604 sprintf(s, "Problem transferring definition of column '%s'", change[column].sourceColumn);
605 SDDS_SetError(s);
606 return 0;
607 }
608 /* THIS CODE IS BROKEN
609 if (change[column].newType > 0 && change[column].newType != change[column].type)
610 {
611 fprintf(stderr, "change[%d].newType=%d change[%d].type=%d\n", column, change[column].newType, column, change[column].type);
612 if (!SDDS_ChangeColumnInformation(outSet, "type", SDDS_GetTypeName(change[column].newType), SDDS_PASS_BY_STRING | SDDS_SET_BY_NAME, change[column].resultColumn))
613 {
614 sprintf(s, "Problem changing type of column %s to make %s\n", change[column].sourceColumn, change[column].resultColumn);
615 SDDS_SetError(s);
616 return 0;
617 }
618 }
619 */
620 if (!SDDS_ChangeColumnInformation(outSet, "description", NULL, SDDS_SET_BY_NAME, change[column].resultColumn) ||
621 SDDS_GetColumnInformation(outSet, "symbol", &symbol, SDDS_BY_NAME, change[column].resultColumn) != SDDS_STRING) {
622 sprintf(s, "Unable to get/modify column '%s' information", change[column].sourceColumn);
623 SDDS_SetError(s);
624 return 0;
625 }
626 if (!symbol)
627 SDDS_CopyString(&symbol, change[column].sourceColumn);
628 switch (change[column].optionCode) {
629 case SET_COPY:
630 case SET_PASS:
631 strcpy(s, symbol);
632 break;
633 case SET_CHANGESIN:
634 sprintf(s, "ChangeIn[%s]", symbol);
635 break;
636 default:
637 SDDS_Bomb("Invalid option code in transferDefinitions");
638 break;
639 }
640 if (!SDDS_ChangeColumnInformation(outSet, "symbol", s, SDDS_BY_NAME, change[column].resultColumn))
641 return 0;
642 }
643 return 1;
644}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t SDDS_CopyParameters(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source)
Definition SDDS_copy.c:286
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.
void * SDDS_GetColumn(SDDS_DATASET *SDDS_dataset, char *column_name)
Retrieves a copy of the data for a specified column, including only rows marked as "of interest".
int64_t SDDS_CountRowsOfInterest(SDDS_DATASET *SDDS_dataset)
Counts the number of rows marked as "of interest" in the current data table.
int32_t SDDS_SetColumnsOfInterest(SDDS_DATASET *SDDS_dataset, int32_t mode,...)
Sets the acceptance flags for columns based on specified naming criteria.
void * SDDS_GetInternalColumn(SDDS_DATASET *SDDS_dataset, char *column_name)
Retrieves an internal pointer to the data of a specified column, including all rows.
int32_t SDDS_SetColumnFlags(SDDS_DATASET *SDDS_dataset, int32_t column_flag_value)
Sets the acceptance flags for all columns in the current data table of a data set.
double * SDDS_GetColumnInDoubles(SDDS_DATASET *SDDS_dataset, char *column_name)
Retrieves the data of a specified numerical column as an array of doubles, considering only rows mark...
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.
Definition SDDS_info.c:364
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.
Definition SDDS_info.c:41
int32_t SDDS_InitializeInput(SDDS_DATASET *SDDS_dataset, char *filename)
Definition SDDS_input.c:49
int32_t SDDS_Terminate(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_ReadPage(SDDS_DATASET *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.
Definition SDDS_utils.c:379
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.
Definition SDDS_utils.c:432
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
Definition SDDS_utils.c:288
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.
Definition SDDS_utils.c:342
int32_t SDDS_CopyString(char **target, const char *source)
Copies a source string to a target string with memory allocation.
Definition SDDS_utils.c:856
void * SDDS_Realloc(void *old_ptr, size_t new_size)
Reallocates memory to a new size.
Definition SDDS_utils.c:677
#define SDDS_STRING
Identifier for the string data type.
Definition SDDStypes.h:85
#define SDDS_NUMERIC_TYPE(type)
Checks if the given type identifier corresponds to any numeric type.
Definition SDDStypes.h:138
void * tmalloc(uint64_t size_of_block)
Allocates a memory block of the specified size with zero initialization.
Definition array.c:59
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
Definition bomb.c:26
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)
Definition scanargs.c:36
long processPipeOption(char **item, long items, unsigned long *flags)
Definition scanargs.c:356
void processFilenames(char *programName, char **input, char **output, unsigned long pipeFlags, long noWarnings, long *tmpOutputUsed)
Definition scanargs.c:390
void free_scanargs(SCANNED_ARG **scanned, int argc)
Definition scanargs.c:584
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.
Definition wild_match.c:498