SDDS ToolKit Programs and Libraries for C and Python
All Classes Files Functions Variables Macros Pages
sdds2math.c
Go to the documentation of this file.
1/**
2 * @file sdds2math.c
3 * @brief Converts SDDS files to a Mathematica-compatible format.
4 *
5 * @details
6 * This program reads an SDDS (Self Describing Data Sets) file and converts it into a format
7 * that can be easily imported and used within Mathematica. The output is structured as a
8 * single Mathematica variable containing descriptions, column definitions, parameter
9 * definitions, array definitions, associations, and tables of data.
10 *
11 * The output Mathematica variable has the following structure:
12 * ```
13 * sdds = {description, coldef, pardef, arraydef, associates, tables}
14 * ```
15 * - **description**: Contains text and contents descriptions.
16 * - **coldef**: Defines columns with name, units, symbol, format, type, field length, and description.
17 * - **pardef**: Defines parameters with name, fixed value, units, symbol, type, and description.
18 * - **arraydef**: Defines arrays with name, units, symbol, format, type, field length, group, and description.
19 * - **associates**: Lists associations with SDDS flag, filename, path, contents, and description.
20 * - **tables**: Contains data tables with parameters and row data.
21 *
22 * @section Usage
23 * ```
24 * sdds2math [<SDDSfilename>] [<outputname>]
25 * [-pipe[=in][,out]]
26 * [-comments]
27 * [-verbose]
28 * [-format=<format-string>]
29 * ```
30 *
31 * @section Options
32 * | Option | Description |
33 * |----------------------------|-----------------------------------------------------------------------------|
34 * | `-pipe` | Standard SDDS Toolkit pipe option. |
35 * | `-comments` | Include helpful Mathematica comments in the output file. |
36 * | `-format` | Specify the format for double precision numbers (Default: `%g`). |
37 * | `-verbose` | Display header information to the terminal similar to `sddsquery`. |
38 *
39 * @subsection SR Specific Requirements
40 * - If `-format=<format-string>` is used, `<format-string>` must be a valid `printf`-style format.
41 *
42 * @copyright
43 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
44 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
45 *
46 * @license
47 * This file is distributed under the terms of the Software License Agreement
48 * found in the file LICENSE included with this distribution.
49 *
50 * @author
51 * K. Evans, C. Saunders, M. Borland, R. Soliday
52 */
53
54#include <stdio.h>
55#include <string.h>
56#include <math.h>
57#include "mdb.h"
58#include "SDDS.h"
59#include "scan.h"
60
61/* Enumeration for option types */
62enum option_type {
63 SET_COMMENTS,
64 SET_FORMAT,
65 SET_VERBOSE,
66 SET_PIPE,
67 N_OPTIONS
68};
69
70#define FORMAT "%g"
71
72/* Option strings corresponding to enum option_type */
73static char *option[N_OPTIONS] = {
74 "comments",
75 "format",
76 "verbose",
77 "pipe"
78};
79
80/* Improved usage message */
81static char *USAGE =
82 "\nUsage:\n"
83 " sdds2math [<SDDSfilename>] [<outputname>]\n"
84 " [-pipe[=in][,out]]\n"
85 " [-comments]\n"
86 " [-verbose]\n"
87 " [-format=<format-string>]\n"
88 "Options:\n"
89 " -pipe[=in][,out] Standard SDDS Toolkit pipe option.\n"
90 " -comments Include helpful Mathematica comments in the output file.\n"
91 " -format=<format-string> Specify the format for double precision numbers (Default: " FORMAT ").\n"
92 " -verbose Display header information to the terminal.\n"
93 "\n"
94 "Description:\n"
95 " sdds2math converts an SDDS file into a Mathematica-readable format.\n"
96 " The output is a single Mathematica variable with the structure:\n"
97 " sdds = {description, coldef, pardef, arraydef, associates, tables}\n"
98 " where each component contains detailed information about the SDDS data.\n"
99 "\n"
100 "Author:\n"
101 " Kenneth Evans (Original version: 1994)\n"
102 " Updated: " __DATE__ " " __TIME__ ", SVN revision: " SVN_VERSION "\n";
103
104int main(int argc, char **argv) {
105 FILE *outfile;
106 SDDS_TABLE SDDS_table;
107 SDDS_LAYOUT *layout;
108 COLUMN_DEFINITION *coldef;
109 PARAMETER_DEFINITION *pardef;
110 ARRAY_DEFINITION *arraydef;
111 char s[256];
112 char *input, *output;
113 long i, i_arg, ntable;
114 int64_t nrows, j;
115 SCANNED_ARG *s_arg;
116 char *text, *contents, *ss, *ptr, *iformat = FORMAT, *format, *rformat;
117 long verbose = 0, comments = 0, addquotes = 1;
118 short nexp;
119 double dd, ddred;
120 float ff, ffred;
121 void *data;
122 unsigned long pipeFlags;
123
125
126 input = output = NULL;
127 pipeFlags = 0;
128
129 argc = scanargs(&s_arg, argc, argv);
130 if (argc == 1) {
131 fprintf(stderr, "%s", USAGE);
132 exit(EXIT_FAILURE);
133 }
134
135 for (i_arg = 1; i_arg < argc; i_arg++) {
136 if (s_arg[i_arg].arg_type == OPTION) {
137 switch (match_string(s_arg[i_arg].list[0], option, N_OPTIONS, 0)) {
138 case SET_COMMENTS:
139 comments = 1;
140 break;
141 case SET_FORMAT:
142 if (s_arg[i_arg].n_items < 2)
143 SDDS_Bomb("Invalid -format syntax");
144 iformat = s_arg[i_arg].list[1]; /* Input format */
145 break;
146 case SET_VERBOSE:
147 verbose = 1;
148 break;
149 case SET_PIPE:
150 if (!processPipeOption(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, &pipeFlags))
151 SDDS_Bomb("Invalid -pipe syntax");
152 break;
153 default:
154 fprintf(stderr, "Unknown option: %s\n", s_arg[i_arg].list[0]);
155 fprintf(stderr, "%s", USAGE);
156 exit(EXIT_FAILURE);
157 }
158 } else {
159 if (input == NULL)
160 input = s_arg[i_arg].list[0];
161 else if (output == NULL)
162 output = s_arg[i_arg].list[0];
163 else
164 SDDS_Bomb("Too many filenames provided.");
165 }
166 }
167
168 processFilenames("sdds2math", &input, &output, pipeFlags, 0, NULL);
169
170 if (output) {
171 outfile = fopen(output, "w");
172 if (!outfile) {
173 fprintf(stderr, "Error: Cannot open output file '%s'\n", output);
174 exit(EXIT_FAILURE);
175 }
176 } else {
177 outfile = stdout;
178 }
179
180 /* Calculate formats for converting to Mathematica convention */
181 format = (char *)calloc(256, sizeof(char)); /* Whole format */
182 if (!format) {
183 fprintf(stderr, "Memory allocation error for format.\n");
184 exit(EXIT_FAILURE);
185 }
186
187 rformat = (char *)calloc(256, sizeof(char)); /* Part before e */
188 if (!rformat) {
189 fprintf(stderr, "Memory allocation error for rformat.\n");
190 free(format);
191 exit(EXIT_FAILURE);
192 }
193
194 strcpy(format, iformat);
195 if ((ptr = strchr(format, 'E')))
196 *ptr = 'e'; /* Convert 'E' to 'e' */
197 if ((ptr = strchr(format, 'G')))
198 *ptr = 'g'; /* Convert 'G' to 'g' */
199 strcpy(rformat, format);
200 if ((ptr = strpbrk(rformat, "eg")))
201 *ptr = 'f';
202
203 /* Initialize SDDS input */
204 if (!SDDS_InitializeInput(&SDDS_table, input)) {
205 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
206 exit(EXIT_FAILURE);
207 }
208
209 layout = &SDDS_table.layout;
210
211 /* Start top level */
212 fprintf(outfile, "{");
213
214 /* Description */
215 fprintf(outfile, "{");
216 if (verbose)
217 printf("\nFile '%s' is in SDDS protocol version %" PRId32 "\n", input, layout->version);
218
219 if (!SDDS_GetDescription(&SDDS_table, &text, &contents))
220 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
221
222 if (text) {
223 if (verbose)
224 printf("Description: %s\n", text);
225 fprintf(outfile, "\"%s\",", text);
226 }
227
228 if (contents) {
229 if (verbose)
230 printf("Contents: %s\n", contents);
231 fprintf(outfile, "\"%s\"", contents);
232 } else {
233 fprintf(outfile, "\"No contents\"");
234 }
235
236 if (layout->data_mode.mode == SDDS_ASCII) {
237 if (verbose)
238 printf("\nData is ASCII with %" PRId32 " lines per row and %" PRId32 " additional header lines expected.\n",
239 layout->data_mode.lines_per_row, layout->data_mode.additional_header_lines);
240 if (verbose)
241 printf("Row counts: %s\n", layout->data_mode.no_row_counts ? "No" : "Yes");
242 } else if (verbose) {
243 printf("\nData is binary\n");
244 }
245
246 fprintf(outfile, "},\n");
247
248 /* Columns */
249 fprintf(outfile, " {");
250 if (layout->n_columns) {
251 if (verbose)
252 printf("\n%" PRId32 " columns of data:\n", layout->n_columns);
253 if (verbose)
254 printf("NAME UNITS SYMBOL FORMAT TYPE FIELD DESCRIPTION\n");
255 if (verbose)
256 printf(" LENGTH\n");
257 for (i = 0; i < layout->n_columns; i++) {
258 if (i > 0)
259 fprintf(outfile, ",\n ");
260 coldef = layout->column_definition + i;
261 if (verbose)
262 printf("%-15s %-15s %-15s %-15s %-7s %-7" PRId32 " %s\n",
263 coldef->name ? coldef->name : "No name",
264 coldef->units ? coldef->units : "",
265 coldef->symbol ? coldef->symbol : "",
266 coldef->format_string ? coldef->format_string : "",
267 SDDS_type_name[coldef->type - 1],
268 coldef->field_length,
269 coldef->description ? coldef->description : "No description");
270 fprintf(outfile, "{\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",%" PRId32 ",\"%s\"}",
271 coldef->name ? coldef->name : "No name",
272 coldef->units ? coldef->units : "",
273 coldef->symbol ? coldef->symbol : "",
274 coldef->format_string ? coldef->format_string : "",
275 SDDS_type_name[coldef->type - 1],
276 coldef->field_length,
277 coldef->description ? coldef->description : "No description");
278 }
279 }
280 fprintf(outfile, "},\n");
281
282 /* Parameters */
283 fprintf(outfile, " {");
284 if (layout->n_parameters) {
285 if (verbose)
286 printf("\n%" PRId32 " parameters:\n", layout->n_parameters);
287 if (verbose)
288 printf("NAME UNITS SYMBOL TYPE DESCRIPTION\n");
289 for (i = 0; i < layout->n_parameters; i++) {
290 if (i > 0)
291 fprintf(outfile, ",\n ");
292 pardef = layout->parameter_definition + i;
293 if (verbose)
294 printf("%-19s %-19s %-19s %-19s %s\n",
295 pardef->name ? pardef->name : "No name",
296 pardef->units ? pardef->units : "",
297 pardef->symbol ? pardef->symbol : "",
298 SDDS_type_name[pardef->type - 1],
299 pardef->description ? pardef->description : "No description");
300 fprintf(outfile, "{\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"}",
301 pardef->name ? pardef->name : "No name",
302 pardef->fixed_value ? pardef->fixed_value : "",
303 pardef->units ? pardef->units : "",
304 pardef->symbol ? pardef->symbol : "",
305 SDDS_type_name[pardef->type - 1],
306 pardef->description ? pardef->description : "No description");
307 }
308 }
309 fprintf(outfile, "},\n");
310
311 /* Arrays */
312 fprintf(outfile, " {");
313 if (layout->n_arrays) {
314 if (verbose)
315 printf("\n%" PRId32 " arrays of data:\n", layout->n_arrays);
316 if (verbose)
317 printf("NAME UNITS SYMBOL FORMAT TYPE FIELD GROUP DESCRIPTION\n");
318 if (verbose)
319 printf(" LENGTH NAME\n");
320 for (i = 0; i < layout->n_arrays; i++) {
321 if (i > 0)
322 fprintf(outfile, ",\n ");
323 arraydef = layout->array_definition + i;
324 if (verbose)
325 printf("%-15s %-15s %-15s %-7s %-8s*^%-5" PRId32 " %-7" PRId32 " %-15s %s\n",
326 arraydef->name ? arraydef->name : "No name",
327 arraydef->units ? arraydef->units : "",
328 arraydef->symbol ? arraydef->symbol : "",
329 arraydef->format_string ? arraydef->format_string : "",
330 SDDS_type_name[arraydef->type - 1],
331 arraydef->dimensions,
332 arraydef->field_length,
333 arraydef->group_name ? arraydef->group_name : "",
334 arraydef->description ? arraydef->description : "No description");
335 fprintf(outfile, "{\"%s\",\"%s\",\"%s\",\"%s\",\"%s*^%" PRId32 "\",%" PRId32 ",\"%s\",\"%s\"}",
336 arraydef->name ? arraydef->name : "No name",
337 arraydef->units ? arraydef->units : "",
338 arraydef->symbol ? arraydef->symbol : "",
339 arraydef->format_string ? arraydef->format_string : "",
340 SDDS_type_name[arraydef->type - 1],
341 arraydef->dimensions,
342 arraydef->field_length,
343 arraydef->group_name ? arraydef->group_name : "",
344 arraydef->description ? arraydef->description : "No description");
345 }
346 }
347 fprintf(outfile, "},\n");
348
349 /* Associates */
350 fprintf(outfile, " {");
351 if (layout->n_associates) {
352 if (verbose)
353 printf("\n%" PRId32 " associates:\n", layout->n_associates);
354 if (verbose)
355 printf("SDDS FILENAME PATH CONTENTS DESCRIPTION\n");
356 for (i = 0; i < layout->n_associates; i++) {
357 if (i > 0)
358 fprintf(outfile, ",\n ");
359 if (verbose)
360 printf("%-5s %-19s %-29s %-19s %s\n",
361 layout->associate_definition[i].sdds ? "True" : "False",
362 layout->associate_definition[i].filename ? layout->associate_definition[i].filename : "",
363 layout->associate_definition[i].path ? layout->associate_definition[i].path : "",
364 layout->associate_definition[i].contents ? layout->associate_definition[i].contents : "",
365 layout->associate_definition[i].description ? layout->associate_definition[i].description : "No description");
366 fprintf(outfile, "{\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"}",
367 layout->associate_definition[i].sdds ? "True" : "False",
368 layout->associate_definition[i].filename ? layout->associate_definition[i].filename : "",
369 layout->associate_definition[i].path ? layout->associate_definition[i].path : "",
370 layout->associate_definition[i].contents ? layout->associate_definition[i].contents : "",
371 layout->associate_definition[i].description ? layout->associate_definition[i].description : "No description");
372 }
373 }
374 fprintf(outfile, "},\n");
375
376 /* Process tables */
377 fprintf(outfile, " {"); /* Start of array of tables */
378 while ((ntable = SDDS_ReadTable(&SDDS_table)) > 0) {
379 if (ntable > 1)
380 fprintf(outfile, ",\n ");
381 if (comments)
382 fprintf(outfile, "(*Table %ld*)", ntable);
383 fprintf(outfile, "{\n"); /* Start of this table */
384
385 /* Variable parameters */
386 fprintf(outfile, " {"); /* Start of parameters */
387 for (i = 0; i < layout->n_parameters; i++) {
388 if (i > 0)
389 fprintf(outfile, ",\n ");
390 pardef = layout->parameter_definition + i;
391 if (!(data = SDDS_GetParameter(&SDDS_table, pardef->name, NULL))) {
392 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
393 exit(EXIT_FAILURE);
394 }
395
396 /* This parameter */
397 if (comments)
398 fprintf(outfile, "(* %s *)", pardef->name);
399
400 addquotes = 1;
401 switch (pardef->type) {
402 case SDDS_DOUBLE:
403 dd = *(double *)data;
404 sprintf(s, format, dd);
405 if ((ptr = strchr(s, 'e'))) {
406 *ptr = ' ';
407 sscanf(s, "%lf %hd", &ddred, &nexp);
408 fprintf(outfile, rformat, ddred);
409 fprintf(outfile, "*10^%d", nexp);
410 } else {
411 fprintf(outfile, "%s", s);
412 }
413 break;
414 case SDDS_FLOAT:
415 ff = *(float *)data;
416 sprintf(s, format, ff);
417 if ((ptr = strchr(s, 'e'))) {
418 *ptr = ' ';
419 sscanf(s, "%f %hd", &ffred, &nexp);
420 fprintf(outfile, rformat, ffred);
421 fprintf(outfile, "*10^%d", nexp);
422 } else {
423 fprintf(outfile, "%s", s);
424 }
425 break;
426 case SDDS_STRING:
427 ss = *(char **)data;
428 if (*ss == '"')
429 addquotes = 0;
430 else if (SDDS_StringIsBlank(ss) || SDDS_HasWhitespace(ss))
431 addquotes = 0;
432 case SDDS_CHARACTER:
433 if (addquotes)
434 fprintf(outfile, "\"");
435 SDDS_PrintTypedValue(data, 0, pardef->type, NULL, outfile, 0);
436 if (addquotes)
437 fprintf(outfile, "\"");
438 break;
439 default:
440 SDDS_PrintTypedValue(data, 0, pardef->type, NULL, outfile, 0);
441 break;
442 }
443 }
444 fprintf(outfile, "},\n"); /* End of parameters */
445
446 /* Columns */
447 fprintf(outfile, " {"); /* Start of data array */
448 if (layout->n_columns) {
449 SDDS_SetColumnFlags(&SDDS_table, 1);
450 SDDS_SetRowFlags(&SDDS_table, 1);
451 if ((nrows = SDDS_CountRowsOfInterest(&SDDS_table)) < 0) {
452 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
453 exit(EXIT_FAILURE);
454 }
455
456 if (nrows) {
457 for (j = 0; j < nrows; j++) {
458 if (j > 0)
459 fprintf(outfile, ",\n ");
460 fprintf(outfile, "{"); /* Start of row */
461 for (i = 0; i < layout->n_columns; i++) {
462 if (i > 0)
463 fprintf(outfile, ",");
464 coldef = layout->column_definition + i;
465 if (!(data = SDDS_GetValue(&SDDS_table, coldef->name, j, NULL))) {
466 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
467 exit(EXIT_FAILURE);
468 }
469
470 addquotes = 1;
471 switch (coldef->type) {
472 case SDDS_DOUBLE:
473 dd = *(double *)data;
474 sprintf(s, format, dd);
475 if ((ptr = strchr(s, 'e'))) {
476 *ptr = ' ';
477 sscanf(s, "%lf %hd", &ddred, &nexp);
478 fprintf(outfile, rformat, ddred);
479 fprintf(outfile, "*10^%d", nexp);
480 } else {
481 fprintf(outfile, "%s", s);
482 }
483 break;
484 case SDDS_FLOAT:
485 ff = *(float *)data;
486 sprintf(s, format, ff);
487 if ((ptr = strchr(s, 'e'))) {
488 *ptr = ' ';
489 sscanf(s, "%f %hd", &ffred, &nexp);
490 fprintf(outfile, rformat, ffred);
491 fprintf(outfile, "*10^%d", nexp);
492 } else {
493 fprintf(outfile, "%s", s);
494 }
495 break;
496 case SDDS_STRING:
497 ss = *(char **)data;
498 if (*ss == '"')
499 addquotes = 0;
500 else if (SDDS_StringIsBlank(ss) || SDDS_HasWhitespace(ss))
501 addquotes = 0;
502 case SDDS_CHARACTER:
503 if (addquotes)
504 fprintf(outfile, "\"");
505 SDDS_PrintTypedValue(data, 0, coldef->type, NULL, outfile, 0);
506 if (addquotes)
507 fprintf(outfile, "\"");
508 break;
509 default:
510 SDDS_PrintTypedValue(data, 0, coldef->type, NULL, outfile, 0);
511 break;
512 }
513 }
514 fprintf(outfile, "}"); /* End of row */
515 }
516 }
517 }
518 fprintf(outfile, "}"); /* End of data array */
519 fprintf(outfile, "}"); /* End of this table */
520 }
521 fprintf(outfile, "\n }\n"); /* End of array of tables, last major component */
522
523 /* End top level */
524 fprintf(outfile, "}\n"); /* End of top level */
525
526 /* Clean up and exit */
527 fflush(stdout);
528 if (!SDDS_Terminate(&SDDS_table)) {
529 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
530 exit(EXIT_FAILURE);
531 }
532
533 free(format);
534 free(rformat);
535
536 return EXIT_SUCCESS;
537}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
char * SDDS_type_name[SDDS_NUM_TYPES]
Array of supported data type names.
Definition SDDS_data.c:43
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_SetRowFlags(SDDS_DATASET *SDDS_dataset, int32_t row_flag_value)
Sets the acceptance flags for all rows in the current data table of a data set.
void * SDDS_GetParameter(SDDS_DATASET *SDDS_dataset, char *parameter_name, void *memory)
Retrieves the value of a specified parameter from the current data table of a data set.
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.
int32_t SDDS_GetDescription(SDDS_DATASET *SDDS_dataset, char **text, char **contents)
Retrieves the text and contents descriptions from an SDDS dataset.
void * SDDS_GetValue(SDDS_DATASET *SDDS_dataset, char *column_name, int64_t srow_index, void *memory)
Retrieves the value from a specified column and selected row, optionally storing it in provided memor...
int32_t SDDS_InitializeInput(SDDS_DATASET *SDDS_dataset, char *filename)
Definition SDDS_input.c:49
int32_t SDDS_Terminate(SDDS_DATASET *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_StringIsBlank(char *s)
Checks if a string is blank (contains only whitespace characters).
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
Definition SDDS_utils.c:342
int32_t SDDS_PrintTypedValue(void *data, int64_t index, int32_t type, char *format, FILE *fp, uint32_t mode)
Prints a data value of a specified type using an optional printf format string.
Definition SDDS_utils.c:59
int32_t SDDS_HasWhitespace(char *string)
Checks if a string contains any whitespace characters.
#define SDDS_FLOAT
Identifier for the float data type.
Definition SDDStypes.h:43
#define SDDS_STRING
Identifier for the string data type.
Definition SDDStypes.h:85
#define SDDS_CHARACTER
Identifier for the character data type.
Definition SDDStypes.h:91
#define SDDS_DOUBLE
Identifier for the double data type.
Definition SDDStypes.h:37
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