SDDS ToolKit Programs and Libraries for C and Python
Loading...
Searching...
No Matches
sddstimeconvert.c
Go to the documentation of this file.
1/**
2 * @file sddstimeconvert.c
3 * @brief Perform time conversions on SDDS data.
4 *
5 * @details
6 * This program enables users to perform various time-related operations on SDDS files.
7 * These operations include breaking down epoch times into components, converting date
8 * strings to epoch times, and specifying the major order of output data.
9 *
10 * @section Usage
11 * ```
12 * sddstimeconvert [<SDDSinput>] [<SDDSoutput>]
13 * [-pipe=<input>[,<output>]]
14 * [-majorOrder=row|column]
15 * [-breakdown={column|parameter},<timeName>[,year=<newName>][,julianDay=<newName>][,month=<newName>][,day=<newName>][,hour=<newName>][,text=<newName>]]
16 * [-dateToTime={column|parameter},<timeName>,<newName>,<stringName>,format=<formatString>]
17 * [-epoch={column|parameter},<newName>,year=<name>,[julianDay=<name>|month=<name>,day=<name>],hour=<name>]
18 * ```
19 *
20 * @section Options
21 * | Optional | Description |
22 * |---------------------------------------|---------------------------------------------------------------------------------------|
23 * | `-pipe` | Enable pipe-based input/output processing. |
24 * | `-majorOrder` | Specify output data order: row-major or column-major. |
25 * | `-breakdown=` | Break down epoch time into components such as year, month, day, hour, etc. |
26 * | `-dateToTime` | Convert date strings to epoch times based on a specified format string. |
27 * | `-epoch` | Generate a new epoch time column or parameter with optional qualifiers. |
28 *
29 * @subsection Incompatibilities
30 * - For `-epoch`, the following requirements must be met:
31 * - Specify either `julianDay` or both `month` and `day` names.
32 * - For `-breakdown`, at least one of the following must be specified:
33 * - `year`, `julianDay`, `month`, `day`, `hour`, or `text` qualifiers.
34 * - For `-dateToTime`, the `format` string is required.
35 *
36 * @copyright
37 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
38 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
39 *
40 * @license
41 * This file is distributed under the terms of the Software License Agreement
42 * found in the file LICENSE included with this distribution.
43 *
44 * @authors
45 * - M. Borland
46 * - R. Soliday
47 * - H. Shang
48 */
49
50#define _XOPEN_SOURCE
51#include <ctype.h>
52#include <time.h>
53#include "mdb.h"
54#include "SDDS.h"
55#include "scan.h"
56
57/* Enumeration for option types */
58enum option_type {
59 SET_EPOCH,
60 SET_PIPE,
61 SET_BREAKDOWN,
62 SET_MAJOR_ORDER,
63 SET_DATE,
64 N_OPTIONS
65};
66
67char *option[N_OPTIONS] = {
68 "epoch",
69 "pipe",
70 "breakdown",
71 "majorOrder",
72 "date",
73};
74
75/* Improved and more readable usage message */
76char *USAGE =
77 "Usage:\n"
78 " sddstimeconvert [<SDDSinput>] [<SDDSoutput>] \n"
79 " [-pipe=<input>[,<output>]] \n"
80 " [-majorOrder=row|column]\n"
81 " [-breakdown={column|parameter},<timeName>[,year=<newName>]\n"
82 " [,julianDay=<newName>]\n"
83 " [,month=<newName>]\n"
84 " [,day=<newName>]\n"
85 " [,hour=<newName>]\n"
86 " [,text=<newName>]]\n"
87 " [-dateToTime={column|parameter},<timeName>,<newName>,<stringName>,format=<formatString>]\n"
88 " [-epoch={column|parameter},<newName>,year=<name>,[julianDay=<name>|month=<name>,day=<name>],hour=<name>]\n"
89 "Options:\n"
90 " -pipe Enable standard SDDS Toolkit pipe processing.\n"
91 " -majorOrder Specify output file order: row or column major.\n"
92 " -breakdown Break down epoch time into components.\n"
93 " -epoch Create a new epoch time column or parameter.\n"
94 " -dateToTime Convert date string to epoch time.\n\n"
95 "Program by Michael Borland. (" __DATE__ " " __TIME__ ", SVN revision: " SVN_VERSION ")\n";
96
97#define IS_COLUMN 0x0001U
98#define IS_PARAMETER 0x0002U
99#define EPOCH_GIVEN 0x0004U
100#define YEAR_GIVEN 0x0008U
101#define JDAY_GIVEN 0x0010U
102#define MONTH_GIVEN 0x0020U
103#define DAY_GIVEN 0x0040U
104#define HOUR_GIVEN 0x0080U
105#define DO_BREAKDOWN 0x0100U
106#define DO_EPOCH 0x0200U
107#define TEXT_GIVEN 0x0400U
108#define FORMAT_GIVEN 0x0800U
109#define DO_DATECONVERSION 0x1000U
110
111typedef struct
112{
113 char *epochName, *yearName, *jDayName, *monthName, *dayName, *hourName;
114 char *textName, *format;
115 long epochIndex, yearIndex, jDayIndex, monthIndex, dayIndex, hourIndex;
116 long textIndex;
117 unsigned long flags;
119
120void DoColumnEpochConversion(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion);
121void DoParameterEpochConversion(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion);
122void DoColumnDateToTimeConversion(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion);
123void DoParameterDateToTimeConversion(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion);
124void DoColumnBreakdownConversion(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion);
125void DoParameterBreakdownConversion(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion);
126void InitializeOutput(SDDS_DATASET *SDDSout, char *outputfile, TIME_CONVERSION *conversion, long conversions,
127 SDDS_DATASET *SDDSin, short columnMajorOrder);
128void CheckEpochConversionElements(SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion, long conversions);
129void CheckBreakdownConversionElements(SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion, long conversions);
130void CheckDateConversionElements(SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion, long conversions);
131
132#if defined(_WIN32)
133typedef struct {
134 struct tm *value;
135 int century;
136 int shortYear;
137 int twelveHour;
138 int meridiem;
139 int julianDay;
140} DATE_PARSE_STATE;
141
142static const char *parseDateNumber(const char *input, int minimumDigits, int maximumDigits,
143 int minimumValue, int maximumValue, int *value) {
144 int digits = 0, result = 0;
145
146 while (digits < maximumDigits && isdigit((unsigned char)*input)) {
147 result = 10 * result + (*input - '0');
148 input++;
149 digits++;
150 }
151 if (digits < minimumDigits || result < minimumValue || result > maximumValue)
152 return NULL;
153 *value = result;
154 return input;
155}
156
157static int dateTextMatches(const char *input, const char *text) {
158 int length = 0;
159
160 while (text[length]) {
161 if (!input[length] ||
162 tolower((unsigned char)input[length]) != tolower((unsigned char)text[length]))
163 return 0;
164 length++;
165 }
166 return length;
167}
168
169static const char *parseDateName(const char *input, const char *const *names, int namesCount, int *index) {
170 int i, length;
171
172 for (i = 0; i < namesCount; i++) {
173 if ((length = dateTextMatches(input, names[i]))) {
174 *index = i;
175 return input + length;
176 }
177 }
178 return NULL;
179}
180
181static const char *parseWindowsDateFormat(const char *input, const char *format, DATE_PARSE_STATE *state) {
182 static const char *const abbreviatedMonth[] = {
183 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
184 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
185 };
186 static const char *const fullMonth[] = {
187 "January", "February", "March", "April", "May", "June",
188 "July", "August", "September", "October", "November", "December"
189 };
190 static const char *const abbreviatedWeekday[] = {
191 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
192 };
193 static const char *const fullWeekday[] = {
194 "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
195 };
196 static const char *const meridiem[] = {"AM", "PM"};
197 const char *parsed;
198 int value;
199
200 while (*format) {
201 if (isspace((unsigned char)*format)) {
202 while (isspace((unsigned char)*format))
203 format++;
204 while (isspace((unsigned char)*input))
205 input++;
206 continue;
207 }
208 if (*format != '%') {
209 if (*input != *format)
210 return NULL;
211 input++;
212 format++;
213 continue;
214 }
215
216 format++;
217 if (*format == 'E' || *format == 'O')
218 format++;
219 if (!*format)
220 return NULL;
221
222 switch (*format++) {
223 case '%':
224 if (*input++ != '%')
225 return NULL;
226 break;
227 case 'Y':
228 if (!(input = parseDateNumber(input, 1, 4, 0, 9999, &value)))
229 return NULL;
230 state->value->tm_year = value - 1900;
231 break;
232 case 'C':
233 if (!(input = parseDateNumber(input, 1, 2, 0, 99, &state->century)))
234 return NULL;
235 break;
236 case 'y':
237 if (!(input = parseDateNumber(input, 1, 2, 0, 99, &state->shortYear)))
238 return NULL;
239 break;
240 case 'm':
241 if (!(input = parseDateNumber(input, 1, 2, 1, 12, &value)))
242 return NULL;
243 state->value->tm_mon = value - 1;
244 break;
245 case 'b':
246 case 'h':
247 if (!(input = parseDateName(input, abbreviatedMonth, 12, &value)))
248 return NULL;
249 state->value->tm_mon = value;
250 break;
251 case 'B':
252 if (!(input = parseDateName(input, fullMonth, 12, &value)))
253 return NULL;
254 state->value->tm_mon = value;
255 break;
256 case 'd':
257 if (!(input = parseDateNumber(input, 1, 2, 1, 31, &state->value->tm_mday)))
258 return NULL;
259 break;
260 case 'e':
261 while (*input == ' ')
262 input++;
263 if (!(input = parseDateNumber(input, 1, 2, 1, 31, &state->value->tm_mday)))
264 return NULL;
265 break;
266 case 'H':
267 case 'k':
268 while (*input == ' ')
269 input++;
270 if (!(input = parseDateNumber(input, 1, 2, 0, 23, &state->value->tm_hour)))
271 return NULL;
272 break;
273 case 'I':
274 case 'l':
275 while (*input == ' ')
276 input++;
277 if (!(input = parseDateNumber(input, 1, 2, 1, 12, &state->value->tm_hour)))
278 return NULL;
279 state->twelveHour = 1;
280 break;
281 case 'M':
282 if (!(input = parseDateNumber(input, 1, 2, 0, 59, &state->value->tm_min)))
283 return NULL;
284 break;
285 case 'S':
286 if (!(input = parseDateNumber(input, 1, 2, 0, 60, &state->value->tm_sec)))
287 return NULL;
288 break;
289 case 'j':
290 if (!(input = parseDateNumber(input, 1, 3, 1, 366, &state->julianDay)))
291 return NULL;
292 state->value->tm_yday = state->julianDay - 1;
293 break;
294 case 'a':
295 if (!(input = parseDateName(input, abbreviatedWeekday, 7, &state->value->tm_wday)))
296 return NULL;
297 break;
298 case 'A':
299 if (!(input = parseDateName(input, fullWeekday, 7, &state->value->tm_wday)))
300 return NULL;
301 break;
302 case 'w':
303 if (!(input = parseDateNumber(input, 1, 1, 0, 6, &state->value->tm_wday)))
304 return NULL;
305 break;
306 case 'u':
307 if (!(input = parseDateNumber(input, 1, 1, 1, 7, &value)))
308 return NULL;
309 state->value->tm_wday = value % 7;
310 break;
311 case 'p':
312 case 'P':
313 if (!(input = parseDateName(input, meridiem, 2, &state->meridiem)))
314 return NULL;
315 break;
316 case 'n':
317 case 't':
318 while (isspace((unsigned char)*input))
319 input++;
320 break;
321 case 'D':
322 if (!(input = parseWindowsDateFormat(input, "%m/%d/%y", state)))
323 return NULL;
324 break;
325 case 'F':
326 if (!(input = parseWindowsDateFormat(input, "%Y-%m-%d", state)))
327 return NULL;
328 break;
329 case 'R':
330 if (!(input = parseWindowsDateFormat(input, "%H:%M", state)))
331 return NULL;
332 break;
333 case 'T':
334 case 'X':
335 if (!(input = parseWindowsDateFormat(input, "%H:%M:%S", state)))
336 return NULL;
337 break;
338 case 'r':
339 if (!(input = parseWindowsDateFormat(input, "%I:%M:%S %p", state)))
340 return NULL;
341 break;
342 case 'x':
343 if (!(input = parseWindowsDateFormat(input, "%m/%d/%y", state)))
344 return NULL;
345 break;
346 case 'c':
347 if (!(input = parseWindowsDateFormat(input, "%a %b %e %H:%M:%S %Y", state)))
348 return NULL;
349 break;
350 case 'Z':
351 parsed = input;
352 while (isalpha((unsigned char)*input) || *input == '_' || *input == '/')
353 input++;
354 if (input == parsed)
355 return NULL;
356 break;
357 default:
358 return NULL;
359 }
360 }
361 return input;
362}
363
364static int dateMonthDayFromJulianDay(int julianDay, int year, int *month, int *day) {
365 static const int daysPerMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
366 int i, days;
367
368 for (i = 0; i < 12; i++) {
369 days = daysPerMonth[i];
370 if (i == 1 && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0))
371 days++;
372 if (julianDay <= days) {
373 *month = i + 1;
374 *day = julianDay;
375 return 1;
376 }
377 julianDay -= days;
378 }
379 return 0;
380}
381
382static const char *parseDateTime(const char *input, const char *format, struct tm *value) {
383 DATE_PARSE_STATE state;
384 const char *result;
385 int month, day;
386 int year;
387
388 memset(&state, 0, sizeof(state));
389 state.value = value;
390 state.century = -1;
391 state.shortYear = -1;
392 state.meridiem = -1;
393
394 if (!(result = parseWindowsDateFormat(input, format, &state)))
395 return NULL;
396
397 if (state.shortYear >= 0) {
398 if (state.century >= 0)
399 year = state.century * 100 + state.shortYear;
400 else
401 year = state.shortYear <= 68 ? 2000 + state.shortYear : 1900 + state.shortYear;
402 value->tm_year = year - 1900;
403 } else if (state.century >= 0) {
404 value->tm_year = state.century * 100 - 1900;
405 }
406
407 if (state.twelveHour && state.meridiem >= 0) {
408 value->tm_hour %= 12;
409 if (state.meridiem)
410 value->tm_hour += 12;
411 }
412
413 if (state.julianDay) {
414 year = value->tm_year + 1900;
415 if (!dateMonthDayFromJulianDay(state.julianDay, year, &month, &day))
416 return NULL;
417 value->tm_mon = month - 1;
418 value->tm_mday = day;
419 }
420 return result;
421}
422#else
423static const char *parseDateTime(const char *input, const char *format, struct tm *value) {
424 return strptime(input, format, value);
425}
426#endif
427
428int main(int argc, char **argv) {
429 SDDS_DATASET SDDSin, SDDSout;
430 long i_arg, iconv;
431 SCANNED_ARG *s_arg;
432 char *input, *output;
433 TIME_CONVERSION *conversion;
434 long conversions;
435 unsigned long pipeFlags, majorOrderFlag;
436 short columnMajorOrder = -1;
437
439 argc = scanargs(&s_arg, argc, argv);
440 if (argc < 3) {
441 fprintf(stderr, "%s", USAGE);
442 exit(EXIT_FAILURE);
443 }
444
445 input = output = NULL;
446 conversions = 0;
447 conversion = NULL;
448 pipeFlags = 0;
449
450 for (i_arg = 1; i_arg < argc; i_arg++) {
451 if (s_arg[i_arg].arg_type == OPTION) {
452 switch (match_string(s_arg[i_arg].list[0], option, N_OPTIONS, 0)) {
453 case SET_MAJOR_ORDER:
454 majorOrderFlag = 0;
455 s_arg[i_arg].n_items--;
456 if (s_arg[i_arg].n_items > 0 &&
457 (!scanItemList(&majorOrderFlag, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
458 "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
459 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)))
460 SDDS_Bomb("invalid -majorOrder syntax/values");
461 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
462 columnMajorOrder = 1;
463 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
464 columnMajorOrder = 0;
465 break;
466 case SET_EPOCH:
467 if (s_arg[i_arg].n_items < 4)
468 SDDS_Bomb("Invalid -epoch syntax");
469 if (!(conversion = SDDS_Realloc(conversion, sizeof(*conversion) * (conversions + 1))))
470 SDDS_Bomb("Memory allocation failure");
471 memset((char *)(conversion + conversions), 0, sizeof(*conversion));
472 conversion[conversions].epochName = s_arg[i_arg].list[2];
473 s_arg[i_arg].list[2] = s_arg[i_arg].list[1];
474 s_arg[i_arg].n_items -= 2;
475 if (!scanItemList(&conversion[conversions].flags,
476 s_arg[i_arg].list + 2, &s_arg[i_arg].n_items, 0,
477 "column", -1, NULL, 0, IS_COLUMN,
478 "parameter", -1, NULL, 0, IS_PARAMETER,
479 "year", SDDS_STRING, &conversion[conversions].yearName, 1, YEAR_GIVEN,
480 "julianday", SDDS_STRING, &conversion[conversions].jDayName, 1, JDAY_GIVEN,
481 "month", SDDS_STRING, &conversion[conversions].monthName, 1, MONTH_GIVEN,
482 "day", SDDS_STRING, &conversion[conversions].dayName, 1, DAY_GIVEN,
483 "hour", SDDS_STRING, &conversion[conversions].hourName, 1, HOUR_GIVEN, NULL))
484 SDDS_Bomb("invalid -epoch syntax");
485 conversion[conversions].flags |= EPOCH_GIVEN | DO_EPOCH;
486 if (!(conversion[conversions].flags & (IS_COLUMN | IS_PARAMETER)))
487 SDDS_Bomb("Specify 'column' or 'parameter' qualifier with -epoch");
488 if (conversion[conversions].flags & IS_COLUMN && conversion[conversions].flags & IS_PARAMETER)
489 SDDS_Bomb("Specify only one of 'column' or 'parameter' qualifier with -epoch");
490 if (!(conversion[conversions].flags & YEAR_GIVEN))
491 SDDS_Bomb("Specify year name with -epoch");
492 if (!(conversion[conversions].flags & JDAY_GIVEN) &&
493 (conversion[conversions].flags & (MONTH_GIVEN | DAY_GIVEN)) != (MONTH_GIVEN | DAY_GIVEN))
494 SDDS_Bomb("Specify either julianDay name, or both month and day names with -epoch");
495 if (conversion[conversions].flags & JDAY_GIVEN && conversion[conversions].flags & (MONTH_GIVEN | DAY_GIVEN))
496 SDDS_Bomb("Invalid combination of julianDay name with month or day name for -epoch");
497 conversions++;
498 break;
499 case SET_BREAKDOWN:
500 if (s_arg[i_arg].n_items < 4)
501 SDDS_Bomb("Invalid -breakdown syntax");
502 if (!(conversion = SDDS_Realloc(conversion, sizeof(*conversion) * (conversions + 1))))
503 SDDS_Bomb("Memory allocation failure");
504 memset((char *)(conversion + conversions), 0, sizeof(*conversion));
505 conversion[conversions].epochName = s_arg[i_arg].list[2];
506 s_arg[i_arg].list[2] = s_arg[i_arg].list[1];
507 s_arg[i_arg].n_items -= 2;
508 if (!scanItemList(&conversion[conversions].flags,
509 s_arg[i_arg].list + 2, &s_arg[i_arg].n_items, 0,
510 "column", -1, NULL, 0, IS_COLUMN,
511 "parameter", -1, NULL, 0, IS_PARAMETER,
512 "year", SDDS_STRING, &conversion[conversions].yearName, 1, YEAR_GIVEN,
513 "julianday", SDDS_STRING, &conversion[conversions].jDayName, 1, JDAY_GIVEN,
514 "month", SDDS_STRING, &conversion[conversions].monthName, 1, MONTH_GIVEN,
515 "day", SDDS_STRING, &conversion[conversions].dayName, 1, DAY_GIVEN,
516 "hour", SDDS_STRING, &conversion[conversions].hourName, 1, HOUR_GIVEN,
517 "text", SDDS_STRING, &conversion[conversions].textName, 1, TEXT_GIVEN, NULL))
518 SDDS_Bomb("invalid -breakdown syntax");
519 conversion[conversions].flags |= EPOCH_GIVEN | DO_BREAKDOWN;
520 if (!(conversion[conversions].flags & (IS_COLUMN | IS_PARAMETER)))
521 SDDS_Bomb("Specify 'column' or 'parameter' qualifier with -breakdown");
522 if (conversion[conversions].flags & IS_COLUMN && conversion[conversions].flags & IS_PARAMETER)
523 SDDS_Bomb("Specify only one of 'column' or 'parameter' qualifier with -breakdown");
524 if (!(conversion[conversions].flags & (YEAR_GIVEN | JDAY_GIVEN | MONTH_GIVEN | DAY_GIVEN | HOUR_GIVEN | TEXT_GIVEN)))
525 SDDS_Bomb("Specify at least one of year, julianDay, month, day, hour, or text qualifiers with -breakdown");
526 conversions++;
527 break;
528 case SET_DATE:
529 if (s_arg[i_arg].n_items < 4)
530 SDDS_Bomb("Invalid -dateToTime syntax");
531 if (!(conversion = SDDS_Realloc(conversion, sizeof(*conversion) * (conversions + 1))))
532 SDDS_Bomb("Memory allocation failure");
533 memset((char *)(conversion + conversions), 0, sizeof(*conversion));
534 conversion[conversions].textName = s_arg[i_arg].list[3];
535 conversion[conversions].epochName = s_arg[i_arg].list[2];
536 s_arg[i_arg].list[3] = s_arg[i_arg].list[1];
537 s_arg[i_arg].n_items -= 3;
538 if (!scanItemList(&conversion[conversions].flags,
539 s_arg[i_arg].list + 3, &s_arg[i_arg].n_items, 0,
540 "column", -1, NULL, 0, IS_COLUMN,
541 "parameter", -1, NULL, 0, IS_PARAMETER,
542 "format", SDDS_STRING, &conversion[conversions].format, 1, FORMAT_GIVEN, NULL))
543 SDDS_Bomb("invalid -dateToTime syntax");
544 conversion[conversions].flags |= DO_DATECONVERSION;
545 if (!(conversion[conversions].flags & (IS_COLUMN | IS_PARAMETER)))
546 SDDS_Bomb("Specify 'column' or 'parameter' qualifier with -dateToTime");
547 if (conversion[conversions].flags & IS_COLUMN && conversion[conversions].flags & IS_PARAMETER)
548 SDDS_Bomb("Specify only one of 'column' or 'parameter' qualifier with -dateToTime");
549 if (!(conversion[conversions].flags & FORMAT_GIVEN))
550 SDDS_Bomb("Format string not provided for date to time conversion");
551 conversions++;
552 break;
553 case SET_PIPE:
554 if (!processPipeOption(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, &pipeFlags))
555 SDDS_Bomb("Invalid -pipe syntax");
556 break;
557 default:
558 fprintf(stderr, "Error: Unknown option: %s\n", s_arg[i_arg].list[0]);
559 SDDS_Bomb(NULL);
560 break;
561 }
562 } else {
563 if (!input)
564 input = s_arg[i_arg].list[0];
565 else if (!output)
566 output = s_arg[i_arg].list[0];
567 else {
568 fprintf(stderr, "Error: Argument '%s' is invalid: too many filenames (sddstimeconvert)\n", s_arg[i_arg].list[0]);
569 exit(EXIT_FAILURE);
570 }
571 }
572 }
573
574 processFilenames("sddstimeconvert", &input, &output, pipeFlags, 0, NULL);
575
576 if (!SDDS_InitializeInput(&SDDSin, input)) {
577 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
578 exit(EXIT_FAILURE);
579 }
580
581 CheckEpochConversionElements(&SDDSin, conversion, conversions);
582 CheckBreakdownConversionElements(&SDDSin, conversion, conversions);
583 CheckDateConversionElements(&SDDSin, conversion, conversions);
584
585 InitializeOutput(&SDDSout, output, conversion, conversions, &SDDSin, columnMajorOrder);
586
587 while (SDDS_ReadPage(&SDDSin) > 0) {
588 if (!SDDS_CopyPage(&SDDSout, &SDDSin)) {
589 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
590 exit(EXIT_FAILURE);
591 }
592 for (iconv = 0; iconv < conversions; iconv++) {
593 if (conversion[iconv].flags & DO_EPOCH) {
594 if (conversion[iconv].flags & IS_PARAMETER)
595 DoParameterEpochConversion(&SDDSout, &SDDSin, conversion + iconv);
596 else
597 DoColumnEpochConversion(&SDDSout, &SDDSin, conversion + iconv);
598 } else if (conversion[iconv].flags & DO_BREAKDOWN) {
599 if (conversion[iconv].flags & IS_PARAMETER)
600 DoParameterBreakdownConversion(&SDDSout, &SDDSin, conversion + iconv);
601 else
602 DoColumnBreakdownConversion(&SDDSout, &SDDSin, conversion + iconv);
603 } else {
604 /* Convert date string to double time */
605 if (conversion[iconv].flags & IS_PARAMETER)
606 DoParameterDateToTimeConversion(&SDDSout, &SDDSin, conversion + iconv);
607 else
608 DoColumnDateToTimeConversion(&SDDSout, &SDDSin, conversion + iconv);
609 }
610 }
611 if (!SDDS_WritePage(&SDDSout)) {
612 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
613 exit(EXIT_FAILURE);
614 }
615 }
616 if (!SDDS_Terminate(&SDDSin) || !SDDS_Terminate(&SDDSout)) {
617 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
618 exit(EXIT_FAILURE);
619 }
620
621 return EXIT_SUCCESS;
622}
623
624void CheckEpochConversionElements(SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion, long conversions) {
625 while (conversions-- > 0) {
626 if (!(conversion[conversions].flags & DO_EPOCH))
627 continue;
628 if (conversion->flags & IS_PARAMETER) {
629 if (SDDS_CheckParameter(SDDSin, conversion->yearName, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OK ||
630 (conversion->jDayName &&
631 SDDS_CheckParameter(SDDSin, conversion->jDayName, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OK) ||
632 (conversion->dayName &&
633 SDDS_CheckParameter(SDDSin, conversion->dayName, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OK) ||
634 (conversion->monthName &&
635 SDDS_CheckParameter(SDDSin, conversion->monthName, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OK) ||
636 SDDS_CheckParameter(SDDSin, conversion->hourName, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OK)
637 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
638 conversion->yearIndex = SDDS_GetParameterIndex(SDDSin, conversion->yearName);
639 conversion->hourIndex = SDDS_GetParameterIndex(SDDSin, conversion->hourName);
640 conversion->dayIndex = conversion->jDayIndex = conversion->monthIndex = -1;
641 if (conversion->dayName)
642 conversion->dayIndex = SDDS_GetParameterIndex(SDDSin, conversion->dayName);
643 if (conversion->jDayName)
644 conversion->jDayIndex = SDDS_GetParameterIndex(SDDSin, conversion->jDayName);
645 if (conversion->monthName)
646 conversion->monthIndex = SDDS_GetParameterIndex(SDDSin, conversion->monthName);
647 } else {
648 if (SDDS_CheckColumn(SDDSin, conversion->yearName, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OK ||
649 (conversion->jDayName &&
650 SDDS_CheckColumn(SDDSin, conversion->jDayName, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OK) ||
651 (conversion->dayName &&
652 SDDS_CheckColumn(SDDSin, conversion->dayName, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OK) ||
653 (conversion->monthName &&
654 SDDS_CheckColumn(SDDSin, conversion->monthName, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OK) ||
655 SDDS_CheckColumn(SDDSin, conversion->hourName, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OK)
656 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
657 conversion->yearIndex = SDDS_GetColumnIndex(SDDSin, conversion->yearName);
658 conversion->hourIndex = SDDS_GetColumnIndex(SDDSin, conversion->hourName);
659 conversion->dayIndex = conversion->jDayIndex = conversion->monthIndex = -1;
660 if (conversion->dayName)
661 conversion->dayIndex = SDDS_GetColumnIndex(SDDSin, conversion->dayName);
662 if (conversion->jDayName)
663 conversion->jDayIndex = SDDS_GetColumnIndex(SDDSin, conversion->jDayName);
664 if (conversion->monthName)
665 conversion->monthIndex = SDDS_GetColumnIndex(SDDSin, conversion->monthName);
666 }
667 conversion++;
668 }
669}
670
671void CheckBreakdownConversionElements(SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion, long conversions) {
672 while (conversions-- > 0) {
673 if (!(conversion[conversions].flags & DO_BREAKDOWN))
674 continue;
675 if (conversion->flags & IS_PARAMETER) {
676 if (SDDS_CheckParameter(SDDSin, conversion->epochName, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OK)
677 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
678 conversion->epochIndex = SDDS_GetParameterIndex(SDDSin, conversion->epochName);
679 } else {
680 if (SDDS_CheckColumn(SDDSin, conversion->epochName, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OK)
681 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
682 conversion->epochIndex = SDDS_GetColumnIndex(SDDSin, conversion->epochName);
683 }
684 conversion++;
685 }
686}
687
688void CheckDateConversionElements(SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion, long conversions) {
689 while (conversions-- > 0) {
690 if (!(conversion[conversions].flags & DO_DATECONVERSION))
691 continue;
692 if (conversion->flags & IS_PARAMETER) {
693 if (SDDS_CheckParameter(SDDSin, conversion->textName, NULL, SDDS_STRING, stderr) != SDDS_CHECK_OK)
694 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
695 conversion->textIndex = SDDS_GetParameterIndex(SDDSin, conversion->textName);
696 } else {
697 if (SDDS_CheckColumn(SDDSin, conversion->textName, NULL, SDDS_STRING, stderr) != SDDS_CHECK_OK)
698 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
699 conversion->textIndex = SDDS_GetColumnIndex(SDDSin, conversion->textName);
700 }
701 if (conversion->textIndex < 0) {
702 fprintf(stderr, "Error: '%s' does not exist in input file.\n", conversion->textName);
703 exit(EXIT_FAILURE);
704 }
705 conversion++;
706 }
707}
708
709void InitializeOutput(SDDS_DATASET *SDDSout, char *outputfile, TIME_CONVERSION *conversion, long conversions,
710 SDDS_DATASET *SDDSin, short columnMajorOrder) {
711 if (!SDDS_InitializeCopy(SDDSout, SDDSin, outputfile, "w"))
712 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
713 if (columnMajorOrder != -1)
714 SDDSout->layout.data_mode.column_major = columnMajorOrder;
715 else
716 SDDSout->layout.data_mode.column_major = SDDSin->layout.data_mode.column_major;
717 while (conversions-- > 0) {
718 if (conversion->flags & DO_EPOCH) {
719 if (conversion->flags & IS_PARAMETER) {
720 if ((conversion->epochIndex = SDDS_DefineParameter(SDDSout, conversion->epochName,
721 NULL, "s", "Time since start of epoch", NULL, SDDS_DOUBLE, NULL)) < 0)
722 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
723 } else {
724 if ((conversion->epochIndex = SDDS_DefineColumn(SDDSout, conversion->epochName,
725 NULL, "s", "Time since start of epoch", NULL, SDDS_DOUBLE, 0)) < 0)
726 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
727 }
728 } else if (conversion->flags & DO_BREAKDOWN) {
729 if (conversion->flags & IS_PARAMETER) {
730 if ((conversion->yearName &&
731 (conversion->yearIndex = SDDS_DefineParameter(SDDSout, conversion->yearName, NULL, NULL, "Year", NULL,
732 SDDS_SHORT, NULL)) < 0) ||
733 (conversion->dayName &&
734 (conversion->dayIndex = SDDS_DefineParameter(SDDSout, conversion->dayName, NULL, NULL, "Day of month",
735 NULL, SDDS_SHORT, NULL)) < 0) ||
736 (conversion->monthName &&
737 (conversion->monthIndex = SDDS_DefineParameter(SDDSout, conversion->monthName, NULL, NULL, "Month", NULL,
738 SDDS_SHORT, NULL)) < 0) ||
739 (conversion->jDayName &&
740 (conversion->jDayIndex = SDDS_DefineParameter(SDDSout, conversion->jDayName, NULL, NULL, "Julian day",
741 NULL, SDDS_SHORT, NULL)) < 0) ||
742 (conversion->hourName &&
743 (conversion->hourIndex = SDDS_DefineParameter(SDDSout, conversion->hourName, NULL, NULL, "Hour of day",
744 NULL, SDDS_DOUBLE, NULL)) < 0) ||
745 (conversion->textName &&
746 (conversion->textIndex = SDDS_DefineParameter(SDDSout, conversion->textName, NULL, NULL, "Timestamp",
747 NULL, SDDS_STRING, NULL)) < 0))
748 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
749 } else {
750 if ((conversion->yearName &&
751 (conversion->yearIndex = SDDS_DefineColumn(SDDSout, conversion->yearName, NULL, NULL, "Year", NULL,
752 SDDS_SHORT, 0)) < 0) ||
753 (conversion->dayName &&
754 (conversion->dayIndex = SDDS_DefineColumn(SDDSout, conversion->dayName, NULL, NULL, "Day of month",
755 NULL, SDDS_SHORT, 0)) < 0) ||
756 (conversion->monthName &&
757 (conversion->monthIndex = SDDS_DefineColumn(SDDSout, conversion->monthName, NULL, NULL, "Month", NULL,
758 SDDS_SHORT, 0)) < 0) ||
759 (conversion->jDayName &&
760 (conversion->jDayIndex = SDDS_DefineColumn(SDDSout, conversion->jDayName, NULL, NULL, "Julian day",
761 NULL, SDDS_SHORT, 0)) < 0) ||
762 (conversion->hourName &&
763 (conversion->hourIndex = SDDS_DefineColumn(SDDSout, conversion->hourName, NULL, NULL, "Hour of day",
764 NULL, SDDS_DOUBLE, 0)) < 0) ||
765 (conversion->textName &&
766 (conversion->textIndex = SDDS_DefineColumn(SDDSout, conversion->textName, NULL, NULL, "Timestamp",
767 NULL, SDDS_STRING, 0)) < 0))
768 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
769 }
770 } else {
771 /* Date to time conversion */
772 if (conversion->flags & IS_PARAMETER) {
773 if ((conversion->epochIndex = SDDS_DefineParameter(SDDSout, conversion->epochName,
774 NULL, "s", "Time since start of epoch", NULL, SDDS_DOUBLE, NULL)) < 0)
775 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
776 } else {
777 if ((conversion->epochIndex = SDDS_DefineColumn(SDDSout, conversion->epochName,
778 NULL, "s", "Time since start of epoch", NULL, SDDS_DOUBLE, 0)) < 0)
779 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
780 }
781 }
782 conversion++;
783 }
784 if (!SDDS_WriteLayout(SDDSout))
785 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
786}
787
788void DoParameterEpochConversion(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion) {
789 double hour;
790 double month = 0, day = 0, jDay = 0, year, epochTime;
791
792 jDay = 0;
793 if (!SDDS_GetParameterAsDouble(SDDSin, conversion->hourName, &hour) ||
794 !SDDS_GetParameterAsDouble(SDDSin, conversion->yearName, &year) ||
795 (conversion->jDayName && !SDDS_GetParameterAsDouble(SDDSin, conversion->jDayName, &jDay)) ||
796 (conversion->monthName && !SDDS_GetParameterAsDouble(SDDSin, conversion->monthName, &month)) ||
797 (conversion->dayName && !SDDS_GetParameterAsDouble(SDDSin, conversion->dayName, &day))) {
798 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
799 exit(EXIT_FAILURE);
800 }
801 TimeBreakdownToEpoch((short)year, (short)jDay, (short)month, (short)day, hour, &epochTime);
802 if (!SDDS_SetParametersFromDoubles(SDDSout, SDDS_BY_NAME | SDDS_PASS_BY_VALUE, conversion->epochName, epochTime, NULL))
803 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
804}
805
806void DoParameterBreakdownConversion(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion) {
807 double hour, epochTime;
808 short year, jDay, month, day;
809 char text[30];
810
811 if (!SDDS_GetParameterAsDouble(SDDSin, conversion->epochName, &epochTime))
812 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
813 TimeEpochToBreakdown(&year, &jDay, &month, &day, &hour, epochTime);
814 TimeEpochToText(text, epochTime);
815 if ((conversion->yearName &&
816 !SDDS_SetParametersFromDoubles(SDDSout, SDDS_BY_INDEX | SDDS_PASS_BY_VALUE,
817 conversion->yearIndex, (double)year, -1)) ||
818 (conversion->dayName &&
819 !SDDS_SetParametersFromDoubles(SDDSout, SDDS_BY_INDEX | SDDS_PASS_BY_VALUE,
820 conversion->dayIndex, (double)day, -1)) ||
821 (conversion->jDayName &&
822 !SDDS_SetParametersFromDoubles(SDDSout, SDDS_BY_INDEX | SDDS_PASS_BY_VALUE,
823 conversion->jDayIndex, (double)jDay, -1)) ||
824 (conversion->monthName &&
825 !SDDS_SetParametersFromDoubles(SDDSout, SDDS_BY_INDEX | SDDS_PASS_BY_VALUE,
826 conversion->monthIndex, (double)month, -1)) ||
827 (conversion->hourName &&
828 !SDDS_SetParametersFromDoubles(SDDSout, SDDS_BY_INDEX | SDDS_PASS_BY_VALUE,
829 conversion->hourIndex, (double)hour, -1)) ||
830 (conversion->textName &&
831 !SDDS_SetParameters(SDDSout, SDDS_BY_INDEX | SDDS_PASS_BY_VALUE, conversion->textIndex, text, -1)))
832 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
833}
834
835void DoParameterDateToTimeConversion(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion) {
836 double hour;
837 double month = 0, day = 0, jDay = 0, year, epochTime;
838 char *timestr = NULL;
839 struct tm tm = {0};
840 /* Note that tm struct:
841 tm_year: years since 1900
842 tm_mon: months since January (0-11)
843 */
844
845 if (!SDDS_GetParameter(SDDSin, conversion->textName, &timestr)) {
846 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
847 exit(EXIT_FAILURE);
848 }
849 if (parseDateTime(timestr, conversion->format, &tm) == NULL) {
850 fprintf(stderr, "Error: Failed to parse date string '%s' with format '%s'\n", timestr, conversion->format);
851 exit(EXIT_FAILURE);
852 }
853 year = tm.tm_year + 1900;
854 month = tm.tm_mon + 1;
855 day = tm.tm_mday;
856 hour = tm.tm_hour + tm.tm_min / 60.0 + tm.tm_sec / 3600.0;
857
858 TimeBreakdownToEpoch((short)year, (short)jDay, (short)month, (short)day, hour, &epochTime);
859 if (!SDDS_SetParametersFromDoubles(SDDSout, SDDS_BY_NAME | SDDS_PASS_BY_VALUE, conversion->epochName, epochTime, NULL))
860 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
861}
862
863void DoColumnEpochConversion(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion) {
864 double *hour;
865 double *month, *day, *jDay, *year, *epochTime;
866 int64_t row, rows;
867
868 year = NULL;
869
870 if (!(rows = SDDS_CountRowsOfInterest(SDDSin)))
871 return;
872
873 jDay = month = day = NULL;
874 if (!(hour = SDDS_GetColumnInDoubles(SDDSin, conversion->hourName)) ||
875 !(year = SDDS_GetColumnInDoubles(SDDSin, conversion->yearName)) ||
876 (conversion->jDayName && !(jDay = SDDS_GetColumnInDoubles(SDDSin, conversion->jDayName))) ||
877 (conversion->monthName && !(month = SDDS_GetColumnInDoubles(SDDSin, conversion->monthName))) ||
878 (conversion->dayName && !(day = SDDS_GetColumnInDoubles(SDDSin, conversion->dayName))))
879 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
880
881 if (!(epochTime = (double *)malloc(sizeof(*epochTime) * rows)))
882 SDDS_Bomb("Memory allocation failure");
883
884 for (row = 0; row < rows; row++)
885 TimeBreakdownToEpoch((short)year[row], jDay ? (short)jDay[row] : 0, month ? (short)month[row] : 0, day ? (short)day[row] : 0, hour[row], epochTime + row);
886 if (!SDDS_SetColumnFromDoubles(SDDSout, SDDS_BY_NAME, epochTime, rows, conversion->epochName))
887 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
888 free(hour);
889 free(year);
890 free(epochTime);
891 if (jDay)
892 free(jDay);
893 if (month)
894 free(month);
895 if (day)
896 free(day);
897}
898
899void DoColumnDateToTimeConversion(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion) {
900 double hour;
901 double month = 0, day = 0, year = 0, jDay = 0, *epochTime;
902 int64_t row, rows;
903 char **timestr = NULL;
904 struct tm tm = {0};
905 /* Note that tm struct:
906 tm_year: years since 1900
907 tm_mon: months since January (0-11)
908 */
909 if (!(rows = SDDS_CountRowsOfInterest(SDDSin)))
910 return;
911
912 if (!(timestr = SDDS_GetColumn(SDDSin, conversion->textName)))
913 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
914
915 if (!(epochTime = (double *)malloc(sizeof(*epochTime) * rows)))
916 SDDS_Bomb("Memory allocation failure");
917
918 for (row = 0; row < rows; row++) {
919 if (parseDateTime(timestr[row], conversion->format, &tm) == NULL) {
920 fprintf(stderr, "Error: Failed to parse date string '%s' with format '%s'\n", timestr[row], conversion->format);
921 exit(EXIT_FAILURE);
922 }
923 year = tm.tm_year + 1900;
924 month = tm.tm_mon + 1;
925 day = tm.tm_mday;
926 hour = tm.tm_hour + tm.tm_min / 60.0 + tm.tm_sec / 3600.0;
927 TimeBreakdownToEpoch((short)year, (short)jDay, (short)month, (short)day, hour, epochTime + row);
928 }
929 if (!SDDS_SetColumnFromDoubles(SDDSout, SDDS_BY_NAME, epochTime, rows, conversion->epochName))
930 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
931 SDDS_FreeStringArray(timestr, rows);
932 free(epochTime);
933}
934
935void DoColumnBreakdownConversion(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion) {
936 double *hour, *epochTime;
937 short *month, *day, *jDay, *year;
938 char **text;
939 int64_t row, rows;
940
941 if (!(rows = SDDS_CountRowsOfInterest(SDDSin)))
942 return;
943
944 if (!(epochTime = SDDS_GetColumnInDoubles(SDDSin, conversion->epochName)))
945 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
946
947 hour = NULL;
948 month = day = jDay = year = NULL;
949 text = NULL;
950 if ((conversion->hourName && !(hour = (double *)malloc(sizeof(*hour) * rows))) ||
951 (conversion->monthName && !(month = (short *)malloc(sizeof(*month) * rows))) ||
952 (conversion->dayName && !(day = (short *)malloc(sizeof(*day) * rows))) ||
953 (conversion->jDayName && !(jDay = (short *)malloc(sizeof(*jDay) * rows))) ||
954 (conversion->textName && !(text = (char **)malloc(sizeof(*text) * rows))) ||
955 (conversion->yearName && !(year = (short *)malloc(sizeof(*year) * rows))))
956 SDDS_Bomb("Memory allocation failure");
957
958 for (row = 0; row < rows; row++) {
959 if (text)
960 text[row] = malloc(sizeof(**text) * 30);
961 if (!TimeEpochToBreakdown(year ? year + row : NULL, jDay ? jDay + row : NULL, month ? month + row : NULL, day ? day + row : NULL, hour ? hour + row : NULL, epochTime[row]) ||
962 (text && !TimeEpochToText(text[row], epochTime[row])))
963 SDDS_Bomb("Problem performing time breakdown");
964 }
965
966 if ((year && !SDDS_SetColumn(SDDSout, SDDS_BY_NAME, year, rows, conversion->yearName)) ||
967 (day && !SDDS_SetColumn(SDDSout, SDDS_BY_NAME, day, rows, conversion->dayName)) ||
968 (month && !SDDS_SetColumn(SDDSout, SDDS_BY_NAME, month, rows, conversion->monthName)) ||
969 (jDay && !SDDS_SetColumn(SDDSout, SDDS_BY_NAME, jDay, rows, conversion->jDayName)) ||
970 (hour && !SDDS_SetColumn(SDDSout, SDDS_BY_NAME, hour, rows, conversion->hourName)) ||
971 (text && !SDDS_SetColumn(SDDSout, SDDS_BY_NAME, text, rows, conversion->textName)))
972 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
973 if (hour)
974 free(hour);
975 if (year)
976 free(year);
977 if (epochTime)
978 free(epochTime);
979 if (jDay)
980 free(jDay);
981 if (month)
982 free(month);
983 if (day)
984 free(day);
985 if (text) {
986 for (row = 0; row < rows; row++)
987 free(text[row]);
988 free(text);
989 }
990}
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
int32_t SDDS_SetParametersFromDoubles(SDDS_DATASET *SDDS_dataset, int32_t mode,...)
int32_t SDDS_SetParameters(SDDS_DATASET *SDDS_dataset, int32_t mode,...)
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".
double * SDDS_GetParameterAsDouble(SDDS_DATASET *SDDS_dataset, char *parameter_name, double *memory)
Retrieves the value of a specified parameter as a double from the current data table of an SDDS datas...
int64_t SDDS_CountRowsOfInterest(SDDS_DATASET *SDDS_dataset)
Counts the number of rows marked as "of interest" in the current data table.
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.
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_InitializeInput(SDDS_DATASET *SDDS_dataset, char *filename)
Definition SDDS_input.c:50
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_DefineColumn(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, int32_t field_length)
Defines a data column within the SDDS dataset.
int32_t SDDS_WriteLayout(SDDS_DATASET *SDDS_dataset)
Writes the SDDS layout header to the output file.
int32_t SDDS_DefineParameter(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, char *fixed_value)
Defines a data parameter with a fixed string value.
int32_t SDDS_FreeStringArray(char **string, int64_t strings)
Frees an array of strings by deallocating each individual string.
int32_t SDDS_GetParameterIndex(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the index of a named parameter 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.
int32_t SDDS_CheckColumn(SDDS_DATASET *SDDS_dataset, char *name, char *units, int32_t type, FILE *fp_message)
Checks if a column exists in the SDDS dataset with the specified name, units, and type.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
Definition SDDS_utils.c:474
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
Definition SDDS_utils.c:318
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
Definition SDDS_utils.c:380
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.
void * SDDS_Realloc(void *old_ptr, size_t new_size)
Reallocates memory to a new size.
Definition SDDS_utils.c:743
#define SDDS_STRING
Identifier for the string data type.
Definition SDDStypes.h:85
#define SDDS_SHORT
Identifier for the signed short integer data type.
Definition SDDStypes.h:73
#define SDDS_ANY_NUMERIC_TYPE
Special identifier used by SDDS_Check*() routines to accept any numeric type.
Definition SDDStypes.h:157
#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:357
void processFilenames(char *programName, char **input, char **output, unsigned long pipeFlags, long noWarnings, long *tmpOutputUsed)
Definition scanargs.c:391
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.
short TimeEpochToBreakdown(short *year, short *jDay, short *month, short *day, double *hour, double epochTime)
Breaks down epoch time into its constituent components.
short TimeBreakdownToEpoch(short year, short jDay, short month, short day, double hour, double *epochTime)
Converts a broken-down time into epoch time.
short TimeEpochToText(char *text, double epochTime)
Converts epoch time to a formatted text string.