SDDS ToolKit Programs and Libraries for C and Python
All Classes Files Functions Variables Macros Pages
sddssplit.c
Go to the documentation of this file.
1/**
2 * @file sddssplit.c
3 * @brief Splits an SDDS file into multiple files, each containing a single page.
4 *
5 * @details
6 * This utility reads an SDDS (Self Describing Data Set) file and splits its contents
7 * into multiple output files, with each page stored in a separate file. The tool allows
8 * customization of output filenames, page selection, output format, and more.
9 *
10 * @section Usage
11 * ```
12 * sddssplit <inputFile>
13 * [-pipe[=input]]
14 * [-binary | -ascii]
15 * [-digits=<number>]
16 * [-rootname=<string>]
17 * [-firstPage=<number>]
18 * [-lastPage=<number>]
19 * [-interval=<number>]
20 * [-extension=<string>]
21 * [-groupParameter=<parameterName>]
22 * [-nameParameter=<filenameParameter>]
23 * [-offset=<integer>]
24 * [-majorOrder=row|column]
25 * ```
26 *
27 * @section Options
28 * | Optional | Description |
29 * |-----------------------------------|----------------------------------------------------------------------------------------|
30 * | `-pipe` | Use standard input instead of an input file. |
31 * | `-binary` | Specify output format (binary). |
32 * | `-ascii` | Specify output format (ASCII). |
33 * | `-digits` | Specify number of digits for output file indices. |
34 * | `-rootname` | Rootname for output filenames. Defaults to input file name. |
35 * | `-firstPage` | First page to include in the output. Defaults to 1. |
36 * | `-lastPage` | Last page to include in the output. Defaults to the last page in the input file. |
37 * | `-interval` | Interval between included pages. Defaults to 1. |
38 * | `-extension` | Specify file extension for output files. Defaults to "sdds". |
39 * | `-groupParameter` | Group pages into output files based on the specified parameter. |
40 * | `-nameParameter` | Name output files based on the specified parameter. |
41 * | `-offset` | Offset for page numbering in output filenames. |
42 * | `-majorOrder` | Specify row- or column-major order for output. |
43 *
44 * @copyright
45 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
46 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
47 *
48 * @license
49 * This file is distributed under the terms of the Software License Agreement
50 * found in the file LICENSE included with this distribution.
51 *
52 * @author
53 * M. Borland, C. Saunders, R. Soliday, H. Shang
54 */
55
56#include "mdb.h"
57#include "SDDS.h"
58#include "scan.h"
59
60/* Enumeration for option types */
61typedef enum {
62 SET_BINARY,
63 SET_ASCII,
64 SET_DIGITS,
65 SET_ROOTNAME,
66 SET_FIRST_PAGE,
67 SET_LAST_PAGE,
68 SET_INTERVAL,
69 SET_EXTENSION,
70 SET_PIPE,
71 SET_NAMEPARAMETER,
72 SET_OFFSET,
73 SET_MAJOR_ORDER,
74 SET_GROUPPARAMETER,
75 N_OPTIONS
76} option_type;
77
78static char *option[N_OPTIONS] = {
79 "binary",
80 "ascii",
81 "digits",
82 "rootname",
83 "firstpage",
84 "lastpage",
85 "interval",
86 "extension",
87 "pipe",
88 "nameparameter",
89 "offset",
90 "majorOrder",
91 "groupparameter"};
92
93static char *USAGE =
94 "sddssplit <inputFile> -pipe[=input]\n"
95 " [-binary | -ascii]\n"
96 " [-digits=<number>]\n"
97 " [-rootname=<string>]\n"
98 " [-firstPage=<number>]\n"
99 " [-lastPage=<number>]\n"
100 " [-interval=<number>]\n"
101 " [-extension=<string>]\n"
102 " [-groupParameter=<parameterName>]\n"
103 " [-nameParameter=<filenameParameter>]\n"
104 " [-offset=<integer>]\n"
105 " [-majorOrder=row|column]\n\n"
106
107 "sddssplit splits an SDDS file into many SDDS files, with each page going to a separate file.\n"
108 "The files are named <rootname><integer>.sdds, where <rootname> is either the filename for\n"
109 "the source file or the specified string, and <integer> is by default <page-number>-<offset>\n"
110 "and is printed to the number of digits given by -digits (3 is the default).\n\n"
111
112 "-binary, -ascii Specifies whether binary (default) or ASCII output is desired.\n"
113 "-rootname Rootname to use for output filenames. Defaults to the source filename.\n"
114 "-digits Number of digits to use in the filenames (3 is default).\n"
115 "-firstPage First page of input file to include in output (1 is default).\n"
116 "-lastPage Last page of input file to include in output (EOF is default).\n"
117 "-interval Interval between pages included in output (1 is default).\n"
118 "-extension Extension for output files (sdds is default).\n"
119 "-groupParameter Parameter of input file to use in grouping pages into output files.\n"
120 "-nameParameter Parameter of input file to use for naming the output files.\n"
121 "-offset Offset of page number to compute index for output filename.\n"
122 "-majorOrder Select row- or column-major order output (default is row).\n\n"
123
124 "Program by Michael Borland. ("__DATE__
125 " "__TIME__
126 ", SVN revision: " SVN_VERSION ")\n";
127
128int main(int argc, char **argv) {
129 SDDS_DATASET sdds_dataset, sdds_orig;
130 long i_arg, offset = 0;
131 SCANNED_ARG *s_arg;
132 char *input = NULL, *rootname = NULL, name[500], format[100], *extension = "sdds";
133 long ascii_output = 0, binary_output = 0, retval, digits = 3;
134 long first_page = 0, last_page = 0, interval = 0;
135 unsigned long pipe_flags = 0, major_order_flag = 0;
136 char *file_parameter = NULL, *name_from_parameter = NULL, *group_parameter_name = NULL;
137 char *last_group_parameter = NULL, *this_group_parameter = NULL;
138 short column_major_order = -1, file_active = 0;
139
141 argc = scanargs(&s_arg, argc, argv);
142 if (argc < 2) {
143 fprintf(stderr, "%s", USAGE);
144 return 1;
145 }
146
147 for (i_arg = 1; i_arg < argc; i_arg++) {
148 if (s_arg[i_arg].arg_type == OPTION) {
149 delete_chars(s_arg[i_arg].list[0], "_");
150 switch (match_string(s_arg[i_arg].list[0], option, N_OPTIONS, 0)) {
151 case SET_MAJOR_ORDER:
152 major_order_flag = 0;
153 s_arg[i_arg].n_items--;
154 if (s_arg[i_arg].n_items > 0 &&
155 !scanItemList(&major_order_flag, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
156 "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
157 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)) {
158 fprintf(stderr, "Error: Invalid -majorOrder syntax/values\n");
159 return 1;
160 }
161 column_major_order = (major_order_flag & SDDS_COLUMN_MAJOR_ORDER) ? 1 : 0;
162 break;
163 case SET_BINARY:
164 binary_output = 1;
165 ascii_output = 0;
166 break;
167 case SET_ASCII:
168 ascii_output = 1;
169 binary_output = 0;
170 break;
171 case SET_DIGITS:
172 if (s_arg[i_arg].n_items != 2 || sscanf(s_arg[i_arg].list[1], "%ld", &digits) != 1 || digits <= 0) {
173 fprintf(stderr, "Error: Invalid -digits syntax\n");
174 return 1;
175 }
176 break;
177 case SET_ROOTNAME:
178 if (s_arg[i_arg].n_items != 2) {
179 fprintf(stderr, "Error: Invalid -rootname syntax\n");
180 return 1;
181 }
182 rootname = s_arg[i_arg].list[1];
183 break;
184 case SET_FIRST_PAGE:
185 if (s_arg[i_arg].n_items != 2 || sscanf(s_arg[i_arg].list[1], "%ld", &first_page) != 1 || first_page <= 0) {
186 fprintf(stderr, "Error: Invalid -firstPage syntax\n");
187 return 1;
188 }
189 break;
190 case SET_LAST_PAGE:
191 if (s_arg[i_arg].n_items != 2 || sscanf(s_arg[i_arg].list[1], "%ld", &last_page) != 1 || last_page <= 0) {
192 fprintf(stderr, "Error: Invalid -lastPage syntax\n");
193 return 1;
194 }
195 break;
196 case SET_INTERVAL:
197 if (s_arg[i_arg].n_items != 2 || sscanf(s_arg[i_arg].list[1], "%ld", &interval) != 1 || interval <= 0) {
198 fprintf(stderr, "Error: Invalid -interval syntax\n");
199 return 1;
200 }
201 break;
202 case SET_EXTENSION:
203 if (s_arg[i_arg].n_items != 2) {
204 fprintf(stderr, "Error: Invalid -extension syntax\n");
205 return 1;
206 }
207 extension = s_arg[i_arg].list[1];
208 break;
209 case SET_OFFSET:
210 if (s_arg[i_arg].n_items != 2 || sscanf(s_arg[i_arg].list[1], "%ld", &offset) != 1) {
211 fprintf(stderr, "Error: Invalid -offset syntax\n");
212 return 1;
213 }
214 break;
215 case SET_PIPE:
216 pipe_flags = USE_STDIN;
217 break;
218 case SET_NAMEPARAMETER:
219 if (s_arg[i_arg].n_items != 2) {
220 fprintf(stderr, "Error: Invalid -nameParameter syntax\n");
221 return 1;
222 }
223 file_parameter = s_arg[i_arg].list[1];
224 break;
225 case SET_GROUPPARAMETER:
226 if (s_arg[i_arg].n_items != 2) {
227 fprintf(stderr, "Error: Invalid -groupParameter syntax\n");
228 return 1;
229 }
230 group_parameter_name = s_arg[i_arg].list[1];
231 break;
232 default:
233 fprintf(stderr, "Error: Unknown switch: %s\n", s_arg[i_arg].list[0]);
234 fprintf(stderr, "%s", USAGE);
235 return 1;
236 }
237 } else {
238 if (!input) {
239 input = s_arg[i_arg].list[0];
240 } else {
241 fprintf(stderr, "Error: Too many filenames\n");
242 return 1;
243 }
244 }
245 }
246
247 if (!input && !(pipe_flags & USE_STDIN)) {
248 fprintf(stderr, "Error: Missing input filename\n");
249 return 1;
250 }
251
252 if (pipe_flags & USE_STDIN && !file_parameter && !rootname) {
253 fprintf(stderr, "Error: Provide -rootname or -nameParameter with -pipe\n");
254 return 1;
255 }
256
257 if (!rootname && !file_parameter) {
258 if ((rootname = strrchr(input, '.'))) {
259 *rootname = 0;
260 SDDS_CopyString(&rootname, input);
261 input[strlen(input)] = '.';
262 } else {
263 SDDS_CopyString(&rootname, input);
264 }
265 }
266
267 if (first_page && last_page && first_page > last_page) {
268 fprintf(stderr, "Error: firstPage > lastPage\n");
269 return 1;
270 }
271
272 if (!SDDS_InitializeInput(&sdds_orig, input)) {
273 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
274 return 1;
275 }
276
277 if (!extension || SDDS_StringIsBlank(extension)) {
278 extension = NULL;
279 snprintf(format, sizeof(format), "%%s%%0%ldld", digits);
280 } else {
281 snprintf(format, sizeof(format), "%%s%%0%ldld.%s", digits, extension);
282 }
283
284 if (file_parameter &&
285 SDDS_CheckParameter(&sdds_orig, file_parameter, NULL, SDDS_STRING, stderr) != SDDS_CHECK_OKAY) {
286 fprintf(stderr, "Error: Filename parameter not present or wrong type\n");
287 return 1;
288 }
289
290 last_group_parameter = NULL;
291 while ((retval = SDDS_ReadPage(&sdds_orig)) > 0) {
292 if (first_page && retval < first_page) {
293 continue;
294 }
295 if (last_page && retval > last_page) {
296 break;
297 }
298 if (interval) {
299 if (first_page) {
300 if ((retval - first_page) % interval != 0) {
301 continue;
302 }
303 } else if ((retval - 1) % interval != 0) {
304 continue;
305 }
306 }
307 if (file_parameter) {
308 if (!SDDS_GetParameter(&sdds_orig, file_parameter, &name_from_parameter)) {
309 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
310 return 1;
311 }
312 strncpy(name, name_from_parameter, sizeof(name) - 1);
313 name[sizeof(name) - 1] = '\0';
314 free(name_from_parameter);
315 } else {
316 snprintf(name, sizeof(name), format, rootname, retval - offset);
317 }
318 if (group_parameter_name) {
319 if (!SDDS_GetParameterAsString(&sdds_orig, group_parameter_name, &this_group_parameter)) {
320 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
321 return 1;
322 }
323 }
324 if (!group_parameter_name || !last_group_parameter ||
325 (group_parameter_name && strcmp(this_group_parameter, last_group_parameter))) {
326 if (file_active && !SDDS_Terminate(&sdds_dataset)) {
327 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
328 return 1;
329 }
330 file_active = 0;
331 if (!SDDS_InitializeCopy(&sdds_dataset, &sdds_orig, name, "w")) {
332 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
333 return 1;
334 }
335 if ((ascii_output && sdds_dataset.layout.data_mode.mode != SDDS_ASCII) ||
336 (binary_output && sdds_dataset.layout.data_mode.mode != SDDS_BINARY)) {
337 sdds_dataset.layout.data_mode.mode = ascii_output ? SDDS_ASCII : SDDS_BINARY;
338 }
339 sdds_dataset.layout.data_mode.column_major = (column_major_order != -1) ? column_major_order : sdds_orig.layout.data_mode.column_major;
340 if (!SDDS_WriteLayout(&sdds_dataset)) {
341 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
342 return 1;
343 }
344 file_active = 1;
345 }
346 if (group_parameter_name) {
347 free(last_group_parameter);
348 last_group_parameter = this_group_parameter;
349 this_group_parameter = NULL;
350 }
351 if (!SDDS_CopyPage(&sdds_dataset, &sdds_orig) || !SDDS_WritePage(&sdds_dataset)) {
352 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
353 return 1;
354 }
355 }
356 if (retval == 0) {
357 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
358 return 1;
359 }
360 if (!SDDS_Terminate(&sdds_orig)) {
361 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
362 return 1;
363 }
364 return 0;
365}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t SDDS_InitializeCopy(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source, char *filename, char *filemode)
Definition SDDS_copy.c:40
int32_t SDDS_CopyPage(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source)
Definition SDDS_copy.c:578
char * SDDS_GetParameterAsString(SDDS_DATASET *SDDS_dataset, char *parameter_name, char **memory)
Retrieves the value of a specified parameter as a string from the current data table of an SDDS datas...
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_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_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.
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).
int32_t SDDS_CheckParameter(SDDS_DATASET *SDDS_dataset, char *name, char *units, int32_t type, FILE *fp_message)
Checks if a parameter exists in the SDDS dataset with the specified name, units, and type.
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
#define SDDS_STRING
Identifier for the string data type.
Definition SDDStypes.h:85
char * delete_chars(char *s, char *t)
Removes all occurrences of characters found in string t from string s.
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 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.