SDDS ToolKit Programs and Libraries for C and Python
All Classes Files Functions Variables Macros Pages
sddssequence.c
Go to the documentation of this file.
1/**
2 * @file sddssequence.c
3 * @brief Generates an SDDS file with equispaced indices in a column.
4 *
5 * @details
6 * This program creates an SDDS file containing a single page with one or more columns of data. The columns can be defined, and sequences of values can be generated using user-specified parameters. Multiple sequences, repeats, and page breaks are supported.
7 *
8 * @section Usage
9 * ```
10 * sddssequence [<outputfile>]
11 * [-pipe=<output>]
12 * -define=<columnName>[,<definitionEntries>]
13 * [-repeat=<number>]
14 * [-break]
15 * -sequence=begin=<value>[,number=<integer>][,end=<value>][,delta=<value>][,interval=<integer>]
16 * [-sequence=...]
17 * [-majorOrder=row|column]
18 * ```
19 *
20 * @section Options
21 * | Required | Description |
22 * |---------------------------------------|---------------------------------------------------------------------------------------|
23 * | `-define` | Define a column with the given name and its entries. |
24 * | `-sequence` | Specify a sequence with flexible parameters (start, end, delta, interval). |
25 *
26 * | Optional | Description |
27 * |---------------------------------------|---------------------------------------------------------------------------------------|
28 * | `-pipe` | Define pipe output options. |
29 * | `-repeat` | Repeat the sequence a specified number of times. |
30 * | `-break` | Insert a page break between repeats. |
31 * | `-majorOrder` | Specify the major order for data storage (row or column). |
32 *
33 * @subsection Incompatibilities
34 * - `-break` requires `-repeat=<number>`.
35 * - `-sequence` parameters must conform to one of these combinations:
36 * - `end` and `delta`
37 * - `end` and `number`
38 * - `delta` and `number`
39 *
40 * @copyright
41 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
42 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
43 *
44 * @license
45 * This file is distributed under the terms of the Software License Agreement
46 * found in the file LICENSE included with this distribution.
47 *
48 * @authors
49 * - M. Borland
50 * - C. Saunders
51 * - L. Emery
52 * - R. Soliday
53 * - H. Shang
54 */
55
56#include <stdlib.h>
57#include "mdb.h"
58#include "SDDS.h"
59#include "scan.h"
60
61/* Enumeration for option types */
62enum option_type {
63 SET_PIPE,
64 SET_DEFINE,
65 SET_SEQUENCE,
66 SET_REPEAT,
67 SET_MAJOR_ORDER,
68 SET_BREAK,
69 N_OPTIONS
70};
71
72char *option[N_OPTIONS] = {
73 "pipe",
74 "define",
75 "sequence",
76 "repeat",
77 "majorOrder",
78 "break",
79};
80
81/* Improved usage message with enhanced readability */
82static char *USAGE =
83 "sddssequence [<outputfile>] \\\n"
84 " [-pipe=<output>] \\\n"
85 " -define=<columnName>[,<definitionEntries>] \\\n"
86 " [-repeat=<number>] \\\n"
87 " [-break] \\\n"
88 " -sequence=begin=<value>[,number=<integer>][,end=<value>][,delta=<value>][,interval=<integer>] \\\n"
89 " [-sequence=begin=<value>[,number=<integer>][,end=<value>][,delta=<value>][,interval=<integer>] ...] \\\n"
90 " [-majorOrder=row|column]\n"
91 "Generates an SDDS file with a single page and several columns of data.\n"
92 "Options:\n"
93 " <outputfile> Specify the output SDDS file. If omitted, standard output is used.\n"
94 " -pipe=<output> Define pipe output options.\n"
95 " -define=<columnName>,<entries> Define a column with the given name and entries.\n"
96 " -repeat=<number> Repeat the sequence the specified number of times.\n"
97 " -break Insert a page break between repeats.\n"
98 " -sequence=begin=<val>,number=<n>,end=<val>,delta=<val>,interval=<n>\n"
99 " Define a sequence with specified parameters. Multiple -sequence options can be used.\n"
100 " -majorOrder=row|column Set the major order of data storage.\n\n"
101 "Notes:\n"
102 " - The default data type is double. To specify a different type, use type=<typeName> in -define.\n"
103 " - Each column is specified with a -define option followed by any number of -sequence options.\n"
104 " - The default value of delta is 1.\n"
105 " - The default beginning value is the ending value of the last sequence plus the delta of the last sequence.\n\n"
106 "Program by Michael Borland. (" __DATE__ " " __TIME__ ", SVN revision: " SVN_VERSION ")\n";
107
108#define SEQ_END_GIVEN 0x0001
109#define SEQ_BEGIN_GIVEN 0x0002
110#define SEQ_NUMBER_GIVEN 0x0004
111#define SEQ_DELTA_GIVEN 0x0008
112#define SEQ_INTERVAL_GIVEN 0x0010
113
114/* Valid combinations of end, number, and delta: */
115#define SEQ_ENDplusDELTA (SEQ_END_GIVEN + SEQ_DELTA_GIVEN)
116#define SEQ_ENDplusNUMBER (SEQ_END_GIVEN + SEQ_NUMBER_GIVEN)
117#define SEQ_DELTAplusNUMBER (SEQ_DELTA_GIVEN + SEQ_NUMBER_GIVEN)
118
119typedef struct {
120 unsigned long flags;
121 double begin, end, delta;
122 int64_t number, interval;
123} SEQUENCE;
124
125typedef struct {
126 char *columnName;
127 char **item;
128 SEQUENCE *sequence;
129 long items;
130 long sequences;
131 long rows;
132 long repeats;
133 double *data;
134} DEFINITION;
135
136void addSequence(char **item, long items, DEFINITION *definition);
137void addDefinition(char **item, long items, DEFINITION **definition, long *definitions);
138void generateOutput(SDDS_DATASET *outputTable, DEFINITION *definition, long definitions, long doBreak);
139void setupOutputFile(SDDS_DATASET *outputTable, char *output, DEFINITION *definition, long definitions, short columnMajorOrder);
140void createColumn(SDDS_DATASET *outputTable, DEFINITION *definition);
141
142int main(int argc, char **argv) {
143 SDDS_DATASET outputTable;
144 SCANNED_ARG *s_arg;
145 long i_arg, i;
146 DEFINITION *definition = NULL;
147 long definitions = 0;
148 long doBreak = 0;
149
150 char *output = NULL;
151 unsigned long pipeFlags = 0, majorOrderFlag;
152 short columnMajorOrder = 0;
153
155 argc = scanargs(&s_arg, argc, argv);
156 if (argc < 2) {
157 bomb(NULL, USAGE);
158 }
159
160 for (i_arg = 1; i_arg < argc; i_arg++) {
161 if (s_arg[i_arg].arg_type == OPTION) {
162 switch (match_string(s_arg[i_arg].list[0], option, N_OPTIONS, 0)) {
163 case SET_MAJOR_ORDER:
164 majorOrderFlag = 0;
165 s_arg[i_arg].n_items--;
166 if (s_arg[i_arg].n_items > 0 &&
167 !scanItemList(&majorOrderFlag, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
168 "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
169 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)) {
170 SDDS_Bomb("invalid -majorOrder syntax/values");
171 }
172 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER) {
173 columnMajorOrder = 1;
174 } else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER) {
175 columnMajorOrder = 0;
176 }
177 break;
178
179 case SET_DEFINE:
180 addDefinition(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, &definition, &definitions);
181 break;
182
183 case SET_REPEAT:
184 if (definitions == 0) {
185 SDDS_Bomb("can't give a repeat specifier prior to a definition");
186 }
187 if (s_arg[i_arg].n_items != 2 ||
188 sscanf(s_arg[i_arg].list[1], "%ld", &definition[definitions - 1].repeats) != 1 ||
189 definition[definitions - 1].repeats <= 0) {
190 SDDS_Bomb("invalid -repeat syntax/value");
191 }
192 break;
193
194 case SET_BREAK:
195 doBreak = 1;
196 break;
197
198 case SET_SEQUENCE:
199 if (definitions == 0) {
200 SDDS_Bomb("can't create a sequence prior to defining the variable");
201 }
202 addSequence(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, definition + definitions - 1);
203 break;
204
205 case SET_PIPE:
206 if (!processPipeOption(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, &pipeFlags)) {
207 SDDS_Bomb("invalid -pipe syntax");
208 }
209 break;
210
211 default:
212 fprintf(stderr, "error: unknown/ambiguous option: %s\n", s_arg[i_arg].list[0]);
213 exit(EXIT_FAILURE);
214 break;
215 }
216 } else {
217 if (output == NULL) {
218 output = s_arg[i_arg].list[0];
219 } else {
220 SDDS_Bomb("too many filenames");
221 }
222 }
223 }
224
225 if (output == NULL && !(pipeFlags & USE_STDOUT)) {
226 SDDS_Bomb("no output specified");
227 }
228
229 if (!definitions) {
230 SDDS_Bomb("no sequences defined");
231 }
232
233 setupOutputFile(&outputTable, output, definition, definitions, columnMajorOrder);
234 generateOutput(&outputTable, definition, definitions, doBreak);
235
236 if (!SDDS_Terminate(&outputTable)) {
237 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
238 exit(EXIT_FAILURE);
239 }
240
241 for (i = 0; i < definitions; i++) {
242 free(definition[i].sequence);
243 free(definition[i].data);
244 }
245 free(definition);
246 free_scanargs(&s_arg, argc);
247
248 return EXIT_SUCCESS;
249}
250
251void addDefinition(char **item, long items, DEFINITION **definition, long *definitions) {
252 if (items < 1) {
253 SDDS_Bomb("unable to add definition--supply column name");
254 }
255 *definition = SDDS_Realloc(*definition, sizeof(**definition) * (*definitions + 1));
256 if (!(*definition)) {
257 SDDS_Bomb("unable to add definition---allocation failure");
258 }
259
260 (*definition)[*definitions].columnName = item[0];
261 (*definition)[*definitions].item = item + 1;
262 (*definition)[*definitions].items = items - 1;
263 (*definition)[*definitions].sequence = NULL;
264 (*definition)[*definitions].sequences = 0;
265 (*definition)[*definitions].rows = 0;
266 (*definition)[*definitions].data = NULL;
267 (*definition)[*definitions].repeats = 1;
268 (*definitions)++;
269}
270
271void addSequence(char **item, long items, DEFINITION *definition) {
272 SEQUENCE *sequence;
273 long i;
274
275 definition->sequence = SDDS_Realloc(definition->sequence, sizeof(*definition->sequence) * (definition->sequences + 1));
276 if (!definition->sequence) {
277 SDDS_Bomb("unable to add sequence--memory allocation failure");
278 }
279
280 sequence = &definition->sequence[definition->sequences];
281 sequence->interval = 1;
282
283 if (!scanItemList(&sequence->flags, item, &items, 0,
284 "begin", SDDS_DOUBLE, &sequence->begin, 1, SEQ_BEGIN_GIVEN,
285 "end", SDDS_DOUBLE, &sequence->end, 1, SEQ_END_GIVEN,
286 "number", SDDS_LONG64, &sequence->number, 1, SEQ_NUMBER_GIVEN,
287 "delta", SDDS_DOUBLE, &sequence->delta, 1, SEQ_DELTA_GIVEN,
288 "interval", SDDS_LONG64, &sequence->interval, 1, SEQ_INTERVAL_GIVEN,
289 NULL)) {
290 SDDS_Bomb("invalid -sequence syntax");
291 }
292
293 if ((sequence->flags & SEQ_NUMBER_GIVEN) && sequence->number <= 0) {
294 SDDS_Bomb("number <= 0 is not valid for -sequence");
295 }
296
297 if ((sequence->flags & SEQ_DELTA_GIVEN) && sequence->delta == 0) {
298 SDDS_Bomb("delta == 0 is not valid for -sequence");
299 }
300
301 if (!(sequence->flags & SEQ_BEGIN_GIVEN)) {
302 if (definition->sequences == 0) {
303 SDDS_Bomb("you must give begin point for the first sequence of a definition");
304 }
305 if (!(sequence->flags & SEQ_DELTA_GIVEN)) {
306 SDDS_Bomb("you must give delta with implied begin point");
307 }
308 sequence->begin = definition->sequence[definition->sequences - 1].end + sequence->delta;
309 }
310
311 if ((sequence->flags & SEQ_INTERVAL_GIVEN) && sequence->interval <= 0) {
312 SDDS_Bomb("interval for sequence must be > 0");
313 }
314
315 if ((sequence->flags & SEQ_ENDplusDELTA) == SEQ_ENDplusDELTA) {
316 sequence->number = ((long)((sequence->end - sequence->begin) / sequence->delta + 1.5)) * sequence->interval;
317 if (sequence->number <= 0) {
318 SDDS_Bomb("given (start, end, delta) implies number of points <= 0");
319 }
320 } else if ((sequence->flags & SEQ_ENDplusNUMBER) == SEQ_ENDplusNUMBER) {
321 if (sequence->number == 1) {
322 sequence->delta = 0;
323 } else {
324 sequence->delta = (sequence->end - sequence->begin) / (sequence->number - 1) * sequence->interval;
325 }
326 } else if ((sequence->flags & SEQ_DELTAplusNUMBER) == SEQ_DELTAplusNUMBER) {
327 sequence->end = (sequence->delta / sequence->interval) * (sequence->number - 1) + sequence->begin;
328 } else {
329 SDDS_Bomb("you must supply (end, delta), (end, number), or (delta, number)");
330 }
331
332 definition->data = SDDS_Realloc(definition->data, sizeof(*definition->data) * (definition->rows + sequence->number));
333 if (!definition->data) {
334 SDDS_Bomb("unable to generate sequence data--allocation failure");
335 }
336
337 for (i = 0; i < sequence->number; i++) {
338 definition->data[definition->rows + i] = sequence->begin + (i / sequence->interval) * sequence->delta;
339 }
340
341 definition->rows += sequence->number;
342 definition->sequences++;
343}
344
345void generateOutput(SDDS_DATASET *outputTable, DEFINITION *definition, long definitions, long doBreak) {
346 long idef, row, rows = 0, totalRows = 0;
347
348 if (!doBreak) {
349 for (idef = 0; idef < definitions; idef++) {
350 totalRows = definition[idef].rows * definition[idef].repeats;
351 if (idef && totalRows != rows) {
352 fputs("warning: sequences are of different length (sddssequence)\n", stderr);
353 }
354 if (totalRows > rows) {
355 rows = totalRows;
356 }
357 }
358
359 if (rows == 0) {
360 SDDS_Bomb("total number of points in sequence is zero");
361 }
362
363 if (!SDDS_StartPage(outputTable, rows)) {
364 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
365 }
366
367 for (idef = 0; idef < definitions; idef++) {
368 if (definition[idef].rows != totalRows) {
369 /* repeats are carried out here */
370 definition[idef].data = SDDS_Realloc(definition[idef].data, sizeof(*definition[idef].data) * rows);
371 if (!definition[idef].data) {
372 SDDS_Bomb("unable to generate output--allocation failure");
373 }
374 for (row = definition[idef].rows; row < rows; row++) {
375 definition[idef].data[row] = definition[idef].data[row % definition[idef].rows];
376 }
377 }
378 if (!SDDS_SetColumnFromDoubles(outputTable, SDDS_BY_NAME, definition[idef].data, rows, definition[idef].columnName)) {
379 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
380 }
381 }
382
383 if (!SDDS_WritePage(outputTable)) {
384 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
385 }
386 } else {
387 long irep;
388 rows = definition[0].rows;
389 if (rows == 0) {
390 SDDS_Bomb("number of points in sequence is zero");
391 }
392 for (idef = 1; idef < definitions; idef++) {
393 if (rows != definition[idef].rows) {
394 fputs("warning: sequences are of different length (sddssequence)\n", stderr);
395 }
396 }
397 for (irep = 0; irep < definition[0].repeats; irep++) {
398 if (!SDDS_StartPage(outputTable, rows)) {
399 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
400 }
401 for (idef = 0; idef < definitions; idef++) {
402 if (!SDDS_SetColumnFromDoubles(outputTable, SDDS_BY_NAME, definition[idef].data, rows, definition[idef].columnName)) {
403 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
404 }
405 }
406 if (!SDDS_WritePage(outputTable)) {
407 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
408 }
409 }
410 }
411}
412
413void setupOutputFile(SDDS_DATASET *outputTable, char *output, DEFINITION *definition, long definitions, short columnMajorOrder) {
414 long i;
415
416 if (!SDDS_InitializeOutput(outputTable, SDDS_BINARY, 0, NULL, "sddssequence output", output)) {
417 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
418 }
419
420 for (i = 0; i < definitions; i++) {
421 createColumn(outputTable, &definition[i]);
422 }
423
424 outputTable->layout.data_mode.column_major = columnMajorOrder;
425 if (!SDDS_WriteLayout(outputTable)) {
426 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
427 }
428}
429
430void createColumn(SDDS_DATASET *outputTable, DEFINITION *definition) {
431 char s[SDDS_MAXLINE];
432 char *ptr;
433 long i;
434
435 if (!definition->columnName) {
436 SDDS_Bomb("column name is null");
437 }
438 if (SDDS_GetColumnIndex(outputTable, definition->columnName) >= 0) {
439 SDDS_Bomb("column name already exists (sddssequence)");
440 }
441
442 /* Initialize the column definition string */
443 snprintf(s, sizeof(s), "&column name=%s, ", definition->columnName);
444
445 for (i = 0; i < definition->items; i++) {
446 ptr = strchr(definition->item[i], '=');
447 if (!ptr) {
448 fprintf(stderr, "error: invalid definition-entry: %s\n", definition->item[i]);
449 exit(EXIT_FAILURE);
450 }
451 *ptr = '\0';
452 strcat(s, definition->item[i]);
453 strcat(s, "=\"");
454 strcat(s, ptr + 1);
455 strcat(s, "\", ");
456 }
457
458 /* Ensure type is specified, default to double if not */
459 if (!strstr(s, ", type=")) {
460 strcat(s, " type=\"double\", ");
461 }
462
463 strcat(s, "&end");
464
465 if (!SDDS_ProcessColumnString(outputTable, s, 0)) {
466 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
467 }
468}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
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_Terminate(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_ProcessColumnString(SDDS_DATASET *SDDS_dataset, char *string, int32_t mode)
Process a column definition string.
int32_t SDDS_GetColumnIndex(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the index of a named column 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
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
Definition SDDS_utils.c:342
void * SDDS_Realloc(void *old_ptr, size_t new_size)
Reallocates memory to a new size.
Definition SDDS_utils.c:677
#define SDDS_DOUBLE
Identifier for the double data type.
Definition SDDStypes.h:37
#define SDDS_LONG64
Identifier for the signed 64-bit integer data type.
Definition SDDStypes.h:49
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 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.