85 {
87 SCANNED_ARG *s_arg;
88 KEYED_EQUIVALENT **keyGroup = NULL;
89 long keyGroups = 0;
90 char **inputfile = NULL;
91 int inputfiles = 0;
92 char *outputfile = NULL;
93 int i_arg, n, row, z;
94 int threads = 1;
95 int64_t i, j, m, r, s;
96 unsigned long pipeFlags = 0;
97 int overwrite = 0;
98 double **timeValues = NULL;
99 double **dataValues = NULL;
100 short **flag = NULL;
101 int64_t *rows = NULL;
102 char **dataNames = NULL;
103 char **uniqueDataName = NULL;
104 int uniqueDataNames = 0;
105 int page = 0;
106 int pages;
107 int found;
108 double *outputTimeValues = NULL;
109 double **outputDataValues = NULL;
110 int64_t allocated_rows = 0;
111 int **array = NULL;
112 int *arrayCount;
114
116 argc =
scanargs(&s_arg, argc, argv);
117
118 if (argc < 3) {
119 fprintf(stderr, "%s", USAGE);
120 return EXIT_FAILURE;
121 }
122
123 for (i_arg = 1; i_arg < argc; i_arg++) {
124 if (s_arg[i_arg].arg_type == OPTION) {
125 switch (
match_string(s_arg[i_arg].list[0], option, N_OPTIONS, 0)) {
126 case SET_OVERWRITE:
127 overwrite = 1;
128 break;
129 case SET_THREADS:
130 if (s_arg[i_arg].n_items != 2 ||
131 sscanf(s_arg[i_arg].list[1], "%d", &threads) != 1 ||
132 threads < 1) {
133 fprintf(stderr, "Error: Invalid -threads option syntax.\n");
134 return EXIT_FAILURE;
135 }
136 break;
137 case SET_PIPE:
139 s_arg[i_arg].n_items - 1,
140 &pipeFlags)) {
141 fprintf(stderr, "Error: Invalid -pipe option syntax.\n");
142 return EXIT_FAILURE;
143 }
144 if (pipeFlags & USE_STDIN) {
145 fprintf(stderr, "Error: -pipe=in is not supported.\n");
146 return EXIT_FAILURE;
147 }
148 break;
149 default:
150 fprintf(stderr, "Error: Unrecognized option.\n%s", USAGE);
151 return EXIT_FAILURE;
152 }
153 } else {
154 inputfile =
trealloc(inputfile,
sizeof(*inputfile) * (inputfiles + 1));
155 inputfile[inputfiles++] = s_arg[i_arg].list[0];
156 }
157 }
158
159 if (inputfiles > 1) {
160 if (!(pipeFlags & USE_STDOUT)) {
161 outputfile = inputfile[--inputfiles];
162 if (
fexists(outputfile) && !overwrite) {
163 fprintf(stderr, "Error: Output file '%s' already exists. Use -overwrite to replace it.\n", outputfile);
164 return EXIT_FAILURE;
165 }
166 }
167 } else if (inputfiles == 1) {
168 if ((pipeFlags & USE_STDOUT) && outputfile) {
169 fprintf(stderr, "Error: Too many filenames provided with -pipe=output.\n");
170 return EXIT_FAILURE;
171 }
172 } else {
173 fprintf(stderr, "Error: No input filenames provided.\n%s", USAGE);
174 return EXIT_FAILURE;
175 }
176
177 if (threads > inputfiles)
178 threads = inputfiles;
179
180 logFile = calloc(inputfiles, sizeof(*logFile));
181 if (!logFile) {
182 fprintf(stderr, "Error: Memory allocation failure.\n");
183 return EXIT_FAILURE;
184 }
185
186#pragma omp parallel for if (threads > 1 && inputfiles > 1) num_threads(threads) schedule(dynamic)
187 for (i = 0; i < inputfiles; i++) {
188 LoadLogFile(inputfile[i], &logFile[i]);
189 }
190
191 pages = 0;
192 for (i = 0; i < inputfiles; i++) {
193 if (!logFile[i].status) {
194 fprintf(stderr, "%s\n", logFile[i].error);
195 for (j = 0; j < inputfiles; j++)
196 FreeLogFileData(&logFile[j]);
197 free(logFile);
198 return EXIT_FAILURE;
199 }
200 pages += logFile[i].pages;
201 }
202
203 timeValues = malloc(sizeof(*timeValues) * pages);
204 dataValues = malloc(sizeof(*dataValues) * pages);
205 dataNames = malloc(sizeof(*dataNames) * pages);
206 rows = malloc(sizeof(*rows) * pages);
207 if (!timeValues || !dataValues || !dataNames || !rows) {
208 fprintf(stderr, "Error: Memory allocation failure.\n");
209 for (i = 0; i < inputfiles; i++)
210 FreeLogFileData(&logFile[i]);
211 free(logFile);
212 return EXIT_FAILURE;
213 }
214
215 page = 0;
216 for (i = 0; i < inputfiles; i++) {
217 int filePage;
218 for (filePage = 0; filePage < logFile[i].pages; filePage++) {
219 timeValues[page] = logFile[i].page[filePage].timeValues;
220 dataValues[page] = logFile[i].page[filePage].dataValues;
221 dataNames[page] = logFile[i].page[filePage].dataName;
222 rows[page] = logFile[i].page[filePage].rows;
223 logFile[i].page[filePage].timeValues = NULL;
224 logFile[i].page[filePage].dataValues = NULL;
225 logFile[i].page[filePage].dataName = NULL;
226 page++;
227 }
228 FreeLogFileData(&logFile[i]);
229 }
230 free(logFile);
231
232 pages = page;
233
234
235 for (page = 0; page < pages; page++) {
236 found = 0;
237 for (i = 0; i < uniqueDataNames; i++) {
238 if (strcmp(dataNames[page], uniqueDataName[i]) == 0) {
239 found = 1;
240 break;
241 }
242 }
243 if (!found) {
244 uniqueDataName = realloc(uniqueDataName, sizeof(*uniqueDataName) * (uniqueDataNames + 1));
246 uniqueDataNames++;
247 }
248 }
249
250
253 return EXIT_FAILURE;
254 }
255
258 return EXIT_FAILURE;
259 }
260
261 for (i = 0; i < uniqueDataNames; i++) {
264 return EXIT_FAILURE;
265 }
266 }
267
268 outputDataValues = malloc(sizeof(*outputDataValues) * uniqueDataNames);
269 if (uniqueDataNames == 1) {
270
271 for (page = 0; page < pages; page++) {
272 allocated_rows += rows[page];
273 }
274
275 outputTimeValues = malloc(sizeof(*outputTimeValues) * allocated_rows);
276 outputDataValues[0] = malloc(sizeof(*(outputDataValues[0])) * allocated_rows);
277
278 i = 0;
279 for (page = 0; page < pages; page++) {
280 for (j = 0; j < rows[page]; j++) {
281 outputTimeValues[i] = timeValues[page][j];
282 outputDataValues[0][i] = dataValues[page][j];
283 i++;
284 }
285 }
286 } else {
287
288 flag = malloc(sizeof(*flag) * pages);
289 for (page = 0; page < pages; page++) {
290 flag[page] = calloc(rows[page], sizeof(*(flag[page])));
291 }
292
293 array = malloc(sizeof(*array) * uniqueDataNames);
294 arrayCount = calloc(uniqueDataNames, sizeof(*arrayCount));
295
296 for (i = 0; i < uniqueDataNames; i++) {
297 for (page = 0; page < pages; page++) {
298 if (strcmp(dataNames[page], uniqueDataName[i]) == 0) {
299 arrayCount[i]++;
300 if (arrayCount[i] == 1) {
301 array[i] = malloc(sizeof(*(array[i])));
302 } else {
303 array[i] = realloc(array[i], sizeof(*(array[i])) * arrayCount[i]);
304 }
305 array[i][arrayCount[i] - 1] = page;
306 }
307 }
308 }
309
310 for (i = 0; i < arrayCount[0]; i++) {
312 for (n = 1; n < uniqueDataNames; n++) {
313 for (m = 0; m < arrayCount[n]; m++) {
314 if ((i == m) && (rows[array[0][i]] == rows[array[n][m]]) && (rows[array[0][i]] > 10)) {
315 if ((timeValues[array[0][i]][0] == timeValues[array[n][m]][0]) &&
316 (timeValues[array[0][i]][1] == timeValues[array[n][m]][1]) &&
317 (timeValues[array[0][i]][rows[array[0][i]] - 2] == timeValues[array[n][m]][rows[array[n][m]] - 2]) &&
318 (timeValues[array[0][i]][rows[array[0][i]] - 1] == timeValues[array[n][m]][rows[array[n][m]] - 1])) {
319
320 for (r = 0; r < rows[array[n][m]]; r++) {
321 if (flag[array[n][m]][r]) {
322 continue;
323 }
324 flag[array[0][i]][r] += 1;
325 flag[array[n][m]][r] = 1;
326 }
327 }
328 }
329
330 for (r = 0; r < rows[array[n][m]]; r++) {
331 if (flag[array[n][m]][r]) {
332 continue;
333 }
335 if (row >= 0) {
336 flag[array[0][i]][row] += 1;
337 flag[array[n][m]][r] = 1;
338 }
339 }
340 }
341 }
342
343 for (j = 0; j < keyGroups; j++) {
344 free(keyGroup[j]->equivalent);
345 free(keyGroup[j]);
346 }
347 free(keyGroup);
348 }
349
350 z = uniqueDataNames - 1;
351 for (n = 0; n < arrayCount[0]; n++) {
352 for (m = 0; m < rows[array[0][n]]; m++) {
353 if (flag[array[0][n]][m] >= z) {
354 allocated_rows++;
355 }
356 }
357 }
358
359 outputTimeValues = malloc(sizeof(*outputTimeValues) * allocated_rows);
360 for (i = 0; i < uniqueDataNames; i++) {
361 outputDataValues[i] = malloc(sizeof(*(outputDataValues[i])) * allocated_rows);
362 }
363
364 s = 0;
365 for (i = 0; i < arrayCount[0]; i++) {
366 for (j = 0; j < rows[array[0][i]]; j++) {
367 if (flag[array[0][i]][j] >= z) {
368 outputTimeValues[s] = timeValues[array[0][i]][j];
369 outputDataValues[0][s] = dataValues[array[0][i]][j];
370 s++;
371 }
372 }
373 }
374
375 if (s == 0) {
376 fprintf(stderr, "Error: No matching 'Time' rows found in input files.\n");
377 return EXIT_FAILURE;
378 }
379
381
382 for (n = 1; n < uniqueDataNames; n++) {
383 for (m = 0; m < arrayCount[n]; m++) {
384 for (r = 0; r < rows[array[n][m]]; r++) {
385 if (flag[array[n][m]][r]) {
387 if (row >= 0) {
388 outputDataValues[n][row] = dataValues[array[n][m]][r];
389 }
390 }
391 }
392 }
393 }
394
395 for (i = 0; i < uniqueDataNames; i++) {
396 free(array[i]);
397 }
398
399 for (j = 0; j < keyGroups; j++) {
400 if (keyGroup[j]->equivalent)
401 free(keyGroup[j]->equivalent);
402 if (keyGroup[j])
403 free(keyGroup[j]);
404 }
405
406 for (page = 0; page < pages; page++) {
407 free(flag[page]);
408 }
409
410 free(array);
411 free(keyGroup);
412 free(arrayCount);
413 free(flag);
414 }
415
416
417 for (page = 0; page < pages; page++) {
418 if (timeValues[page])
419 free(timeValues[page]);
420 if (dataValues[page])
421 free(dataValues[page]);
422 free(dataNames[page]);
423 }
424 free(timeValues);
425 free(dataValues);
426 free(dataNames);
427
428
431 return EXIT_FAILURE;
432 }
433
436 return EXIT_FAILURE;
437 }
438
441 return EXIT_FAILURE;
442 }
443
444 for (i = 0; i < uniqueDataNames; i++) {
445 if (!
SDDS_SetColumnFromDoubles(&SDDS_output, SDDS_SET_BY_NAME, outputDataValues[i], allocated_rows, uniqueDataName[i])) {
447 return EXIT_FAILURE;
448 }
449 }
450
451 if (!SDDS_WriteTable(&SDDS_output)) {
453 return EXIT_FAILURE;
454 }
455
458 return EXIT_FAILURE;
459 }
460
461
462 for (i = 0; i < uniqueDataNames; i++) {
463 free(uniqueDataName[i]);
464 free(outputDataValues[i]);
465 }
466 free(outputTimeValues);
467 free(outputDataValues);
468 free(uniqueDataName);
469 free(rows);
470
471 if (inputfiles > 0) {
472 free(inputfile);
473 }
474
476
477 return EXIT_SUCCESS;
478}
int32_t SDDS_StartPage(SDDS_DATASET *SDDS_dataset, int64_t expected_n_rows)
int32_t SDDS_SetColumnFromDoubles(SDDS_DATASET *SDDS_dataset, int32_t mode, double *data, int64_t rows,...)
Sets the values for a single data column using double-precision floating-point numbers.
int32_t SDDS_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_DefineSimpleColumn(SDDS_DATASET *SDDS_dataset, const char *name, const char *unit, int32_t type)
Defines a simple data column within the SDDS dataset.
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.
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
#define SDDS_DOUBLE
Identifier for the double data type.
void * trealloc(void *old_ptr, uint64_t size_of_block)
Reallocates a memory block to a new size.
long fexists(const char *filename)
Checks if a file exists.
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)
long processPipeOption(char **item, long items, unsigned long *flags)
void free_scanargs(SCANNED_ARG **scanned, int argc)
KEYED_EQUIVALENT ** MakeSortedKeyGroups(long *keyGroups, long keyType, void *data, long points)
Create sorted key groups from data.
long FindMatchingKeyGroup(KEYED_EQUIVALENT **keyGroup, long keyGroups, long keyType, void *searchKeyData, long reuse)
Find a matching key group for a search key.