SDDS ToolKit Programs and Libraries for C and Python
Loading...
Searching...
No Matches
sddsconvertalarmlog.c
Go to the documentation of this file.
1/**
2 * @file sddsconvertalarmlog.c
3 * @brief Convert SDDS alarm log files to an explicit, array-free form.
4 *
5 * sddsalarmlog normally stores control names, alarm status strings, and
6 * alarm severity strings in SDDS arrays, with row data holding integer
7 * indices into those arrays. This program dereferences those indices and
8 * writes explicit string columns, which makes the output usable by tools
9 * that don't handle SDDS arrays.
10 */
11
12#include "mdb.h"
13#include "SDDS.h"
14#include "scan.h"
15
16enum option_type {
17 SET_BINARY,
18 SET_ASCII,
19 SET_FLOAT,
20 SET_DOUBLE,
21 SET_SNAPSHOT,
22 SET_PIPE,
23 SET_MININTERVAL,
24 SET_TIME,
25 SET_DELETE,
26 SET_RETAIN,
27 N_OPTIONS
28};
29
30enum output_column {
31 COL_TIME,
32 COL_PREVIOUS_ROW,
33 COL_TIME_OF_DAY_WS,
34 COL_TIME_OF_DAY,
35 COL_CONTROL_NAME,
36 COL_ALARM_STATUS,
37 COL_ALARM_SEVERITY,
38 COL_DESCRIPTION,
39 COL_RELATED_CONTROL_NAME,
40 COL_DURATION,
41 COL_RELATED_VALUE_STRING,
42 N_OUTPUT_COLUMNS
43};
44
45typedef struct {
46 int used;
47 double time;
48 int32_t previousRow;
49 float timeOfDayWS;
50 float timeOfDay;
51 char *controlName;
52 char *alarmStatus;
53 char *alarmSeverity;
54 char *description;
55 char *relatedControlName;
56 float duration;
57 char *relatedValueString;
59
60#if !defined(MAXDOUBLE)
61# define MAXDOUBLE 1.79769313486231570e+308
62#endif
63
64static char *option[N_OPTIONS] = {
65 "binary",
66 "ascii",
67 "float",
68 "double",
69 "snapshot",
70 "pipe",
71 "minimuminterval",
72 "time",
73 "delete",
74 "retain"};
75
76static const char *outputColumnName[N_OUTPUT_COLUMNS] = {
77 "Time",
78 "PreviousRow",
79 "TimeOfDayWS",
80 "TimeOfDay",
81 "ControlName",
82 "AlarmStatus",
83 "AlarmSeverity",
84 "Description",
85 "RelatedControlName",
86 "Duration",
87 "RelatedValueString"};
88
89static char *USAGE =
90 "Usage: sddsconvertalarmlog [<input-file>] [<output-file>]\n"
91 " [-pipe=[input][,output]]\n"
92 " [-binary | -ascii]\n"
93 " [-float | -double]\n"
94 " [-minimumInterval=<seconds>]\n"
95 " [-snapshot=<epochtime>]\n"
96 " [-time=[start=<epochtime>][,end=<epochtime>]]\n"
97 " [-delete=<column-names>]\n"
98 " [-retain=<column-names>]\n"
99 "\nOptions:\n"
100 " -pipe=[input][,output] Use pipe for input and/or output.\n"
101 " -binary Output in binary format.\n"
102 " -ascii Output in ASCII format.\n"
103 " -double Use double precision for the computed Time column.\n"
104 " -float Use float precision for the computed Time column.\n"
105 " -minimumInterval=<seconds> Set minimum interval between output rows.\n"
106 " -snapshot=<epochtime> Output the latest alarm state for each PV at the epoch time.\n"
107 " -time=[start=<epochtime>][,end=<epochtime>]\n"
108 " Filter data by epoch time range.\n"
109 " -delete={<matching-string>[,...]} Delete output columns matching the pattern.\n"
110 " -retain={<matching-string>[,...]} Retain only output columns matching the pattern.\n"
111 "\nProgram by Robert Soliday. (" __DATE__ " " __TIME__ ", SVN revision: " SVN_VERSION ")\n";
112
113static int NameMatchesList(const char *name, char **list, long items);
114static int NameSelected(const char *name, char **deleteName, long deleteNames, char **retainName, long retainNames);
115static int DefineOutputColumns(SDDS_DATASET *outSet, int32_t *outIndex, int *available, long outputType);
116static int EnsureRows(SDDS_DATASET *outSet, int64_t *allocatedRows, int64_t neededRows);
117static int WriteAlarmEvent(SDDS_DATASET *outSet, int32_t *outIndex, int64_t row, ALARM_EVENT *event);
118static double ComputeEpochTime(double timeOfDay, double startTime, double startHour);
119static char *ArrayString(SDDS_ARRAY *array, int32_t index);
120static char *StringColumnValue(char **column, int64_t row);
121static void ClearAlarmEvent(ALARM_EVENT *event);
122static int CopyStringOrBlank(char **target, const char *source);
123static int SaveSnapshotEvent(ALARM_EVENT **snapshotEvent, int64_t *snapshotEvents, ALARM_EVENT *event);
124
125int main(int argc, char **argv) {
126 SDDS_DATASET SDDS_input, SDDS_output;
127 SCANNED_ARG *s_arg;
128 char *input, *output;
129 char **retainName, **deleteName;
130 long retainNames, deleteNames;
131 long i, i_arg, noWarnings, tmpfile_used;
132 unsigned long pipeFlags, flags;
133 long ascii_output, binary_output, outputType;
134 long snapshot;
135 double snapshotTime, minimumInterval, previousOutputTime, startTime, endTime;
136 short filterTime;
137 int32_t outIndex[N_OUTPUT_COLUMNS];
138 int available[N_OUTPUT_COLUMNS];
139 int hasIndexedData, hasExplicitData, copiedParameters;
140 int hasControlNameString, hasAlarmStatusString, hasAlarmSeverityString;
141 int hasDescriptionString, hasRelatedControlNameString;
142 int hasControlName, hasAlarmStatus, hasAlarmSeverity;
143 int hasDescription, hasRelatedControlName, hasDuration, hasRelatedValueString;
144 int hasPreviousRow, hasTimeOfDayWS, hasTimeOfDay, hasTime;
145 int64_t allocatedRows, outputRows, snapshotEvents;
146 ALARM_EVENT *snapshotEvent;
147
149 argc = scanargs(&s_arg, argc, argv);
150 if (argc < 3) {
151 fprintf(stderr, "%s", USAGE);
152 exit(EXIT_FAILURE);
153 }
154
155 input = output = NULL;
156 retainName = deleteName = NULL;
157 retainNames = deleteNames = 0;
158 noWarnings = tmpfile_used = 0;
159 pipeFlags = 0;
160 ascii_output = binary_output = 0;
161 outputType = SDDS_DOUBLE;
162 snapshot = 0;
163 snapshotTime = 0;
164 minimumInterval = -1;
165 previousOutputTime = -MAXDOUBLE;
166 filterTime = 0;
167 startTime = -MAXDOUBLE;
168 endTime = MAXDOUBLE;
169
170 for (i_arg = 1; i_arg < argc; i_arg++) {
171 if (s_arg[i_arg].arg_type == OPTION) {
172 delete_chars(s_arg[i_arg].list[0], "_");
173 switch (match_string(s_arg[i_arg].list[0], option, N_OPTIONS, 0)) {
174 case SET_BINARY:
175 binary_output = 1;
176 ascii_output = 0;
177 break;
178 case SET_ASCII:
179 ascii_output = 1;
180 binary_output = 0;
181 break;
182 case SET_FLOAT:
183 outputType = SDDS_FLOAT;
184 break;
185 case SET_DOUBLE:
186 outputType = SDDS_DOUBLE;
187 break;
188 case SET_SNAPSHOT:
189 if (s_arg[i_arg].n_items < 2 ||
190 sscanf(s_arg[i_arg].list[1], "%lf", &snapshotTime) != 1) {
191 fprintf(stderr, "invalid -snapshot syntax or value\n");
192 exit(EXIT_FAILURE);
193 }
194 snapshot = 1;
195 break;
196 case SET_PIPE:
197 if (!processPipeOption(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, &pipeFlags)) {
198 fprintf(stderr, "invalid -pipe syntax\n");
199 exit(EXIT_FAILURE);
200 }
201 break;
202 case SET_MININTERVAL:
203 if (s_arg[i_arg].n_items < 2 ||
204 sscanf(s_arg[i_arg].list[1], "%lf", &minimumInterval) != 1) {
205 fprintf(stderr, "invalid -minimumInterval syntax or value\n");
206 exit(EXIT_FAILURE);
207 }
208 break;
209 case SET_TIME:
210 s_arg[i_arg].n_items -= 1;
211 filterTime = 1;
212 if (!scanItemList(&flags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
213 "start", SDDS_DOUBLE, &startTime, 1, 0,
214 "end", SDDS_DOUBLE, &endTime, 1, 0, NULL)) {
215 fprintf(stderr, "invalid -time syntax\n");
216 exit(EXIT_FAILURE);
217 }
218 s_arg[i_arg].n_items += 1;
219 break;
220 case SET_RETAIN:
221 retainName = trealloc(retainName, sizeof(*retainName) * (retainNames + s_arg[i_arg].n_items - 1));
222 for (i = 1; i < s_arg[i_arg].n_items; i++)
223 retainName[i - 1 + retainNames] = s_arg[i_arg].list[i];
224 retainNames += s_arg[i_arg].n_items - 1;
225 break;
226 case SET_DELETE:
227 deleteName = trealloc(deleteName, sizeof(*deleteName) * (deleteNames + s_arg[i_arg].n_items - 1));
228 for (i = 1; i < s_arg[i_arg].n_items; i++)
229 deleteName[i - 1 + deleteNames] = s_arg[i_arg].list[i];
230 deleteNames += s_arg[i_arg].n_items - 1;
231 break;
232 default:
233 fprintf(stderr, "Error (%s): unknown switch: %s\n", argv[0], s_arg[i_arg].list[0]);
234 exit(EXIT_FAILURE);
235 }
236 } else {
237 if (input == NULL)
238 input = s_arg[i_arg].list[0];
239 else if (output == NULL)
240 output = s_arg[i_arg].list[0];
241 else {
242 fprintf(stderr, "too many filenames\n");
243 exit(EXIT_FAILURE);
244 }
245 }
246 }
247
248 if (snapshot && minimumInterval >= 0) {
249 fprintf(stderr, "-snapshot and -minimumInterval options cannot be used together\n");
250 exit(EXIT_FAILURE);
251 }
252 if (snapshot && filterTime) {
253 fprintf(stderr, "-snapshot and -time options cannot be used together\n");
254 exit(EXIT_FAILURE);
255 }
256
257 processFilenames("sddsconvertalarmlog", &input, &output, pipeFlags, noWarnings, &tmpfile_used);
258
259 if (!SDDS_InitializeInput(&SDDS_input, input)) {
260 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
261 exit(EXIT_FAILURE);
262 }
263
264 hasControlNameString = SDDS_CheckArray(&SDDS_input, "ControlNameString", NULL, SDDS_STRING, NULL) == SDDS_CHECK_OK;
265 hasAlarmStatusString = SDDS_CheckArray(&SDDS_input, "AlarmStatusString", NULL, SDDS_STRING, NULL) == SDDS_CHECK_OK;
266 hasAlarmSeverityString = SDDS_CheckArray(&SDDS_input, "AlarmSeverityString", NULL, SDDS_STRING, NULL) == SDDS_CHECK_OK;
267 hasDescriptionString = SDDS_CheckArray(&SDDS_input, "DescriptionString", NULL, SDDS_STRING, NULL) == SDDS_CHECK_OK;
268 hasRelatedControlNameString = SDDS_CheckArray(&SDDS_input, "RelatedControlNameString", NULL, SDDS_STRING, NULL) == SDDS_CHECK_OK;
269 hasControlName = SDDS_CheckColumn(&SDDS_input, "ControlName", NULL, SDDS_STRING, NULL) == SDDS_CHECK_OK;
270 hasAlarmStatus = SDDS_CheckColumn(&SDDS_input, "AlarmStatus", NULL, SDDS_STRING, NULL) == SDDS_CHECK_OK;
271 hasAlarmSeverity = SDDS_CheckColumn(&SDDS_input, "AlarmSeverity", NULL, SDDS_STRING, NULL) == SDDS_CHECK_OK;
272 hasDescription = SDDS_CheckColumn(&SDDS_input, "Description", NULL, SDDS_STRING, NULL) == SDDS_CHECK_OK;
273 hasRelatedControlName = SDDS_CheckColumn(&SDDS_input, "RelatedControlName", NULL, SDDS_STRING, NULL) == SDDS_CHECK_OK;
274 hasDuration = SDDS_CheckColumn(&SDDS_input, "Duration", NULL, SDDS_ANY_NUMERIC_TYPE, NULL) == SDDS_CHECK_OK;
275 hasRelatedValueString = SDDS_CheckColumn(&SDDS_input, "RelatedValueString", NULL, SDDS_STRING, NULL) == SDDS_CHECK_OK;
276 hasPreviousRow = SDDS_CheckColumn(&SDDS_input, "PreviousRow", NULL, SDDS_ANY_NUMERIC_TYPE, NULL) == SDDS_CHECK_OK;
277 hasTimeOfDayWS = SDDS_CheckColumn(&SDDS_input, "TimeOfDayWS", NULL, SDDS_ANY_NUMERIC_TYPE, NULL) == SDDS_CHECK_OK;
278 hasTimeOfDay = SDDS_CheckColumn(&SDDS_input, "TimeOfDay", NULL, SDDS_ANY_NUMERIC_TYPE, NULL) == SDDS_CHECK_OK;
279 hasTime = SDDS_CheckColumn(&SDDS_input, "Time", NULL, SDDS_ANY_NUMERIC_TYPE, NULL) == SDDS_CHECK_OK;
280
281 hasIndexedData = hasControlNameString && hasAlarmStatusString && hasAlarmSeverityString &&
282 SDDS_CheckColumn(&SDDS_input, "ControlNameIndex", NULL, SDDS_ANY_INTEGER_TYPE, NULL) == SDDS_CHECK_OK &&
283 SDDS_CheckColumn(&SDDS_input, "AlarmStatusIndex", NULL, SDDS_ANY_INTEGER_TYPE, NULL) == SDDS_CHECK_OK &&
284 SDDS_CheckColumn(&SDDS_input, "AlarmSeverityIndex", NULL, SDDS_ANY_INTEGER_TYPE, NULL) == SDDS_CHECK_OK;
285 hasExplicitData = hasControlName && hasAlarmStatus && hasAlarmSeverity;
286 if (!hasIndexedData && !hasExplicitData) {
287 fprintf(stderr, "Error: input file has neither indexed alarm-log data nor explicit alarm-log columns.\n");
288 fprintf(stderr, " Expected ControlNameString/AlarmStatusString/AlarmSeverityString arrays with index columns,\n");
289 fprintf(stderr, " or ControlName/AlarmStatus/AlarmSeverity string columns.\n");
290 exit(EXIT_FAILURE);
291 }
292 if (!hasTime && !hasTimeOfDay) {
293 fprintf(stderr, "Error: TimeOfDay column is missing and no Time column is available.\n");
294 exit(EXIT_FAILURE);
295 }
296
297 for (i = 0; i < N_OUTPUT_COLUMNS; i++) {
298 available[i] = NameSelected(outputColumnName[i], deleteName, deleteNames, retainName, retainNames);
299 outIndex[i] = -1;
300 }
301 available[COL_PREVIOUS_ROW] = available[COL_PREVIOUS_ROW] && hasPreviousRow;
302 available[COL_TIME_OF_DAY_WS] = available[COL_TIME_OF_DAY_WS] && hasTimeOfDayWS;
303 available[COL_TIME_OF_DAY] = available[COL_TIME_OF_DAY] && hasTimeOfDay;
304 available[COL_DESCRIPTION] = available[COL_DESCRIPTION] && (hasDescription || (hasIndexedData && hasDescriptionString));
305 available[COL_RELATED_CONTROL_NAME] = available[COL_RELATED_CONTROL_NAME] && (hasRelatedControlName || (hasIndexedData && hasRelatedControlNameString));
306 available[COL_DURATION] = available[COL_DURATION] && hasDuration;
307 available[COL_RELATED_VALUE_STRING] = available[COL_RELATED_VALUE_STRING] && hasRelatedValueString;
308
309 if (!SDDS_InitializeOutput(&SDDS_output,
310 ascii_output ? SDDS_ASCII : (binary_output ? SDDS_BINARY : SDDS_input.layout.data_mode.mode),
311 1, NULL, NULL, output) ||
312 !SDDS_TransferAllParameterDefinitions(&SDDS_output, &SDDS_input, 0) ||
313 !DefineOutputColumns(&SDDS_output, outIndex, available, outputType) ||
314 !SDDS_WriteLayout(&SDDS_output)) {
315 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
316 exit(EXIT_FAILURE);
317 }
318
319 allocatedRows = 0;
320 outputRows = 0;
321 copiedParameters = 0;
322 snapshotEvent = NULL;
323 snapshotEvents = 0;
324
325 if (!SDDS_StartTable(&SDDS_output, 0)) {
326 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
327 exit(EXIT_FAILURE);
328 }
329
330 while (SDDS_ReadTable(&SDDS_input) > 0) {
331 int64_t row, rows;
332 double pageStartTime, pageStartHour;
333 double *timeData, *timeOfDayData, *timeOfDayWSData, *durationData, *previousRowData;
334 int32_t *controlNameIndexData, *alarmStatusIndexData, *alarmSeverityIndexData;
335 char **controlNameData, **alarmStatusData, **alarmSeverityData;
336 char **descriptionData, **relatedControlNameData, **relatedValueStringData;
337 SDDS_ARRAY *controlNameArray, *alarmStatusArray, *alarmSeverityArray;
338 SDDS_ARRAY *descriptionArray, *relatedControlNameArray;
339
340 rows = SDDS_RowCount(&SDDS_input);
341 if (!copiedParameters) {
342 if (!SDDS_CopyParameters(&SDDS_output, &SDDS_input)) {
343 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
344 exit(EXIT_FAILURE);
345 }
346 copiedParameters = 1;
347 }
348
349 pageStartTime = pageStartHour = 0;
350 if (!hasTime &&
351 (!SDDS_GetParameterAsDouble(&SDDS_input, "StartTime", &pageStartTime) ||
352 !SDDS_GetParameterAsDouble(&SDDS_input, "StartHour", &pageStartHour))) {
353 fprintf(stderr, "Error: StartTime and StartHour parameters are required when Time is absent.\n");
354 exit(EXIT_FAILURE);
355 }
356
357 timeData = hasTime ? SDDS_GetColumnInDoubles(&SDDS_input, "Time") : NULL;
358 timeOfDayData = hasTimeOfDay ? SDDS_GetColumnInDoubles(&SDDS_input, "TimeOfDay") : NULL;
359 timeOfDayWSData = hasTimeOfDayWS ? SDDS_GetColumnInDoubles(&SDDS_input, "TimeOfDayWS") : NULL;
360 durationData = hasDuration ? SDDS_GetColumnInDoubles(&SDDS_input, "Duration") : NULL;
361 previousRowData = hasPreviousRow ? SDDS_GetColumnInDoubles(&SDDS_input, "PreviousRow") : NULL;
362 controlNameIndexData = alarmStatusIndexData = alarmSeverityIndexData = NULL;
363 controlNameData = alarmStatusData = alarmSeverityData = NULL;
364 descriptionData = relatedControlNameData = relatedValueStringData = NULL;
365 controlNameArray = alarmStatusArray = alarmSeverityArray = NULL;
366 descriptionArray = relatedControlNameArray = NULL;
367
368 if ((hasTime && !timeData) || (hasTimeOfDay && !timeOfDayData) ||
369 (hasTimeOfDayWS && !timeOfDayWSData) || (hasDuration && !durationData) ||
370 (hasPreviousRow && !previousRowData)) {
371 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
372 exit(EXIT_FAILURE);
373 }
374
375 if (hasIndexedData) {
376 controlNameIndexData = SDDS_GetColumnInLong(&SDDS_input, "ControlNameIndex");
377 alarmStatusIndexData = SDDS_GetColumnInLong(&SDDS_input, "AlarmStatusIndex");
378 alarmSeverityIndexData = SDDS_GetColumnInLong(&SDDS_input, "AlarmSeverityIndex");
379 controlNameArray = SDDS_GetArray(&SDDS_input, "ControlNameString", NULL);
380 alarmStatusArray = SDDS_GetArray(&SDDS_input, "AlarmStatusString", NULL);
381 alarmSeverityArray = SDDS_GetArray(&SDDS_input, "AlarmSeverityString", NULL);
382 descriptionArray = hasDescriptionString ? SDDS_GetArray(&SDDS_input, "DescriptionString", NULL) : NULL;
383 relatedControlNameArray = hasRelatedControlNameString ? SDDS_GetArray(&SDDS_input, "RelatedControlNameString", NULL) : NULL;
384 if (!controlNameIndexData || !alarmStatusIndexData || !alarmSeverityIndexData ||
385 !controlNameArray || !alarmStatusArray || !alarmSeverityArray ||
386 (hasDescriptionString && !descriptionArray) ||
387 (hasRelatedControlNameString && !relatedControlNameArray)) {
388 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
389 exit(EXIT_FAILURE);
390 }
391 }
392 if (hasControlName)
393 controlNameData = SDDS_GetColumn(&SDDS_input, "ControlName");
394 if (hasAlarmStatus)
395 alarmStatusData = SDDS_GetColumn(&SDDS_input, "AlarmStatus");
396 if (hasAlarmSeverity)
397 alarmSeverityData = SDDS_GetColumn(&SDDS_input, "AlarmSeverity");
398 if (hasDescription)
399 descriptionData = SDDS_GetColumn(&SDDS_input, "Description");
400 if (hasRelatedControlName)
401 relatedControlNameData = SDDS_GetColumn(&SDDS_input, "RelatedControlName");
402 if (hasRelatedValueString)
403 relatedValueStringData = SDDS_GetColumn(&SDDS_input, "RelatedValueString");
404
405 if ((hasControlName && !controlNameData) || (hasAlarmStatus && !alarmStatusData) ||
406 (hasAlarmSeverity && !alarmSeverityData) || (hasDescription && !descriptionData) ||
407 (hasRelatedControlName && !relatedControlNameData) ||
408 (hasRelatedValueString && !relatedValueStringData)) {
409 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
410 exit(EXIT_FAILURE);
411 }
412
413 for (row = 0; row < rows; row++) {
414 ALARM_EVENT event;
415 int32_t controlIndex, statusIndex, severityIndex;
416
417 memset(&event, 0, sizeof(event));
418 event.previousRow = hasPreviousRow ? (int32_t)previousRowData[row] : -1;
419 event.timeOfDay = hasTimeOfDay ? (float)timeOfDayData[row] : 0;
420 event.timeOfDayWS = hasTimeOfDayWS ? (float)timeOfDayWSData[row] : 0;
421 event.duration = hasDuration ? (float)durationData[row] : 0;
422 event.time = hasTime ? timeData[row] : ComputeEpochTime(timeOfDayData[row], pageStartTime, pageStartHour);
423
424 if (filterTime && (event.time < startTime || event.time > endTime))
425 continue;
426
427 if (hasIndexedData) {
428 controlIndex = controlNameIndexData[row];
429 statusIndex = alarmStatusIndexData[row];
430 severityIndex = alarmSeverityIndexData[row];
431 event.controlName = ArrayString(controlNameArray, controlIndex);
432 event.alarmStatus = ArrayString(alarmStatusArray, statusIndex);
433 event.alarmSeverity = ArrayString(alarmSeverityArray, severityIndex);
434 event.description = hasDescription ? StringColumnValue(descriptionData, row) : ArrayString(descriptionArray, controlIndex);
435 event.relatedControlName = hasRelatedControlName ? StringColumnValue(relatedControlNameData, row) : ArrayString(relatedControlNameArray, controlIndex);
436 } else {
437 event.controlName = StringColumnValue(controlNameData, row);
438 event.alarmStatus = StringColumnValue(alarmStatusData, row);
439 event.alarmSeverity = StringColumnValue(alarmSeverityData, row);
440 event.description = StringColumnValue(descriptionData, row);
441 event.relatedControlName = StringColumnValue(relatedControlNameData, row);
442 }
443 event.relatedValueString = StringColumnValue(relatedValueStringData, row);
444
445 if (!event.controlName || !event.alarmStatus || !event.alarmSeverity)
446 continue;
447
448 if (snapshot) {
449 if (event.time <= snapshotTime && !SaveSnapshotEvent(&snapshotEvent, &snapshotEvents, &event)) {
450 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
451 exit(EXIT_FAILURE);
452 }
453 } else {
454 if (minimumInterval > 0 && event.time - previousOutputTime <= minimumInterval)
455 continue;
456 if (!EnsureRows(&SDDS_output, &allocatedRows, outputRows + 1) ||
457 !WriteAlarmEvent(&SDDS_output, outIndex, outputRows, &event)) {
458 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
459 exit(EXIT_FAILURE);
460 }
461 previousOutputTime = event.time;
462 outputRows++;
463 }
464 }
465
466 if (timeData)
467 free(timeData);
468 if (timeOfDayData)
469 free(timeOfDayData);
470 if (timeOfDayWSData)
471 free(timeOfDayWSData);
472 if (durationData)
473 free(durationData);
474 if (previousRowData)
475 free(previousRowData);
476 if (controlNameIndexData)
477 free(controlNameIndexData);
478 if (alarmStatusIndexData)
479 free(alarmStatusIndexData);
480 if (alarmSeverityIndexData)
481 free(alarmSeverityIndexData);
482 if (controlNameData)
483 SDDS_FreeStringArray(controlNameData, rows);
484 if (alarmStatusData)
485 SDDS_FreeStringArray(alarmStatusData, rows);
486 if (alarmSeverityData)
487 SDDS_FreeStringArray(alarmSeverityData, rows);
488 if (descriptionData)
489 SDDS_FreeStringArray(descriptionData, rows);
490 if (relatedControlNameData)
491 SDDS_FreeStringArray(relatedControlNameData, rows);
492 if (relatedValueStringData)
493 SDDS_FreeStringArray(relatedValueStringData, rows);
494 if (controlNameArray)
495 SDDS_FreeArray(controlNameArray);
496 if (alarmStatusArray)
497 SDDS_FreeArray(alarmStatusArray);
498 if (alarmSeverityArray)
499 SDDS_FreeArray(alarmSeverityArray);
500 if (descriptionArray)
501 SDDS_FreeArray(descriptionArray);
502 if (relatedControlNameArray)
503 SDDS_FreeArray(relatedControlNameArray);
504 }
505
506 if (snapshot) {
507 for (i = 0; i < snapshotEvents; i++) {
508 if (!snapshotEvent[i].used)
509 continue;
510 if (!EnsureRows(&SDDS_output, &allocatedRows, outputRows + 1) ||
511 !WriteAlarmEvent(&SDDS_output, outIndex, outputRows, snapshotEvent + i)) {
512 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
513 exit(EXIT_FAILURE);
514 }
515 outputRows++;
516 }
517 }
518
519 if (!SDDS_WriteTable(&SDDS_output) ||
520 !SDDS_Terminate(&SDDS_input) ||
521 !SDDS_Terminate(&SDDS_output)) {
522 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
523 exit(EXIT_FAILURE);
524 }
525
526 if (snapshotEvent) {
527 for (i = 0; i < snapshotEvents; i++)
528 ClearAlarmEvent(snapshotEvent + i);
529 free(snapshotEvent);
530 }
531 if (retainName)
532 free(retainName);
533 if (deleteName)
534 free(deleteName);
535 if (tmpfile_used && !replaceFileAndBackUp(input, output))
536 exit(EXIT_FAILURE);
537 free_scanargs(&s_arg, argc);
538 return EXIT_SUCCESS;
539}
540
541static int NameMatchesList(const char *name, char **list, long items) {
542 long i;
543 char *expanded;
544 int matched;
545
546 for (i = 0; i < items; i++) {
547 expanded = expand_ranges(list[i]);
548 matched = wild_match((char *)name, expanded);
549 if (expanded)
550 free(expanded);
551 if (matched)
552 return 1;
553 }
554 return 0;
555}
556
557static int NameSelected(const char *name, char **deleteName, long deleteNames, char **retainName, long retainNames) {
558 int selected;
559
560 selected = 1;
561 if (deleteNames && NameMatchesList(name, deleteName, deleteNames))
562 selected = 0;
563 if (retainNames) {
564 if (!deleteNames)
565 selected = 0;
566 if (NameMatchesList(name, retainName, retainNames))
567 selected = 1;
568 }
569 return selected;
570}
571
572static int DefineOutputColumns(SDDS_DATASET *outSet, int32_t *outIndex, int *available, long outputType) {
573 if (available[COL_TIME] &&
574 0 > (outIndex[COL_TIME] = SDDS_DefineColumn(outSet, "Time", NULL, "s", "Computed epoch time", NULL, outputType, 0)))
575 return 0;
576 if (available[COL_PREVIOUS_ROW] &&
577 0 > (outIndex[COL_PREVIOUS_ROW] = SDDS_DefineColumn(outSet, "PreviousRow", NULL, NULL, NULL, "%6ld", SDDS_LONG, 0)))
578 return 0;
579 if (available[COL_TIME_OF_DAY_WS] &&
580 0 > (outIndex[COL_TIME_OF_DAY_WS] = SDDS_DefineColumn(outSet, "TimeOfDayWS", NULL, "h", "Time of day in hours per workstation", "%8.5f", SDDS_FLOAT, 0)))
581 return 0;
582 if (available[COL_TIME_OF_DAY] &&
583 0 > (outIndex[COL_TIME_OF_DAY] = SDDS_DefineColumn(outSet, "TimeOfDay", NULL, "h", "Time of day in hours per IOC", "%8.5f", SDDS_FLOAT, 0)))
584 return 0;
585 if (available[COL_CONTROL_NAME] &&
586 0 > (outIndex[COL_CONTROL_NAME] = SDDS_DefineColumn(outSet, "ControlName", NULL, NULL, NULL, "%32s", SDDS_STRING, 0)))
587 return 0;
588 if (available[COL_ALARM_STATUS] &&
589 0 > (outIndex[COL_ALARM_STATUS] = SDDS_DefineColumn(outSet, "AlarmStatus", NULL, NULL, NULL, "%12s", SDDS_STRING, 0)))
590 return 0;
591 if (available[COL_ALARM_SEVERITY] &&
592 0 > (outIndex[COL_ALARM_SEVERITY] = SDDS_DefineColumn(outSet, "AlarmSeverity", NULL, NULL, NULL, "%10s", SDDS_STRING, 0)))
593 return 0;
594 if (available[COL_DESCRIPTION] &&
595 0 > (outIndex[COL_DESCRIPTION] = SDDS_DefineColumn(outSet, "Description", NULL, NULL, NULL, NULL, SDDS_STRING, 0)))
596 return 0;
597 if (available[COL_RELATED_CONTROL_NAME] &&
598 0 > (outIndex[COL_RELATED_CONTROL_NAME] = SDDS_DefineColumn(outSet, "RelatedControlName", NULL, NULL, NULL, NULL, SDDS_STRING, 0)))
599 return 0;
600 if (available[COL_DURATION] &&
601 0 > (outIndex[COL_DURATION] = SDDS_DefineColumn(outSet, "Duration", NULL, "s", NULL, "%8.4f", SDDS_FLOAT, 0)))
602 return 0;
603 if (available[COL_RELATED_VALUE_STRING] &&
604 0 > (outIndex[COL_RELATED_VALUE_STRING] = SDDS_DefineColumn(outSet, "RelatedValueString", NULL, NULL, NULL, NULL, SDDS_STRING, 0)))
605 return 0;
606 return 1;
607}
608
609static int EnsureRows(SDDS_DATASET *outSet, int64_t *allocatedRows, int64_t neededRows) {
610 int64_t increment;
611
612 if (neededRows <= *allocatedRows)
613 return 1;
614 increment = neededRows - *allocatedRows;
615 if (increment < 100)
616 increment = 100;
617 if (!SDDS_LengthenTable(outSet, increment))
618 return 0;
619 *allocatedRows += increment;
620 return 1;
621}
622
623static int WriteAlarmEvent(SDDS_DATASET *outSet, int32_t *outIndex, int64_t row, ALARM_EVENT *event) {
624 if (outIndex[COL_TIME] >= 0 &&
625 !SDDS_SetRowValues(outSet, SDDS_PASS_BY_VALUE | SDDS_SET_BY_INDEX, row, outIndex[COL_TIME], event->time, -1))
626 return 0;
627 if (outIndex[COL_PREVIOUS_ROW] >= 0 &&
628 !SDDS_SetRowValues(outSet, SDDS_PASS_BY_VALUE | SDDS_SET_BY_INDEX, row, outIndex[COL_PREVIOUS_ROW], event->previousRow, -1))
629 return 0;
630 if (outIndex[COL_TIME_OF_DAY_WS] >= 0 &&
631 !SDDS_SetRowValues(outSet, SDDS_PASS_BY_VALUE | SDDS_SET_BY_INDEX, row, outIndex[COL_TIME_OF_DAY_WS], event->timeOfDayWS, -1))
632 return 0;
633 if (outIndex[COL_TIME_OF_DAY] >= 0 &&
634 !SDDS_SetRowValues(outSet, SDDS_PASS_BY_VALUE | SDDS_SET_BY_INDEX, row, outIndex[COL_TIME_OF_DAY], event->timeOfDay, -1))
635 return 0;
636 if (outIndex[COL_CONTROL_NAME] >= 0 &&
637 !SDDS_SetRowValues(outSet, SDDS_PASS_BY_VALUE | SDDS_SET_BY_INDEX, row, outIndex[COL_CONTROL_NAME], event->controlName ? event->controlName : "", -1))
638 return 0;
639 if (outIndex[COL_ALARM_STATUS] >= 0 &&
640 !SDDS_SetRowValues(outSet, SDDS_PASS_BY_VALUE | SDDS_SET_BY_INDEX, row, outIndex[COL_ALARM_STATUS], event->alarmStatus ? event->alarmStatus : "", -1))
641 return 0;
642 if (outIndex[COL_ALARM_SEVERITY] >= 0 &&
643 !SDDS_SetRowValues(outSet, SDDS_PASS_BY_VALUE | SDDS_SET_BY_INDEX, row, outIndex[COL_ALARM_SEVERITY], event->alarmSeverity ? event->alarmSeverity : "", -1))
644 return 0;
645 if (outIndex[COL_DESCRIPTION] >= 0 &&
646 !SDDS_SetRowValues(outSet, SDDS_PASS_BY_VALUE | SDDS_SET_BY_INDEX, row, outIndex[COL_DESCRIPTION], event->description ? event->description : "", -1))
647 return 0;
648 if (outIndex[COL_RELATED_CONTROL_NAME] >= 0 &&
649 !SDDS_SetRowValues(outSet, SDDS_PASS_BY_VALUE | SDDS_SET_BY_INDEX, row, outIndex[COL_RELATED_CONTROL_NAME], event->relatedControlName ? event->relatedControlName : "", -1))
650 return 0;
651 if (outIndex[COL_DURATION] >= 0 &&
652 !SDDS_SetRowValues(outSet, SDDS_PASS_BY_VALUE | SDDS_SET_BY_INDEX, row, outIndex[COL_DURATION], event->duration, -1))
653 return 0;
654 if (outIndex[COL_RELATED_VALUE_STRING] >= 0 &&
655 !SDDS_SetRowValues(outSet, SDDS_PASS_BY_VALUE | SDDS_SET_BY_INDEX, row, outIndex[COL_RELATED_VALUE_STRING], event->relatedValueString ? event->relatedValueString : "", -1))
656 return 0;
657 return 1;
658}
659
660static double ComputeEpochTime(double timeOfDay, double startTime, double startHour) {
661 double deltaHours;
662
663 deltaHours = timeOfDay - startHour;
664 if (deltaHours < -12)
665 deltaHours += 24;
666 return startTime + 3600 * deltaHours;
667}
668
669static char *ArrayString(SDDS_ARRAY *array, int32_t index) {
670 if (!array || index < 0 || index >= array->elements)
671 return NULL;
672 return ((char **)array->data)[index];
673}
674
675static char *StringColumnValue(char **column, int64_t row) {
676 if (!column)
677 return NULL;
678 return column[row];
679}
680
681static void ClearAlarmEvent(ALARM_EVENT *event) {
682 if (!event)
683 return;
684 if (event->controlName)
685 free(event->controlName);
686 if (event->alarmStatus)
687 free(event->alarmStatus);
688 if (event->alarmSeverity)
689 free(event->alarmSeverity);
690 if (event->description)
691 free(event->description);
692 if (event->relatedControlName)
693 free(event->relatedControlName);
694 if (event->relatedValueString)
695 free(event->relatedValueString);
696 memset(event, 0, sizeof(*event));
697}
698
699static int CopyStringOrBlank(char **target, const char *source) {
700 if (!source)
701 source = "";
702 return SDDS_CopyString(target, (char *)source);
703}
704
705static int SaveSnapshotEvent(ALARM_EVENT **snapshotEvent, int64_t *snapshotEvents, ALARM_EVENT *event) {
706 int64_t i;
707 ALARM_EVENT *item;
708
709 for (i = 0; i < *snapshotEvents; i++) {
710 if ((*snapshotEvent)[i].used && strcmp((*snapshotEvent)[i].controlName, event->controlName) == 0)
711 break;
712 }
713 if (i == *snapshotEvents) {
714 *snapshotEvent = trealloc(*snapshotEvent, sizeof(**snapshotEvent) * (*snapshotEvents + 1));
715 memset(*snapshotEvent + *snapshotEvents, 0, sizeof(**snapshotEvent));
716 (*snapshotEvents)++;
717 } else {
718 ClearAlarmEvent(*snapshotEvent + i);
719 }
720
721 item = *snapshotEvent + i;
722 item->used = 1;
723 item->time = event->time;
724 item->previousRow = event->previousRow;
725 item->timeOfDayWS = event->timeOfDayWS;
726 item->timeOfDay = event->timeOfDay;
727 item->duration = event->duration;
728 if (!CopyStringOrBlank(&item->controlName, event->controlName) ||
729 !CopyStringOrBlank(&item->alarmStatus, event->alarmStatus) ||
730 !CopyStringOrBlank(&item->alarmSeverity, event->alarmSeverity) ||
731 !CopyStringOrBlank(&item->description, event->description) ||
732 !CopyStringOrBlank(&item->relatedControlName, event->relatedControlName) ||
733 !CopyStringOrBlank(&item->relatedValueString, event->relatedValueString))
734 return 0;
735 return 1;
736}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t SDDS_CopyParameters(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source)
Definition SDDS_copy.c:286
int32_t SDDS_LengthenTable(SDDS_DATASET *SDDS_dataset, int64_t n_additional_rows)
int32_t SDDS_SetRowValues(SDDS_DATASET *SDDS_dataset, int32_t mode, int64_t row,...)
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...
SDDS_ARRAY * SDDS_GetArray(SDDS_DATASET *SDDS_dataset, char *array_name, SDDS_ARRAY *memory)
Retrieves an array from the current data table of an SDDS dataset.
int32_t * SDDS_GetColumnInLong(SDDS_DATASET *SDDS_dataset, char *column_name)
Retrieves the data of a specified numerical column as an array of 32-bit integers,...
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_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_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_TransferAllParameterDefinitions(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source, uint32_t mode)
Transfers all parameter definitions from a source dataset to a target dataset.
void SDDS_FreeArray(SDDS_ARRAY *array)
Frees memory allocated for an SDDS array structure.
int32_t SDDS_CheckArray(SDDS_DATASET *SDDS_dataset, char *name, char *units, int32_t type, FILE *fp_message)
Checks if an array exists in the SDDS dataset with the specified name, units, and type.
int32_t SDDS_FreeStringArray(char **string, int64_t strings)
Frees an array of strings by deallocating each individual string.
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
int32_t SDDS_CopyString(char **target, const char *source)
Copies a source string to a target string with memory allocation.
Definition SDDS_utils.c:922
#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_LONG
Identifier for the signed 32-bit integer data type.
Definition SDDStypes.h:61
#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
#define SDDS_ANY_INTEGER_TYPE
Special identifier used by SDDS_Check*() routines to accept any integer type.
Definition SDDStypes.h:173
void * trealloc(void *old_ptr, uint64_t size_of_block)
Reallocates a memory block to a new size.
Definition array.c:190
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.
long replaceFileAndBackUp(char *file, char *replacement)
Replaces a file with a replacement file and creates a backup of the original.
Definition replacefile.c:78
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
void free_scanargs(SCANNED_ARG **scanned, int argc)
Definition scanargs.c:588
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.
char * expand_ranges(char *template)
Expand range specifiers in a wildcard template into explicit character lists.
Definition wild_match.c:429
int wild_match(char *string, char *template)
Determine whether one string is a wildcard match for another.
Definition wild_match.c:49