SDDS ToolKit Programs and Libraries for C and Python
Loading...
Searching...
No Matches
SDDS_input.c
Go to the documentation of this file.
1/**
2 * @file SDDS_input.c
3 * @brief This file contains the functions related to reading SDDS files.
4 *
5 * The SDDS_input.c file provides functions for reading data from SDDS files.
6 * It includes functions for opening and closing SDDS files, reading headers,
7 * and reading data tables.
8 *
9 * @copyright
10 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
11 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
12 *
13 * @license
14 * This file is distributed under the terms of the Software License Agreement
15 * found in the file LICENSE included with this distribution.
16 *
17 * @author M. Borland, C. Saunders, R. Soliday, H. Shang
18 */
19
20#include "mdb.h"
21#include "match_string.h"
22#include "SDDS.h"
23#include "SDDS_internal.h"
24#include "mdb_thread.h"
25#include "namelist.h"
26#include "scan.h"
27
28#if defined(_WIN32)
29# include <fcntl.h>
30# include <io.h>
31# if !defined(_MINGW)
32# define pclose(x) _pclose(x)
33# endif
34# if defined(__BORLANDC__)
35# define _setmode(handle, amode) setmode(handle, amode)
36# endif
37#endif
38
39#define DEBUG 0
40
41/**
42 * Initializes a SDDS_DATASET structure for use in reading data from a SDDS file. This involves opening the file and reading the SDDS header.
43 *
44 * @param SDDS_dataset Address of the SDDS_DATASET structure for the data set.
45 * @param filename A NULL-terminated character string giving the name of the file to set up for input.
46 *
47 * @return 1 on success. On failure, returns 0 and records an error message.
48 *
49 */
50int32_t SDDS_InitializeInput(SDDS_DATASET *SDDS_dataset, char *filename) {
51 /* char *ptr, *datafile, *headerfile; */
52 char s[SDDS_MAXLINE];
53#if defined(zLib)
54 char *extension;
55#endif
56 if (sizeof(gzFile) != sizeof(void *)) {
57 SDDS_SetError("gzFile is not the same size as void *, possible corruption of the SDDS_LAYOUT structure");
58 return (0);
59 }
60 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_InitializeInput"))
61 return (0);
62
63 if (!SDDS_ZeroMemory((void *)SDDS_dataset, sizeof(SDDS_DATASET))) {
64 sprintf(s, "Unable to initialize input for file %s--can't zero SDDS_DATASET structure (SDDS_InitializeInput)", filename);
66 return (0);
67 }
68 SDDS_dataset->layout.gzipFile = SDDS_dataset->layout.lzmaFile = SDDS_dataset->layout.disconnected = SDDS_dataset->layout.popenUsed = 0;
69 SDDS_dataset->layout.depth = SDDS_dataset->layout.data_command_seen = SDDS_dataset->layout.commentFlags = SDDS_dataset->deferSavingLayout = 0;
70 SDDS_dataset->layout.data_mode.column_memory_mode = DEFAULT_COLUMN_MEMORY_MODE;
71 if (!filename)
72 SDDS_dataset->layout.filename = NULL;
73 else if (!SDDS_CopyString(&SDDS_dataset->layout.filename, filename)) {
74 sprintf(s, "Memory allocation failure initializing file \"%s\" (SDDS_InitializeInput)", filename);
76 return (0);
77 }
78 if (!filename) {
79#if defined(_WIN32)
80 if (_setmode(_fileno(stdin), _O_BINARY) == -1) {
81 sprintf(s, "unable to set stdin to binary mode");
83 return 0;
84 }
85#endif
86 SDDS_dataset->layout.fp = stdin;
87 } else {
88#if defined(zLib)
89 if (!(extension = strrchr(filename, '.')) || strcmp(extension, ".gz") != 0) {
90#endif
91 if ((extension = strrchr(filename, '.')) && ((strcmp(extension, ".lzma") == 0) || (strcmp(extension, ".xz") == 0))) {
92 SDDS_dataset->layout.lzmaFile = 1;
93 if (!(SDDS_dataset->layout.lzmafp = UnpackLZMAOpen(filename))) {
94 sprintf(s, "Unable to open file \"%s\" for reading (SDDS_InitializeInput)", filename);
96 return (0);
97 }
98 SDDS_dataset->layout.fp = SDDS_dataset->layout.lzmafp->fp;
99 } else {
100 if (!(SDDS_dataset->layout.fp = UnpackFopen(filename, UNPACK_REQUIRE_SDDS | UNPACK_USE_PIPE, &SDDS_dataset->layout.popenUsed, NULL))) {
101 sprintf(s, "Unable to open file \"%s\" for reading (SDDS_InitializeInput)", filename);
102 SDDS_SetError(s);
103 return (0);
104 }
105 }
106#if defined(zLib)
107 } else {
108 SDDS_dataset->layout.gzipFile = 1;
109 if (!(SDDS_dataset->layout.gzfp = gzopen(filename, "rb"))) {
110 sprintf(s, "Unable to open file \"%s\" for reading (SDDS_InitializeInput)", filename);
111 SDDS_SetError(s);
112 return (0);
113 }
114 }
115#endif
116 }
117 SDDS_dataset->page_number = SDDS_dataset->page_started = 0;
118 SDDS_dataset->file_had_data = 0;
119 SDDS_DeferSavingLayout(SDDS_dataset, 1);
120#if defined(zLib)
121 if (SDDS_dataset->layout.gzipFile) {
122 if (!SDDS_GZipReadLayout(SDDS_dataset, SDDS_dataset->layout.gzfp))
123 return (0);
124 } else {
125#endif
126 if (SDDS_dataset->layout.lzmaFile) {
127 if (!SDDS_LZMAReadLayout(SDDS_dataset, SDDS_dataset->layout.lzmafp))
128 return (0);
129 } else {
130 if (!SDDS_ReadLayout(SDDS_dataset, SDDS_dataset->layout.fp))
131 return (0);
132 }
133#if defined(zLib)
134 }
135#endif
136 SDDS_dataset->layout.layout_written = 0;
137 SDDS_DeferSavingLayout(SDDS_dataset, 0);
138 if (!SDDS_SaveLayout(SDDS_dataset))
139 return 0;
140 if (SDDS_dataset->layout.n_columns &&
141 ((!(SDDS_dataset->column_flag = (int32_t *)SDDS_Malloc(sizeof(int32_t) * SDDS_dataset->layout.n_columns)) ||
142 !(SDDS_dataset->column_order = (int32_t *)SDDS_Malloc(sizeof(int32_t) * SDDS_dataset->layout.n_columns))) ||
143 (!SDDS_SetMemory(SDDS_dataset->column_flag, SDDS_dataset->layout.n_columns, SDDS_LONG, (int32_t)1, (int32_t)0) ||
144 !SDDS_SetMemory(SDDS_dataset->column_order, SDDS_dataset->layout.n_columns, SDDS_LONG, (int32_t)0, (int32_t)1)))) {
145 SDDS_SetError("Unable to initialize input--memory allocation failure (SDDS_InitializeInput)");
146 return (0);
147 }
148 SDDS_dataset->mode = SDDS_READMODE; /*reading */
149 SDDS_dataset->pagecount_offset = NULL;
150 if (!SDDS_dataset->layout.gzipFile && !SDDS_dataset->layout.lzmaFile && !SDDS_dataset->layout.popenUsed && SDDS_dataset->layout.filename) {
151 /* Data is not:
152 1. from a gzip file
153 2. from a file that is being internally decompressed by a command executed with popen()
154 3. from a pipe set up externally (e.g., -pipe=in on commandline)
155 */
156 SDDS_dataset->pages_read = 0;
157 SDDS_dataset->pagecount_offset = malloc(sizeof(*SDDS_dataset->pagecount_offset));
158 SDDS_dataset->pagecount_offset[0] = ftell(SDDS_dataset->layout.fp);
159 fseek(SDDS_dataset->layout.fp, 0, 2); /*point to the end of the file */
160 SDDS_dataset->endOfFile_offset = ftell(SDDS_dataset->layout.fp);
161 fseek(SDDS_dataset->layout.fp, SDDS_dataset->pagecount_offset[0], 0);
162 /*point to the beginning of the first page */
163 }
164 return (1);
165}
166
167/**
168 * @brief Initializes the SDDS dataset for headerless input.
169 *
170 * This function initializes the SDDS dataset structure for reading data from a file without a header.
171 *
172 * @param SDDS_dataset A pointer to the SDDS_DATASET structure to be initialized.
173 * @param filename The name of the file to read data from.
174 * @return Returns 1 on success, 0 on failure.
175 */
176int32_t SDDS_InitializeHeaderlessInput(SDDS_DATASET *SDDS_dataset, char *filename) {
177 /* char *ptr, *datafile; */
178
179 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_InitializeInput"))
180 return (0);
181 if (!SDDS_ZeroMemory((void *)SDDS_dataset, sizeof(SDDS_DATASET))) {
182 SDDS_SetError("Unable to initialize input--can't zero SDDS_DATASET structure (SDDS_InitializeInput)");
183 return (0);
184 }
185 SDDS_dataset->layout.gzipFile = SDDS_dataset->layout.lzmaFile = 0;
186 SDDS_dataset->layout.depth = SDDS_dataset->layout.data_command_seen = SDDS_dataset->layout.commentFlags = SDDS_dataset->deferSavingLayout = 0;
187 if (!(SDDS_dataset->layout.fp = fopen(filename, FOPEN_READ_MODE))) {
188 SDDS_SetError("Unable to open file (SDDS_InitializeInput)");
189 return (0);
190 }
191 if (!SDDS_CopyString(&SDDS_dataset->layout.filename, filename)) {
192 SDDS_SetError("Memory allocation failure (SDDS_InitializeInput)");
193 return (0);
194 }
195 SDDS_dataset->mode = SDDS_READMODE; /*reading */
196 SDDS_dataset->page_number = SDDS_dataset->page_started = 0;
197 SDDS_dataset->pages_read = 0;
198 SDDS_dataset->pagecount_offset = malloc(sizeof(*SDDS_dataset->pagecount_offset));
199 SDDS_dataset->pagecount_offset[0] = ftell(SDDS_dataset->layout.fp);
200 fseek(SDDS_dataset->layout.fp, 0, 2); /*point to the end of the file */
201 SDDS_dataset->endOfFile_offset = ftell(SDDS_dataset->layout.fp);
202 fseek(SDDS_dataset->layout.fp, SDDS_dataset->pagecount_offset[0], 0);
203 /*point to the beginning of the first page */
204 return (1);
205}
206
207/**
208 * @brief Checks if a position in a string is within a quoted section.
209 *
210 * Determines whether the specified position within a string falls inside a quoted section
211 * delimited by the given quotation mark.
212 *
213 * @param string The string to examine.
214 * @param position The position within the string to check.
215 * @param quotation_mark The character used as the quotation mark.
216 * @return Returns 1 if the position is within a quoted section, 0 otherwise.
217 */
218int32_t SDDS_IsQuoted(char *string, char *position, char quotation_mark) {
219 int32_t in_quoted_section;
220 char *string0;
221
222 if (*position == quotation_mark)
223 return (1);
224
225 in_quoted_section = 0;
226 string0 = string;
227 while (*string) {
228 if (*string == quotation_mark && (string == string0 || *(string - 1) != '\\'))
229 in_quoted_section = !in_quoted_section;
230 else if (string == position)
231 return (in_quoted_section);
232 string++;
233 }
234 return (0);
235}
236
237/**
238 * @brief Reads a namelist from a file into a buffer.
239 *
240 * This function reads a namelist from the given file stream into the provided buffer,
241 * handling comments and skipping them appropriately.
242 *
243 * @param SDDS_dataset The SDDS dataset structure.
244 * @param buffer The buffer where the namelist will be stored.
245 * @param buflen The length of the buffer.
246 * @param fp The file stream to read from.
247 * @return Returns 1 if a namelist is successfully read, 0 otherwise.
248 */
249int32_t SDDS_GetNamelist(SDDS_DATASET *SDDS_dataset, char *buffer, int32_t buflen, FILE *fp) {
250 char *ptr, *flag, *buffer0;
251 /* char *ptr1 */
252 int32_t n, i;
253 /* int32_t namelistStarted; */
254
255 while ((flag = fgetsSkipComments(SDDS_dataset, buffer, buflen, fp, '!'))) {
256 if ((ptr = strchr(buffer, '&')) && !SDDS_IsQuoted(buffer, ptr, '"'))
257 break;
258 }
259 if (!flag)
260 return 0;
261 n = strlen(buffer) - 1;
262 if (buffer[n] == '\n') {
263 buffer[n] = ' ';
264 if ((n - 1 >= 0) && (buffer[n - 1] == '\r'))
265 buffer[n - 1] = ' ';
266 }
267
268 /* check for the beginning of a namelist (an unquoted &) */
269 ptr = buffer;
270 while (*ptr) {
271 if (*ptr == '"') {
272 /* skip quoted section */
273 ptr++;
274 while (*ptr != '"' && *ptr)
275 ptr++;
276 if (*ptr)
277 ptr++;
278 continue;
279 }
280 if (*ptr == '&') {
281 if (strncmp(ptr, "&end", 4) == 0)
282 return 0;
283 break;
284 }
285 ptr++;
286 }
287 if (!*ptr)
288 return 0;
289
290 /* remove the trailing &end if there is one */
291 if ((n = strlen(buffer)) >= 4) {
292 ptr = buffer + n - 4;
293 while (1) {
294 if (*ptr == '&' && (ptr == buffer || *(ptr - 1) != '\\') && strncmp(ptr, "&end", 4) == 0 && !SDDS_IsQuoted(buffer, ptr, '"')) {
295 *ptr = 0;
296 return 1;
297 }
298 if (ptr == buffer)
299 break;
300 ptr--;
301 }
302 }
303
304 /* read in the remainder of the namelist */
305 buffer0 = buffer;
306 buflen -= strlen(buffer);
307 buffer += strlen(buffer);
308 i = 0;
309 while ((flag = fgetsSkipComments(SDDS_dataset, buffer, buflen, fp, '!'))) {
310 n = strlen(buffer) - 1;
311 if (buffer[n] == '\n') {
312 buffer[n] = ' ';
313 if ((n - 1 >= 0) && (buffer[n - 1] == '\r'))
314 buffer[n - 1] = ' ';
315 }
316 if ((ptr = strstr(buffer, "&end")) && !SDDS_IsQuoted(buffer0, ptr, '"'))
317 return 1;
318 buflen -= strlen(buffer);
319 buffer += strlen(buffer);
320 if (buflen == 0)
321 return 0;
322 /* this was needed after encountering a file that had binary crap
323 dumpted into the header. sddscheck will now report badHeader
324 instead of getting stuck in an endless loop here. */
325 i++;
326 if (i > 10000) {
327 return 0;
328 }
329 }
330 return 0;
331}
332
333/**
334 * @brief Reads a namelist from an LZMA-compressed file into a buffer.
335 *
336 * This function reads a namelist from an LZMA-compressed file stream into the provided buffer,
337 * handling comments and skipping them appropriately.
338 *
339 * @param SDDS_dataset The SDDS dataset structure.
340 * @param buffer The buffer where the namelist will be stored.
341 * @param buflen The length of the buffer.
342 * @param lzmafp The LZMA file stream to read from.
343 * @return Returns 1 if a namelist is successfully read, 0 otherwise.
344 */
345int32_t SDDS_GetLZMANamelist(SDDS_DATASET *SDDS_dataset, char *buffer, int32_t buflen, struct lzmafile *lzmafp) {
346 char *ptr, *flag, *buffer0;
347 /* char *ptr1 */
348 int32_t n;
349 /* int32_t namelistStarted; */
350
351 while ((flag = fgetsLZMASkipComments(SDDS_dataset, buffer, buflen, lzmafp, '!'))) {
352 if ((ptr = strchr(buffer, '&')) && !SDDS_IsQuoted(buffer, ptr, '"'))
353 break;
354 }
355 if (!flag)
356 return 0;
357 n = strlen(buffer) - 1;
358 if (buffer[n] == '\n') {
359 buffer[n] = ' ';
360 if ((n - 1 >= 0) && (buffer[n - 1] == '\r'))
361 buffer[n - 1] = ' ';
362 }
363
364 /* check for the beginning of a namelist (an unquoted &) */
365 ptr = buffer;
366 while (*ptr) {
367 if (*ptr == '"') {
368 /* skip quoted section */
369 ptr++;
370 while (*ptr != '"' && *ptr)
371 ptr++;
372 if (*ptr)
373 ptr++;
374 continue;
375 }
376 if (*ptr == '&') {
377 if (strncmp(ptr, "&end", 4) == 0)
378 return 0;
379 break;
380 }
381 ptr++;
382 }
383 if (!*ptr)
384 return 0;
385
386 /* remove the trailing &end if there is one */
387 if ((n = strlen(buffer)) >= 4) {
388 ptr = buffer + n - 4;
389 while (1) {
390 if (*ptr == '&' && (ptr == buffer || *(ptr - 1) != '\\') && strncmp(ptr, "&end", 4) == 0 && !SDDS_IsQuoted(buffer, ptr, '"')) {
391 *ptr = 0;
392 return 1;
393 }
394 if (ptr == buffer)
395 break;
396 ptr--;
397 }
398 }
399
400 /* read in the remainder of the namelist */
401 buffer0 = buffer;
402 buflen -= strlen(buffer);
403 buffer += strlen(buffer);
404 while ((flag = fgetsLZMASkipComments(SDDS_dataset, buffer, buflen, lzmafp, '!'))) {
405 n = strlen(buffer) - 1;
406 if (buffer[n] == '\n') {
407 buffer[n] = ' ';
408 if ((n - 1 >= 0) && (buffer[n - 1] == '\r'))
409 buffer[n - 1] = ' ';
410 }
411 if ((ptr = strstr(buffer, "&end")) && !SDDS_IsQuoted(buffer0, ptr, '"'))
412 return 1;
413 buflen -= strlen(buffer);
414 buffer += strlen(buffer);
415 if (buflen == 0)
416 return 0;
417 }
418 return 0;
419}
420
421#if defined(zLib)
422/**
423 * @brief Reads a namelist from a GZip-compressed file into a buffer.
424 *
425 * This function reads a namelist from a GZip-compressed file stream into the provided buffer,
426 * handling comments and skipping them appropriately.
427 *
428 * @param SDDS_dataset The SDDS dataset structure.
429 * @param buffer The buffer where the namelist will be stored.
430 * @param buflen The length of the buffer.
431 * @param gzfp The GZip file stream to read from.
432 * @return Returns 1 if a namelist is successfully read, 0 otherwise.
433 */
434int32_t SDDS_GetGZipNamelist(SDDS_DATASET *SDDS_dataset, char *buffer, int32_t buflen, gzFile gzfp) {
435 char *ptr, *flag, *buffer0;
436 /* char *ptr1 */
437 int32_t n;
438 /* int32_t namelistStarted; */
439
440 while ((flag = fgetsGZipSkipComments(SDDS_dataset, buffer, buflen, gzfp, '!'))) {
441 if ((ptr = strchr(buffer, '&')) && !SDDS_IsQuoted(buffer, ptr, '"'))
442 break;
443 }
444 if (!flag)
445 return 0;
446 n = strlen(buffer) - 1;
447 if (buffer[n] == '\n') {
448 buffer[n] = ' ';
449 if ((n - 1 >= 0) && (buffer[n - 1] == '\r'))
450 buffer[n - 1] = ' ';
451 }
452
453 /* check for the beginning of a namelist (an unquoted &) */
454 ptr = buffer;
455 while (*ptr) {
456 if (*ptr == '"') {
457 /* skip quoted section */
458 ptr++;
459 while (*ptr != '"' && *ptr)
460 ptr++;
461 if (*ptr)
462 ptr++;
463 continue;
464 }
465 if (*ptr == '&') {
466 if (strncmp(ptr, "&end", 4) == 0)
467 return 0;
468 break;
469 }
470 ptr++;
471 }
472 if (!*ptr)
473 return 0;
474
475 /* remove the trailing &end if there is one */
476 if ((n = strlen(buffer)) >= 4) {
477 ptr = buffer + n - 4;
478 while (1) {
479 if (*ptr == '&' && (ptr == buffer || *(ptr - 1) != '\\') && strncmp(ptr, "&end", 4) == 0 && !SDDS_IsQuoted(buffer, ptr, '"')) {
480 *ptr = 0;
481 return 1;
482 }
483 if (ptr == buffer)
484 break;
485 ptr--;
486 }
487 }
488
489 /* read in the remainder of the namelist */
490 buffer0 = buffer;
491 buflen -= strlen(buffer);
492 buffer += strlen(buffer);
493 while ((flag = fgetsGZipSkipComments(SDDS_dataset, buffer, buflen, gzfp, '!'))) {
494 n = strlen(buffer) - 1;
495 if (buffer[n] == '\n') {
496 buffer[n] = ' ';
497 if ((n - 1 >= 0) && (buffer[n - 1] == '\r'))
498 buffer[n - 1] = ' ';
499 }
500 if ((ptr = strstr(buffer, "&end")) && !SDDS_IsQuoted(buffer0, ptr, '"'))
501 return 1;
502 buflen -= strlen(buffer);
503 buffer += strlen(buffer);
504 if (buflen == 0)
505 return 0;
506 }
507 return 0;
508}
509#endif
510
511/**
512 * Reads the header layout of an SDDS dataset from a file.
513 *
514 * @param SDDS_dataset The SDDS dataset structure to store the layout information.
515 * @param fp The file pointer to the SDDS file.
516 * @return Returns 1 on success, 0 on failure.
517 */
518int32_t SDDS_ReadLayout(SDDS_DATASET *SDDS_dataset, FILE *fp) {
519 char buffer[SDDS_MAXLINE];
520 char *groupName, *ptr;
521 FILE *fp1;
522 int32_t retval, bigEndianMachine;
523 uint32_t commentFlags;
524
525 if (!fp) {
526 SDDS_SetError("Unable to read layout--NULL file pointer (SDDS_ReadLayout)");
527 return (0);
528 }
529 if (SDDS_dataset->layout.depth == 0) {
530 if (SDDS_dataset->layout.disconnected) {
531 SDDS_SetError("Can't read layout--file is disconnected (SDDS_ReadLayout)");
532 return 0;
533 }
534 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_ReadLayout")) {
535 fclose(fp);
536 return (0);
537 }
538 SDDS_dataset->layout.layout_written = 1; /* it is already in the file */
539 if (!fgets(SDDS_dataset->layout.s, SDDS_MAXLINE, fp)) {
540 fclose(fp);
541 SDDS_SetError("Unable to read layout--no header lines found (SDDS_ReadLayout)");
542 return (0);
543 }
544 if (strncmp(SDDS_dataset->layout.s, "SDDS", 4) != 0) {
545 fclose(fp);
546 SDDS_SetError("Unable to read layout--no header lines found (SDDS_ReadLayout)");
547 return (0);
548 }
549 if (sscanf(SDDS_dataset->layout.s + 4, "%" SCNd32, &SDDS_dataset->layout.version) != 1) {
550 fclose(fp);
551 SDDS_SetError("Unable to read layout--no version number on first line (SDDS_ReadLayout)");
552 return (0);
553 }
554 SDDS_ResetSpecialCommentsModes(SDDS_dataset);
555 SDDS_dataset->layout.data_command_seen = 0;
556 }
557 while (SDDS_GetNamelist(SDDS_dataset, SDDS_dataset->layout.s, SDDS_MAXLINE, fp)) {
558#if DEBUG
559 strcpy(buffer, SDDS_dataset->layout.s);
560#endif
561 groupName = SDDS_dataset->layout.s + 1;
562 if (!(ptr = strpbrk(SDDS_dataset->layout.s, " \t"))) {
563 SDDS_SetError("Unable to read layout---no groupname in namelist (SDDS_ReadLayout)");
564 return 0;
565 }
566 *ptr = 0;
567 switch (match_string(groupName, SDDS_command, SDDS_NUM_COMMANDS, EXACT_MATCH)) {
568 case SDDS_DESCRIPTION_COMMAND:
569 if (!SDDS_ProcessDescription(SDDS_dataset, ptr + 1)) {
570 fclose(fp);
571 SDDS_SetError("Unable to process description (SDDS_ReadLayout)");
572 return (0);
573 }
574 break;
575 case SDDS_COLUMN_COMMAND:
576 if (!SDDS_ProcessColumnDefinition(SDDS_dataset, ptr + 1)) {
577 fclose(fp);
578 SDDS_SetError("Unable to process column definition (SDDS_ReadLayout)");
579 return (0);
580 }
581 break;
582 case SDDS_PARAMETER_COMMAND:
583 if (!SDDS_ProcessParameterDefinition(SDDS_dataset, ptr + 1)) {
584 fclose(fp);
585 SDDS_SetError("Unable to process parameter definition (SDDS_ReadLayout)");
586 return (0);
587 }
588 break;
589 case SDDS_ASSOCIATE_COMMAND:
590#if RW_ASSOCIATES != 0
591 if (!SDDS_ProcessAssociateDefinition(SDDS_dataset, ptr + 1)) {
592 fclose(fp);
593 SDDS_SetError("Unable to process associate definition (SDDS_ReadLayout)");
594 return (0);
595 }
596#endif
597 break;
598 case SDDS_DATA_COMMAND:
599 if (!SDDS_ProcessDataMode(SDDS_dataset, ptr + 1)) {
600 fclose(fp);
601 SDDS_SetError("Unable to process data mode (SDDS_ReadLayout)");
602 return (0);
603 }
604 if (SDDS_dataset->layout.data_command_seen) {
605 /* should never happen */
606 fclose(fp);
607 SDDS_SetError("Unable to read layout--multiple data commands (SDDS_ReadLayout)");
608 return (0);
609 }
610 if (!SDDS_SaveLayout(SDDS_dataset)) {
611 SDDS_SetError("Unable to read layout--couldn't save layout (SDDS_ReadLayout)");
612 return (0);
613 }
614 SDDS_dataset->layout.data_command_seen = 1;
615 commentFlags = SDDS_GetSpecialCommentsModes(SDDS_dataset);
616 if ((commentFlags & SDDS_BIGENDIAN_SEEN) && (commentFlags & SDDS_LITTLEENDIAN_SEEN)) {
617 SDDS_SetError("Unable to read data as it says it is both big and little endian (SDDS_ReadLayout)");
618 return (0);
619 }
620 bigEndianMachine = SDDS_IsBigEndianMachine();
621 SDDS_dataset->swapByteOrder = SDDS_dataset->layout.byteOrderDeclared = 0;
622 SDDS_dataset->autoRecover = 0;
623 if ((commentFlags & SDDS_BIGENDIAN_SEEN) || (SDDS_dataset->layout.data_mode.endian == SDDS_BIGENDIAN)) {
624 SDDS_dataset->layout.byteOrderDeclared = SDDS_BIGENDIAN_SEEN;
625 if (!bigEndianMachine)
626 SDDS_dataset->swapByteOrder = 1;
627 }
628 if ((commentFlags & SDDS_LITTLEENDIAN_SEEN) || (SDDS_dataset->layout.data_mode.endian == SDDS_LITTLEENDIAN)) {
629 SDDS_dataset->layout.byteOrderDeclared = SDDS_LITTLEENDIAN_SEEN;
630 if (bigEndianMachine)
631 SDDS_dataset->swapByteOrder = 1;
632 }
633 if ((commentFlags & SDDS_FIXED_ROWCOUNT_SEEN) || (SDDS_dataset->layout.data_mode.fixed_row_count))
634 if (!SDDS_SetAutoReadRecovery(SDDS_dataset, SDDS_AUTOREADRECOVER))
635 return (0);
636 return (1);
637 case SDDS_INCLUDE_COMMAND:
638 if (!(fp1 = SDDS_ProcessIncludeCommand(SDDS_dataset, ptr + 1))) {
639 fclose(fp);
640 SDDS_SetError("Unable to process include command (SDDS_ReadLayout)");
641 return (0);
642 }
643 SDDS_dataset->layout.depth += 1;
644 retval = SDDS_ReadLayout(SDDS_dataset, fp1);
645 SDDS_dataset->layout.depth -= 1;
646 fclose(fp1);
647 if (retval == 0) {
648 return (0);
649 }
650 if (SDDS_dataset->layout.data_command_seen) {
651 return (1);
652 }
653 break;
654 case SDDS_ARRAY_COMMAND:
655 if (!SDDS_ProcessArrayDefinition(SDDS_dataset, ptr + 1)) {
656 fclose(fp);
657 SDDS_SetError("Unable to process array definition (SDDS_ReadLayout)");
658 return (0);
659 }
660 break;
661 default:
662 fclose(fp);
663 sprintf(buffer, "Unknown layout entry %s given (SDDS_ReadLayout)", groupName);
664 SDDS_SetError(buffer);
665 return (0);
666 }
667 }
668 /* on recursive calls, it's okay to hit EOF */
669 if ((feof(fp) && SDDS_dataset->layout.depth != 0) || SDDS_dataset->layout.data_command_seen)
670 return (1);
671 return (0);
672}
673
674/**
675 * Reads the header layout of an SDDS dataset from a file with LZMA compression.
676 *
677 * @param SDDS_dataset The SDDS dataset structure to store the layout information.
678 * @param lzmafp The LZMA file pointer to the SDDS file.
679 * @return Returns 1 on success, 0 on failure.
680 */
681int32_t SDDS_LZMAReadLayout(SDDS_DATASET *SDDS_dataset, struct lzmafile *lzmafp) {
682 char buffer[SDDS_MAXLINE];
683 char *groupName, *ptr;
684 FILE *fp1;
685 int32_t retval, bigEndianMachine;
686 uint32_t commentFlags;
687
688 if (!lzmafp) {
689 SDDS_SetError("Unable to read layout--NULL file pointer (SDDS_LZMAReadLayout)");
690 return (0);
691 }
692 if (SDDS_dataset->layout.depth == 0) {
693 if (SDDS_dataset->layout.disconnected) {
694 SDDS_SetError("Can't read layout--file is disconnected (SDDS_LZMAReadLayout)");
695 return 0;
696 }
697 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_LZMAReadLayout")) {
698 lzma_close(lzmafp);
699 return (0);
700 }
701 SDDS_dataset->layout.layout_written = 1; /* it is already in the file */
702 if (!lzma_gets(SDDS_dataset->layout.s, SDDS_MAXLINE, lzmafp)) {
703 lzma_close(lzmafp);
704 SDDS_SetError("Unable to read layout--no header lines found (SDDS_LZMAReadLayout)");
705 return (0);
706 }
707 if (strncmp(SDDS_dataset->layout.s, "SDDS", 4) != 0) {
708 lzma_close(lzmafp);
709 SDDS_SetError("Unable to read layout--no header lines found (SDDS_LZMAReadLayout)");
710 return (0);
711 }
712 if (sscanf(SDDS_dataset->layout.s + 4, "%" SCNd32, &SDDS_dataset->layout.version) != 1) {
713 lzma_close(lzmafp);
714 SDDS_SetError("Unable to read layout--no version number on first line (SDDS_LZMAReadLayout)");
715 return (0);
716 }
717 SDDS_ResetSpecialCommentsModes(SDDS_dataset);
718 SDDS_dataset->layout.data_command_seen = 0;
719 }
720 while (SDDS_GetLZMANamelist(SDDS_dataset, SDDS_dataset->layout.s, SDDS_MAXLINE, lzmafp)) {
721#if DEBUG
722 strcpy(buffer, SDDS_dataset->layout.s);
723#endif
724 groupName = SDDS_dataset->layout.s + 1;
725 if (!(ptr = strpbrk(SDDS_dataset->layout.s, " \t"))) {
726 SDDS_SetError("Unable to read layout---no groupname in namelist (SDDS_LZMAReadLayout)");
727 return 0;
728 }
729 *ptr = 0;
730 switch (match_string(groupName, SDDS_command, SDDS_NUM_COMMANDS, EXACT_MATCH)) {
731 case SDDS_DESCRIPTION_COMMAND:
732 if (!SDDS_ProcessDescription(SDDS_dataset, ptr + 1)) {
733 lzma_close(lzmafp);
734 SDDS_SetError("Unable to process description (SDDS_LZMAReadLayout)");
735 return (0);
736 }
737 break;
738 case SDDS_COLUMN_COMMAND:
739 if (!SDDS_ProcessColumnDefinition(SDDS_dataset, ptr + 1)) {
740 lzma_close(lzmafp);
741 SDDS_SetError("Unable to process column definition (SDDS_LZMAReadLayout)");
742 return (0);
743 }
744 break;
745 case SDDS_PARAMETER_COMMAND:
746 if (!SDDS_ProcessParameterDefinition(SDDS_dataset, ptr + 1)) {
747 lzma_close(lzmafp);
748 SDDS_SetError("Unable to process parameter definition (SDDS_LZMAReadLayout)");
749 return (0);
750 }
751 break;
752 case SDDS_ASSOCIATE_COMMAND:
753#if RW_ASSOCIATES != 0
754 if (!SDDS_ProcessAssociateDefinition(SDDS_dataset, ptr + 1)) {
755 lzma_close(lzmafp);
756 SDDS_SetError("Unable to process associate definition (SDDS_LZMAReadLayout)");
757 return (0);
758 }
759#endif
760 break;
761 case SDDS_DATA_COMMAND:
762 if (!SDDS_ProcessDataMode(SDDS_dataset, ptr + 1)) {
763 lzma_close(lzmafp);
764 SDDS_SetError("Unable to process data mode (SDDS_LZMAReadLayout)");
765 return (0);
766 }
767 if (SDDS_dataset->layout.data_command_seen) {
768 /* should never happen */
769 lzma_close(lzmafp);
770 SDDS_SetError("Unable to read layout--multiple data commands (SDDS_LZMAReadLayout)");
771 return (0);
772 }
773 if (!SDDS_SaveLayout(SDDS_dataset)) {
774 SDDS_SetError("Unable to read layout--couldn't save layout (SDDS_LZMAReadLayout)");
775 return (0);
776 }
777 SDDS_dataset->layout.data_command_seen = 1;
778 commentFlags = SDDS_GetSpecialCommentsModes(SDDS_dataset);
779 if ((commentFlags & SDDS_BIGENDIAN_SEEN) && (commentFlags & SDDS_LITTLEENDIAN_SEEN)) {
780 SDDS_SetError("Unable to read data as it says it is both big and little endian (SDDS_LZMAReadLayout)");
781 return (0);
782 }
783 bigEndianMachine = SDDS_IsBigEndianMachine();
784 SDDS_dataset->swapByteOrder = SDDS_dataset->layout.byteOrderDeclared = 0;
785 SDDS_dataset->autoRecover = 0;
786 if ((commentFlags & SDDS_BIGENDIAN_SEEN) || (SDDS_dataset->layout.data_mode.endian == SDDS_BIGENDIAN)) {
787 SDDS_dataset->layout.byteOrderDeclared = SDDS_BIGENDIAN_SEEN;
788 if (!bigEndianMachine)
789 SDDS_dataset->swapByteOrder = 1;
790 }
791 if ((commentFlags & SDDS_LITTLEENDIAN_SEEN) || (SDDS_dataset->layout.data_mode.endian == SDDS_LITTLEENDIAN)) {
792 SDDS_dataset->layout.byteOrderDeclared = SDDS_LITTLEENDIAN_SEEN;
793 if (bigEndianMachine)
794 SDDS_dataset->swapByteOrder = 1;
795 }
796 if ((commentFlags & SDDS_FIXED_ROWCOUNT_SEEN) || (SDDS_dataset->layout.data_mode.fixed_row_count))
797 if (!SDDS_SetAutoReadRecovery(SDDS_dataset, SDDS_AUTOREADRECOVER))
798 return (0);
799 return (1);
800 case SDDS_INCLUDE_COMMAND:
801 if (!(fp1 = SDDS_ProcessIncludeCommand(SDDS_dataset, ptr + 1))) {
802 lzma_close(lzmafp);
803 SDDS_SetError("Unable to process include command (SDDS_LZMAReadLayout)");
804 return (0);
805 }
806 SDDS_dataset->layout.depth += 1;
807 retval = SDDS_ReadLayout(SDDS_dataset, fp1);
808 SDDS_dataset->layout.depth -= 1;
809 fclose(fp1);
810 if (retval == 0) {
811 return (0);
812 }
813 if (SDDS_dataset->layout.data_command_seen) {
814 return (1);
815 }
816 break;
817 case SDDS_ARRAY_COMMAND:
818 if (!SDDS_ProcessArrayDefinition(SDDS_dataset, ptr + 1)) {
819 lzma_close(lzmafp);
820 SDDS_SetError("Unable to process array definition (SDDS_LZMAReadLayout)");
821 return (0);
822 }
823 break;
824 default:
825 lzma_close(lzmafp);
826 sprintf(buffer, "Unknown layout entry %s given (SDDS_LZMAReadLayout)", groupName);
827 SDDS_SetError(buffer);
828 return (0);
829 }
830 }
831 /* on recursive calls, it's okay to hit EOF */
832 if ((lzma_eof(lzmafp) && SDDS_dataset->layout.depth != 0) || SDDS_dataset->layout.data_command_seen)
833 return (1);
834 return (0);
835}
836
837#if defined(zLib)
838/**
839 * Reads the header layout of an SDDS dataset from a file with GZIP compression.
840 *
841 * @param SDDS_dataset The SDDS dataset structure to store the layout information.
842 * @param gzfp The GZIP file pointer to the SDDS file.
843 * @return Returns 1 on success, 0 on failure.
844 */
845int32_t SDDS_GZipReadLayout(SDDS_DATASET *SDDS_dataset, gzFile gzfp) {
846 char buffer[SDDS_MAXLINE];
847 char *groupName, *ptr;
848 FILE *fp1;
849 int32_t retval, bigEndianMachine;
850 uint32_t commentFlags;
851
852 if (!gzfp) {
853 SDDS_SetError("Unable to read layout--NULL file pointer (SDDS_GZipReadLayout)");
854 return (0);
855 }
856 if (SDDS_dataset->layout.disconnected) {
857 SDDS_SetError("Can't read layout--file is disconnected (SDDS_GZipReadLayout)");
858 return 0;
859 }
860 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_GZipReadLayout")) {
861 gzclose(gzfp);
862 return (0);
863 }
864 SDDS_dataset->layout.layout_written = 1; /* it is already in the file */
865 if (!gzgets(gzfp, SDDS_dataset->layout.s, SDDS_MAXLINE)) {
866 gzclose(gzfp);
867 SDDS_SetError("Unable to read layout--no header lines found (SDDS_GZipReadLayout)");
868 return (0);
869 }
870 if (strncmp(SDDS_dataset->layout.s, "SDDS", 4) != 0) {
871 gzclose(gzfp);
872 SDDS_SetError("Unable to read layout--no header lines found (SDDS_GZipReadLayout)");
873 return (0);
874 }
875 if (sscanf(SDDS_dataset->layout.s + 4, "%" SCNd32, &SDDS_dataset->layout.version) != 1) {
876 gzclose(gzfp);
877 SDDS_SetError("Unable to read layout--no version number on first line (SDDS_GZipReadLayout)");
878 return (0);
879 }
880 SDDS_ResetSpecialCommentsModes(SDDS_dataset);
881 if (SDDS_dataset->layout.depth == 0)
882 SDDS_dataset->layout.data_command_seen = 0;
883 while (SDDS_GetGZipNamelist(SDDS_dataset, SDDS_dataset->layout.s, SDDS_MAXLINE, gzfp)) {
884# if DEBUG
885 strcpy(buffer, SDDS_dataset->layout.s);
886# endif
887 groupName = SDDS_dataset->layout.s + 1;
888 if (!(ptr = strpbrk(SDDS_dataset->layout.s, " \t"))) {
889 SDDS_SetError("Unable to read layout---no groupname in namelist (SDDS_GZipReadLayout)");
890 return 0;
891 }
892 *ptr = 0;
893 switch (match_string(groupName, SDDS_command, SDDS_NUM_COMMANDS, EXACT_MATCH)) {
894 case SDDS_DESCRIPTION_COMMAND:
895 if (!SDDS_ProcessDescription(SDDS_dataset, ptr + 1)) {
896 gzclose(gzfp);
897 SDDS_SetError("Unable to process description (SDDS_GZipReadLayout)");
898 return (0);
899 }
900 break;
901 case SDDS_COLUMN_COMMAND:
902 if (!SDDS_ProcessColumnDefinition(SDDS_dataset, ptr + 1)) {
903 gzclose(gzfp);
904 SDDS_SetError("Unable to process column definition (SDDS_GZipReadLayout)");
905 return (0);
906 }
907 break;
908 case SDDS_PARAMETER_COMMAND:
909 if (!SDDS_ProcessParameterDefinition(SDDS_dataset, ptr + 1)) {
910 gzclose(gzfp);
911 SDDS_SetError("Unable to process parameter definition (SDDS_GZipReadLayout)");
912 return (0);
913 }
914 break;
915 case SDDS_ASSOCIATE_COMMAND:
916# if RW_ASSOCIATES != 0
917 if (!SDDS_ProcessAssociateDefinition(SDDS_dataset, ptr + 1)) {
918 gzclose(gzfp);
919 SDDS_SetError("Unable to process associate definition (SDDS_GZipReadLayout)");
920 return (0);
921 }
922# endif
923 break;
924 case SDDS_DATA_COMMAND:
925 if (!SDDS_ProcessDataMode(SDDS_dataset, ptr + 1)) {
926 gzclose(gzfp);
927 SDDS_SetError("Unable to process data mode (SDDS_GZipReadLayout)");
928 return (0);
929 }
930 if (SDDS_dataset->layout.data_command_seen) {
931 /* should never happen */
932 gzclose(gzfp);
933 SDDS_SetError("Unable to read layout--multiple data commands (SDDS_GZipReadLayout)");
934 return (0);
935 }
936 if (!SDDS_SaveLayout(SDDS_dataset)) {
937 SDDS_SetError("Unable to read layout--couldn't save layout (SDDS_GZipReadLayout)");
938 return (0);
939 }
940 SDDS_dataset->layout.data_command_seen = 1;
941 commentFlags = SDDS_GetSpecialCommentsModes(SDDS_dataset);
942 if ((commentFlags & SDDS_BIGENDIAN_SEEN) && (commentFlags & SDDS_LITTLEENDIAN_SEEN)) {
943 SDDS_SetError("Unable to read data as it says it is both big and little endian (SDDS_ReadLayout)");
944 return (0);
945 }
946 bigEndianMachine = SDDS_IsBigEndianMachine();
947 SDDS_dataset->swapByteOrder = SDDS_dataset->layout.byteOrderDeclared = 0;
948 SDDS_dataset->autoRecover = 0;
949 if ((commentFlags & SDDS_BIGENDIAN_SEEN) || (SDDS_dataset->layout.data_mode.endian == SDDS_BIGENDIAN)) {
950 SDDS_dataset->layout.byteOrderDeclared = SDDS_BIGENDIAN_SEEN;
951 if (!bigEndianMachine)
952 SDDS_dataset->swapByteOrder = 1;
953 }
954 if ((commentFlags & SDDS_LITTLEENDIAN_SEEN) || (SDDS_dataset->layout.data_mode.endian == SDDS_LITTLEENDIAN)) {
955 SDDS_dataset->layout.byteOrderDeclared = SDDS_LITTLEENDIAN_SEEN;
956 if (bigEndianMachine)
957 SDDS_dataset->swapByteOrder = 1;
958 }
959 if ((commentFlags & SDDS_FIXED_ROWCOUNT_SEEN) || (SDDS_dataset->layout.data_mode.fixed_row_count))
960 if (!SDDS_SetAutoReadRecovery(SDDS_dataset, SDDS_AUTOREADRECOVER))
961 return (0);
962 return (1);
963 case SDDS_INCLUDE_COMMAND:
964 if (!(fp1 = SDDS_ProcessIncludeCommand(SDDS_dataset, ptr + 1))) {
965 gzclose(gzfp);
966 SDDS_SetError("Unable to process include command (SDDS_GZipReadLayout)");
967 return (0);
968 }
969 SDDS_dataset->layout.depth += 1;
970 retval = SDDS_ReadLayout(SDDS_dataset, fp1);
971 SDDS_dataset->layout.depth -= 1;
972 fclose(fp1);
973 if (retval == 0) {
974 return (0);
975 }
976 if (SDDS_dataset->layout.data_command_seen) {
977 return (1);
978 }
979 break;
980 case SDDS_ARRAY_COMMAND:
981 if (!SDDS_ProcessArrayDefinition(SDDS_dataset, ptr + 1)) {
982 gzclose(gzfp);
983 SDDS_SetError("Unable to process array definition (SDDS_GZipReadLayout)");
984 return (0);
985 }
986 break;
987 default:
988 gzclose(gzfp);
989 sprintf(buffer, "Unknown layout entry %s given (SDDS_GZipReadLayout)", groupName);
990 SDDS_SetError(buffer);
991 return (0);
992 }
993 }
994 /* on recursive calls, it's okay to hit EOF */
995 if ((gzeof(gzfp) && SDDS_dataset->layout.depth != 0) || SDDS_dataset->layout.data_command_seen)
996 return (1);
997 return (0);
998}
999#endif
1000
1001/**
1002 * Reads a page of an SDDS file. Usually called after SDDS_InitializeInput.
1003 *
1004 * @param SDDS_dataset Address of the SDDS_DATASET structure for the data set.
1005 * @return Page number on success, -1 if it is the end-of-file, 0 on error.
1006 */
1007int32_t SDDS_ReadPage(SDDS_DATASET *SDDS_dataset) {
1008#if SDDS_MPI_IO
1009 if (SDDS_dataset->parallel_io)
1010 return SDDS_MPI_ReadPage(SDDS_dataset);
1011#endif
1012 return SDDS_ReadPageSparse(SDDS_dataset, 0, 1, 0, 0);
1013}
1014
1015/**
1016 * Checks if the end of the SDDS dataset file has been reached.
1017 *
1018 * @param SDDS_dataset The SDDS dataset structure.
1019 * @return Returns 1 if the end of file has been reached, 0 if not, and 2 on error.
1020 */
1021int32_t SDDS_CheckEndOfFile(SDDS_DATASET *SDDS_dataset) {
1022 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_EndOfFile"))
1023 return (0);
1024 if (SDDS_dataset->layout.disconnected) {
1025 SDDS_SetError("Can't check status--file is disconnected (SDDS_EndOfFile)");
1026 return 2;
1027 }
1028#if defined(zLib)
1029 if (SDDS_dataset->layout.gzipFile) {
1030 if (!SDDS_dataset->layout.gzfp) {
1031 SDDS_SetError("Unable to check status--NULL file pointer (SDDS_EndOfFile)");
1032 return 2;
1033 }
1034 } else {
1035#endif
1036 if (SDDS_dataset->layout.lzmaFile) {
1037 if (!SDDS_dataset->layout.lzmafp) {
1038 SDDS_SetError("Unable to check status--NULL file pointer (SDDS_EndOfFile)");
1039 return 2;
1040 }
1041 } else {
1042 if (!SDDS_dataset->layout.fp) {
1043 SDDS_SetError("Unable to check status--NULL file pointer (SDDS_EndOfFile)");
1044 return 2;
1045 }
1046 }
1047#if defined(zLib)
1048 }
1049#endif
1050 if (SDDS_dataset->fBuffer.bufferSize && SDDS_dataset->fBuffer.bytesLeft) {
1051 return 0;
1052 }
1053
1054#if defined(zLib)
1055 if (SDDS_dataset->layout.gzipFile) {
1056 if (gzeof(SDDS_dataset->layout.gzfp))
1057 return 1;
1058 } else {
1059#endif
1060 if (SDDS_dataset->layout.lzmaFile) {
1061 if (lzma_eof(SDDS_dataset->layout.lzmafp))
1062 return 1;
1063 } else {
1064 if (feof(SDDS_dataset->layout.fp))
1065 return 1;
1066 }
1067#if defined(zLib)
1068 }
1069#endif
1070 return 0;
1071}
1072
1073/**
1074 * Reads a sparsed page of an SDDS file. Usually called after SDDS_InitializeInput.
1075 *
1076 * @param SDDS_dataset A pointer to an SDDS dataset.
1077 * @param mode Not used.
1078 * @param sparse_interval The column data can be sparsified over row intervals if this is greater than 1.
1079 * @param sparse_offset This is used to skip the initial rows of the column data.
1080 * @param sparse_statistics Not used.
1081 * @return Page number on success, -1 if it is the end-of-file, 0 on error.
1082 */
1083int32_t SDDS_ReadPageSparse(SDDS_DATASET *SDDS_dataset, uint32_t mode, int64_t sparse_interval, int64_t sparse_offset, int32_t sparse_statistics)
1084/* the mode argument is to support future expansion */
1085{
1086 int32_t retval;
1087 /* SDDS_LAYOUT layout_copy; */
1088
1089 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_ReadPageSparse"))
1090 return (0);
1091 if (SDDS_dataset->layout.disconnected) {
1092 SDDS_SetError("Can't read page--file is disconnected (SDDS_ReadPageSparse)");
1093 return 0;
1094 }
1095#if defined(zLib)
1096 if (SDDS_dataset->layout.gzipFile) {
1097 if (!SDDS_dataset->layout.gzfp) {
1098 SDDS_SetError("Unable to read page--NULL file pointer (SDDS_ReadPageSparse)");
1099 return (0);
1100 }
1101 } else {
1102#endif
1103 if (SDDS_dataset->layout.lzmaFile) {
1104 if (!SDDS_dataset->layout.lzmafp) {
1105 SDDS_SetError("Unable to read page--NULL file pointer (SDDS_ReadPageSparse)");
1106 return (0);
1107 }
1108 } else {
1109 if (!SDDS_dataset->layout.fp) {
1110 SDDS_SetError("Unable to read page--NULL file pointer (SDDS_ReadPageSparse)");
1111 return (0);
1112 }
1113 }
1114#if defined(zLib)
1115 }
1116#endif
1117 if (SDDS_dataset->original_layout.data_mode.mode == SDDS_ASCII) {
1118 if ((retval = SDDS_ReadAsciiPage(SDDS_dataset, sparse_interval, sparse_offset, sparse_statistics)) < 1) {
1119 return (retval);
1120 }
1121 } else if (SDDS_dataset->original_layout.data_mode.mode == SDDS_BINARY) {
1122 if ((retval = SDDS_ReadBinaryPage(SDDS_dataset, sparse_interval, sparse_offset, sparse_statistics)) < 1) {
1123 return (retval);
1124 }
1125 } else {
1126 SDDS_SetError("Unable to read page--unrecognized data mode (SDDS_ReadPageSparse)");
1127 return (0);
1128 }
1129 if (!SDDS_dataset->layout.gzipFile && !SDDS_dataset->layout.lzmaFile && !SDDS_dataset->layout.popenUsed && SDDS_dataset->layout.filename && SDDS_dataset->pagecount_offset) {
1130 /* Data is not:
1131 1. from a gzip file
1132 2. from a file that is being internally decompressed by a command executed with popen()
1133 3. from a pipe set up externally (e.g., -pipe=in on commandline)
1134 and pagecount_offset has been allocate memory from SDDS_initializeInput()
1135 */
1136 if (SDDS_dataset->pagecount_offset[SDDS_dataset->pages_read] < SDDS_dataset->endOfFile_offset) {
1137 SDDS_dataset->pages_read++;
1138 if (!(SDDS_dataset->pagecount_offset = realloc(SDDS_dataset->pagecount_offset, sizeof(int64_t) * (SDDS_dataset->pages_read + 1)))) {
1139 SDDS_SetError("Unable to allocate memory for pagecount_offset (SDDS_ReadPageSparse)");
1140 exit(1);
1141 }
1142 SDDS_dataset->pagecount_offset[SDDS_dataset->pages_read] = ftell(SDDS_dataset->layout.fp);
1143 }
1144 } else {
1145 SDDS_dataset->pages_read++;
1146 }
1147 return (retval);
1148}
1149
1150/**
1151 * Reads the last specified number of rows from the SDDS dataset.
1152 *
1153 * @param SDDS_dataset The pointer to the SDDS dataset structure.
1154 * @param last_rows The number of rows to read from the end of the dataset.
1155 * @return Page number on success, -1 if it is the end-of-file, 0 on error.
1156 */
1157int32_t SDDS_ReadPageLastRows(SDDS_DATASET *SDDS_dataset, int64_t last_rows) {
1158 int32_t retval;
1159
1160 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_ReadPageLastRows"))
1161 return (0);
1162 if (SDDS_dataset->layout.disconnected) {
1163 SDDS_SetError("Can't read page--file is disconnected (SDDS_ReadPageLastRows)");
1164 return 0;
1165 }
1166#if defined(zLib)
1167 if (SDDS_dataset->layout.gzipFile) {
1168 if (!SDDS_dataset->layout.gzfp) {
1169 SDDS_SetError("Unable to read page--NULL file pointer (SDDS_ReadPageLastRows)");
1170 return (0);
1171 }
1172 } else {
1173#endif
1174 if (SDDS_dataset->layout.lzmaFile) {
1175 if (!SDDS_dataset->layout.lzmafp) {
1176 SDDS_SetError("Unable to read page--NULL file pointer (SDDS_ReadPageLastRows)");
1177 return (0);
1178 }
1179 } else {
1180 if (!SDDS_dataset->layout.fp) {
1181 SDDS_SetError("Unable to read page--NULL file pointer (SDDS_ReadPageLastRows)");
1182 return (0);
1183 }
1184 }
1185#if defined(zLib)
1186 }
1187#endif
1188 if (SDDS_dataset->original_layout.data_mode.mode == SDDS_ASCII) {
1189 if ((retval = SDDS_ReadAsciiPageLastRows(SDDS_dataset, last_rows)) < 1) {
1190 return (retval);
1191 }
1192 } else if (SDDS_dataset->original_layout.data_mode.mode == SDDS_BINARY) {
1193 if ((retval = SDDS_ReadBinaryPageLastRows(SDDS_dataset, last_rows)) < 1) {
1194 return (retval);
1195 }
1196 } else {
1197 SDDS_SetError("Unable to read page--unrecognized data mode (SDDS_ReadPageLastRows)");
1198 return (0);
1199 }
1200 if (!SDDS_dataset->layout.gzipFile && !SDDS_dataset->layout.lzmaFile && !SDDS_dataset->layout.popenUsed && SDDS_dataset->layout.filename && SDDS_dataset->pagecount_offset) {
1201 /* Data is not:
1202 1. from a gzip file
1203 2. from a file that is being internally decompressed by a command executed with popen()
1204 3. from a pipe set up externally (e.g., -pipe=in on commandline)
1205 and pagecount_offset has been allocate memory from SDDS_initializeInput()
1206 */
1207 if (SDDS_dataset->pagecount_offset[SDDS_dataset->pages_read] < SDDS_dataset->endOfFile_offset) {
1208 SDDS_dataset->pages_read++;
1209 if (!(SDDS_dataset->pagecount_offset = realloc(SDDS_dataset->pagecount_offset, sizeof(int64_t) * (SDDS_dataset->pages_read + 1)))) {
1210 SDDS_SetError("Unable to allocate memory for pagecount_offset (SDDS_ReadPageLastRows)");
1211 exit(1);
1212 }
1213 SDDS_dataset->pagecount_offset[SDDS_dataset->pages_read] = ftell(SDDS_dataset->layout.fp);
1214 }
1215 } else {
1216 SDDS_dataset->pages_read++;
1217 }
1218 return (retval);
1219}
1220
1221/**
1222 * @brief Global variable to set a limit on the number of rows read.
1223 *
1224 * The default value is `INT64_MAX`, indicating no limit.
1225 */
1226static MDB_THREAD_LOCK SDDS_RowLimitLock = MDB_THREAD_LOCK_INITIALIZER;
1227static int64_t SDDS_RowLimit = INT64_MAX;
1228
1229static int64_t SDDS_GetLockedRowLimit(void) {
1230 int64_t limit;
1231 mdb_thread_lock(&SDDS_RowLimitLock);
1232 limit = SDDS_RowLimit;
1233 mdb_thread_unlock(&SDDS_RowLimitLock);
1234 return limit;
1235}
1236
1237/**
1238 * Sets the row limit for the SDDS dataset.
1239 *
1240 * @param limit The maximum number of rows to read. If `limit <= 0`, the row limit is set to `INT64_MAX`.
1241 * @return The previous row limit value.
1242 */
1243int64_t SDDS_SetRowLimit(int64_t limit) {
1244 int64_t previous;
1245 if (limit <= 0)
1246 limit = INT64_MAX;
1247 mdb_thread_lock(&SDDS_RowLimitLock);
1248 previous = SDDS_RowLimit;
1249 SDDS_RowLimit = limit;
1250 mdb_thread_unlock(&SDDS_RowLimitLock);
1251 return previous;
1252}
1253
1254/**
1255 * Retrieves the current row limit for the SDDS dataset.
1256 *
1257 * @return The current row limit.
1258 */
1260 return SDDS_GetLockedRowLimit();
1261}
1262
1263/**
1264 * @brief Sets the current page of the SDDS dataset to the specified page number.
1265 *
1266 * This function is used to navigate to a specific page of the SDDS dataset. It is only
1267 * supported for non-zip files and does not work for pipe input.
1268 *
1269 * @param SDDS_dataset The SDDS dataset to operate on.
1270 * @param page_number The page number to navigate to.
1271 * @return Returns 1 on success, 0 on failure.
1272 */
1273int32_t SDDS_GotoPage(SDDS_DATASET *SDDS_dataset, int32_t page_number) {
1274 int64_t offset;
1275
1276 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_GotoPage"))
1277 return (0);
1278 if (SDDS_dataset->layout.disconnected) {
1279 SDDS_SetError("Can't go to page--file is disconnected (SDDS_GotoPage)");
1280 return 0;
1281 }
1282 if (SDDS_dataset->layout.popenUsed || !SDDS_dataset->layout.filename) {
1283 SDDS_SetError("Can't go to page of pipe is used (SDDS_GotoPage)");
1284 return 0;
1285 }
1286#if defined(zLib)
1287 if (SDDS_dataset->layout.gzipFile) {
1288 SDDS_SetError("Can not go to page of a gzip file (SDDS_GotoPage)");
1289 return (0);
1290 } else {
1291#endif
1292 if (SDDS_dataset->layout.lzmaFile) {
1293 SDDS_SetError("Can not go to page of an .lzma or .xz file (SDDS_GotoPage)");
1294 return (0);
1295 } else {
1296 if (!SDDS_dataset->layout.fp) {
1297 SDDS_SetError("Unable to go to page--NULL file pointer (SDDS_GotoPage)");
1298 return (0);
1299 }
1300 }
1301#if defined(zLib)
1302 }
1303#endif
1304 if (!SDDS_dataset->layout.filename) {
1305 SDDS_SetError("Can't go to page--NULL filename pointer (SDDS_GotoPage)");
1306 return 0;
1307 }
1308 if (SDDS_dataset->mode != SDDS_READMODE) {
1309 SDDS_SetError("Can't go to page--file mode has to be reading mode (SDDS_GotoPage)");
1310 return 0;
1311 }
1312 if (SDDS_dataset->fBuffer.bufferSize) {
1313 SDDS_SetError("Can't go to page--file buffering is turned on (SDDS_GotoPage)");
1314 return 0;
1315 }
1316 if (page_number < 1) {
1317 SDDS_SetError("The page_number can not be less than 1 (SDDS_GotoPage)");
1318 return (0);
1319 }
1320 if (page_number > SDDS_dataset->pages_read) {
1321 offset = SDDS_dataset->pagecount_offset[SDDS_dataset->pages_read] - ftell(SDDS_dataset->layout.fp);
1322 fseek(SDDS_dataset->layout.fp, offset, 1);
1323 SDDS_dataset->page_number = SDDS_dataset->pages_read;
1324 while (SDDS_dataset->pages_read < page_number) {
1325 if (SDDS_ReadPageSparse(SDDS_dataset, 0, SDDS_dataset->layout.data_mode.column_major ? 1 : 10000, 0, 0) <= 0) {
1326 SDDS_SetError("The page_number is greater than the total pages (SDDS_GotoPage)");
1327 return (0);
1328 }
1329 }
1330 } else {
1331 offset = SDDS_dataset->pagecount_offset[page_number - 1] - ftell(SDDS_dataset->layout.fp);
1332 fseek(SDDS_dataset->layout.fp, offset, 1); /*seek to the position from current offset */
1333 SDDS_dataset->page_number = page_number - 1;
1334 }
1335 return 1;
1336}
1337
1338/**
1339 * @brief Global variable to set the terminate mode for the SDDS dataset.
1340 *
1341 * Default value is 0.
1342 */
1343static MDB_THREAD_LOCK terminateModeLock = MDB_THREAD_LOCK_INITIALIZER;
1344static int32_t terminateMode = 0;
1345
1346int32_t SDDS_GetTerminateMode(void) {
1347 int32_t mode;
1348 mdb_thread_lock(&terminateModeLock);
1349 mode = terminateMode;
1350 mdb_thread_unlock(&terminateModeLock);
1351 return mode;
1352}
1353
1354/**
1355 * Sets the terminate mode for the SDDS dataset.
1356 *
1357 * @param mode The terminate mode to set.
1358 */
1359void SDDS_SetTerminateMode(uint32_t mode) {
1360 mdb_thread_lock(&terminateModeLock);
1361 terminateMode = mode;
1362 mdb_thread_unlock(&terminateModeLock);
1363}
1364
1365/**
1366 * Sets the column memory mode for the SDDS dataset.
1367 *
1368 * @param SDDS_dataset The SDDS dataset to operate on.
1369 * @param mode The column memory mode to set.
1370 */
1371void SDDS_SetColumnMemoryMode(SDDS_DATASET *SDDS_dataset, uint32_t mode) {
1372 SDDS_dataset->layout.data_mode.column_memory_mode = mode;
1373}
1374
1375/**
1376 * Retrieves the current column memory mode for the SDDS dataset.
1377 *
1378 * @param SDDS_dataset The SDDS dataset to query.
1379 * @return The current column memory mode.
1380 */
1382 return (SDDS_dataset->layout.data_mode.column_memory_mode);
1383}
1384
1385#include <signal.h>
1386
1387/**
1388 * Frees all allocated string data in the SDDS dataset.
1389 *
1390 * This function frees any strings allocated for parameters, arrays, and columns
1391 * within the SDDS dataset. It is typically called during termination to clean up
1392 * allocated memory.
1393 *
1394 * @param SDDS_dataset The SDDS dataset to free string data from.
1395 * @return Returns 1 on success, 0 on failure.
1396 */
1397int32_t SDDS_FreeStringData(SDDS_DATASET *SDDS_dataset) {
1398 SDDS_LAYOUT *layout;
1399 char **ptr;
1400 int64_t i, j;
1401 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_Terminate"))
1402 return (0);
1403 layout = &SDDS_dataset->original_layout;
1404
1405 if (SDDS_dataset->parameter) {
1406 for (i = 0; i < layout->n_parameters; i++) {
1407 if (layout->parameter_definition[i].type == SDDS_STRING) {
1408 free(*(char **)(SDDS_dataset->parameter[i]));
1409 *(char **)(SDDS_dataset->parameter[i]) = NULL;
1410 }
1411 }
1412 }
1413 if (SDDS_dataset->array) {
1414 for (i = 0; i < layout->n_arrays; i++) {
1415 if (layout->array_definition[i].type == SDDS_STRING) {
1416 for (j = 0; j < SDDS_dataset->array[i].elements; j++)
1417 if (((char **)SDDS_dataset->array[i].data)[j]) {
1418 free(((char **)SDDS_dataset->array[i].data)[j]);
1419 ((char **)SDDS_dataset->array[i].data)[j] = NULL;
1420 }
1421 }
1422 }
1423 }
1424 if (SDDS_dataset->data) {
1425 for (i = 0; i < layout->n_columns; i++)
1426 if (SDDS_dataset->data[i]) {
1427 if (layout->column_definition[i].type == SDDS_STRING) {
1428 ptr = (char **)SDDS_dataset->data[i];
1429 for (j = 0; j < SDDS_dataset->n_rows_allocated; j++, ptr++)
1430 if (*ptr) {
1431 free(*ptr);
1432 *ptr = NULL;
1433 }
1434 }
1435 }
1436 }
1437 return (1);
1438}
1439
1440/**
1441 * Frees the strings in the current table of the SDDS dataset.
1442 *
1443 * This function frees any strings stored in the data columns of the current table.
1444 * It does not free strings from parameters or arrays.
1445 *
1446 * @param SDDS_dataset The SDDS dataset to free table strings from.
1447 */
1449 int64_t i, j;
1450 char **ptr;
1451 /* free stored strings */
1452 if (!SDDS_dataset)
1453 return;
1454 for (i = 0; i < SDDS_dataset->layout.n_columns; i++)
1455 if (SDDS_dataset->layout.column_definition[i].type == SDDS_STRING) {
1456 ptr = (char **)SDDS_dataset->data[i];
1457 for (j = 0; j < SDDS_dataset->n_rows; j++, ptr++)
1458 if (*ptr) {
1459 free(*ptr);
1460 *ptr = NULL;
1461 }
1462 }
1463}
1464
1465/**
1466 * Closes an SDDS file and frees the related memory.
1467 *
1468 * @param SDDS_dataset A pointer to an SDDS dataset.
1469 * @return 1 on success, 0 on error.
1470 */
1471int32_t SDDS_Terminate(SDDS_DATASET *SDDS_dataset) {
1472 SDDS_LAYOUT *layout;
1473 char **ptr;
1474 int64_t i, j;
1475 FILE *fp;
1476 char termBuffer[16384];
1477 int32_t terminateMode;
1478#if SDDS_MPI_IO
1479 if (SDDS_dataset->parallel_io)
1480 return SDDS_MPI_Terminate(SDDS_dataset);
1481#endif
1482 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_Terminate"))
1483 return (0);
1484 layout = &SDDS_dataset->original_layout;
1485 terminateMode = SDDS_GetTerminateMode();
1486
1487 fp = SDDS_dataset->layout.fp;
1488#if defined(zLib)
1489 if (SDDS_dataset->layout.gzipFile) {
1490 if (SDDS_dataset->layout.gzfp && layout->filename) {
1491 if ((SDDS_dataset->writing_page) && (SDDS_dataset->layout.data_mode.fixed_row_count)) {
1492 if (!SDDS_UpdateRowCount(SDDS_dataset))
1493 return (0);
1494 }
1495 gzclose(SDDS_dataset->layout.gzfp);
1496 }
1497 } else {
1498#endif
1499 if (SDDS_dataset->layout.lzmaFile) {
1500 if (SDDS_dataset->layout.lzmafp && layout->filename) {
1501 if ((SDDS_dataset->writing_page) && (SDDS_dataset->layout.data_mode.fixed_row_count)) {
1502 if (!SDDS_UpdateRowCount(SDDS_dataset))
1503 return (0);
1504 }
1505 lzma_close(SDDS_dataset->layout.lzmafp);
1506 }
1507 } else {
1508 if (fp && layout->filename) {
1509 if ((SDDS_dataset->writing_page) && (SDDS_dataset->layout.data_mode.fixed_row_count)) {
1510 if (!SDDS_UpdateRowCount(SDDS_dataset))
1511 return (0);
1512 }
1513 if (layout->popenUsed) {
1514 while (fread(termBuffer, sizeof(*termBuffer), 16384, fp)) {
1515 }
1516#if defined(vxWorks)
1517 fprintf(stderr, "pclose is not supported in vxWorks\n");
1518 exit(1);
1519#else
1520 pclose(fp);
1521#endif
1522 } else {
1523 fclose(fp);
1524 }
1525 }
1526 }
1527#if defined(zLib)
1528 }
1529#endif
1530
1531#if DEBUG
1532 fprintf(stderr, "Freeing data for file %s\n", SDDS_dataset->layout.filename ? SDDS_dataset->layout.filename : "NULL");
1533#endif
1534
1535 if (SDDS_dataset->pagecount_offset)
1536 free(SDDS_dataset->pagecount_offset);
1537 if (SDDS_dataset->row_flag)
1538 free(SDDS_dataset->row_flag);
1539 if (SDDS_dataset->column_order)
1540 free(SDDS_dataset->column_order);
1541 if (SDDS_dataset->column_flag)
1542 free(SDDS_dataset->column_flag);
1543 if (SDDS_dataset->fBuffer.buffer)
1544 free(SDDS_dataset->fBuffer.buffer);
1545#if DEBUG
1546 fprintf(stderr, "freeing parameter data...\n");
1547#endif
1548 if (SDDS_dataset->parameter) {
1549 for (i = 0; i < layout->n_parameters; i++) {
1550 if (layout->parameter_definition[i].type == SDDS_STRING && *(char **)(SDDS_dataset->parameter[i]))
1551 free(*(char **)(SDDS_dataset->parameter[i]));
1552 if (SDDS_dataset->parameter[i])
1553 free(SDDS_dataset->parameter[i]);
1554 }
1555 free(SDDS_dataset->parameter);
1556 }
1557#if DEBUG
1558 fprintf(stderr, "freeing array data...\n");
1559#endif
1560 if (SDDS_dataset->array) {
1561 for (i = 0; i < layout->n_arrays; i++) {
1562 if (layout->array_definition[i].type == SDDS_STRING && !(terminateMode & TERMINATE_DONT_FREE_ARRAY_STRINGS)) {
1563 for (j = 0; j < SDDS_dataset->array[i].elements; j++)
1564 if (((char **)SDDS_dataset->array[i].data)[j])
1565 free(((char **)SDDS_dataset->array[i].data)[j]);
1566 }
1567 /*
1568 if (SDDS_dataset->array[i].definition->type==SDDS_STRING &&
1569 !(SDDS_GetTerminateMode()&TERMINATE_DONT_FREE_ARRAY_STRINGS)) {
1570 for (j=0; j<SDDS_dataset->array[i].elements; j++)
1571 if (((char**)SDDS_dataset->array[i].data)[j])
1572 free(((char**)SDDS_dataset->array[i].data)[j]);
1573 }
1574 */
1575 if (SDDS_dataset->array[i].data)
1576 free(SDDS_dataset->array[i].data);
1577 /* should free the subpointers too, but it would be a lot of trouble for little benefit: */
1578 if (SDDS_dataset->array[i].pointer && SDDS_dataset->array[i].definition->dimensions != 1)
1579 free(SDDS_dataset->array[i].pointer);
1580 if (SDDS_dataset->array[i].dimension)
1581 free(SDDS_dataset->array[i].dimension);
1582 /* don't touch this--it's done below */
1583 if (SDDS_dataset->array[i].definition && SDDS_dataset->array[i].definition->name) {
1584 if (SDDS_dataset->array[i].definition->name != layout->array_definition[i].name)
1585 SDDS_FreeArrayDefinition(SDDS_dataset->array[i].definition);
1586 }
1587 SDDS_dataset->array[i].definition = NULL;
1588 }
1589 free(SDDS_dataset->array);
1590 }
1591#if DEBUG
1592 fprintf(stderr, "freeing tabular data...\n");
1593#endif
1594 if (SDDS_dataset->data) {
1595 for (i = 0; i < layout->n_columns; i++)
1596 if (SDDS_dataset->data[i]) {
1597 if ((SDDS_dataset->column_track_memory == NULL) || (SDDS_dataset->column_track_memory[i])) {
1598 if (layout->column_definition[i].type == SDDS_STRING && !(terminateMode & TERMINATE_DONT_FREE_TABLE_STRINGS)) {
1599 ptr = (char **)SDDS_dataset->data[i];
1600 for (j = 0; j < SDDS_dataset->n_rows_allocated; j++, ptr++)
1601 if (*ptr)
1602 free(*ptr);
1603 }
1604 free(SDDS_dataset->data[i]);
1605 }
1606 }
1607 free(SDDS_dataset->data);
1608 }
1609 if (SDDS_dataset->column_track_memory)
1610 free(SDDS_dataset->column_track_memory);
1611#if DEBUG
1612 fprintf(stderr, "freeing layout data...\n");
1613#endif
1614 if (layout->description)
1615 free(layout->description);
1616 if (layout->contents == (&SDDS_dataset->layout)->contents)
1617 (&SDDS_dataset->layout)->contents = NULL;
1618 if (layout->contents)
1619 free(layout->contents);
1620 if (layout->filename)
1621 free(layout->filename);
1622 if (layout->column_definition) {
1623 for (i = 0; i < layout->n_columns; i++) {
1624 if (layout->column_index[i])
1625 free(layout->column_index[i]);
1626 if (layout->column_definition[i].name)
1627 free(layout->column_definition[i].name);
1628 if (layout->column_definition[i].symbol)
1629 free(layout->column_definition[i].symbol);
1630 if (layout->column_definition[i].units)
1631 free(layout->column_definition[i].units);
1632 if (layout->column_definition[i].description)
1633 free(layout->column_definition[i].description);
1634 if (layout->column_definition[i].format_string)
1635 free(layout->column_definition[i].format_string);
1636 }
1637 free(layout->column_definition);
1638 free(layout->column_index);
1639 }
1640 if (layout->parameter_definition) {
1641 for (i = 0; i < layout->n_parameters; i++) {
1642 if (layout->parameter_index[i])
1643 free(layout->parameter_index[i]);
1644 if (layout->parameter_definition[i].name)
1645 free(layout->parameter_definition[i].name);
1646 if (layout->parameter_definition[i].symbol)
1647 free(layout->parameter_definition[i].symbol);
1648 if (layout->parameter_definition[i].units)
1649 free(layout->parameter_definition[i].units);
1650 if (layout->parameter_definition[i].description)
1651 free(layout->parameter_definition[i].description);
1652 if (layout->parameter_definition[i].format_string)
1653 free(layout->parameter_definition[i].format_string);
1654 if (layout->parameter_definition[i].fixed_value)
1655 free(layout->parameter_definition[i].fixed_value);
1656 }
1657 free(layout->parameter_definition);
1658 free(layout->parameter_index);
1659 }
1660 if (layout->array_definition) {
1661 for (i = 0; i < layout->n_arrays; i++) {
1662 if (layout->array_index[i])
1663 free(layout->array_index[i]);
1664 if (layout->array_definition[i].name)
1665 free(layout->array_definition[i].name);
1666 if (layout->array_definition[i].symbol)
1667 free(layout->array_definition[i].symbol);
1668 if (layout->array_definition[i].units)
1669 free(layout->array_definition[i].units);
1670 if (layout->array_definition[i].description)
1671 free(layout->array_definition[i].description);
1672 if (layout->array_definition[i].format_string)
1673 free(layout->array_definition[i].format_string);
1674 if (layout->array_definition[i].group_name)
1675 free(layout->array_definition[i].group_name);
1676 }
1677 free(layout->array_definition);
1678 free(layout->array_index);
1679 }
1680 if (layout->associate_definition) {
1681 for (i = 0; i < layout->n_associates; i++) {
1682 if (layout->associate_definition[i].name)
1683 free(layout->associate_definition[i].name);
1684 if (layout->associate_definition[i].filename)
1685 free(layout->associate_definition[i].filename);
1686 if (layout->associate_definition[i].path)
1687 free(layout->associate_definition[i].path);
1688 if (layout->associate_definition[i].description)
1689 free(layout->associate_definition[i].description);
1690 if (layout->associate_definition[i].contents)
1691 free(layout->associate_definition[i].contents);
1692 }
1693 free(layout->associate_definition);
1694 }
1695 SDDS_ZeroMemory(&SDDS_dataset->original_layout, sizeof(SDDS_LAYOUT));
1696 layout = &SDDS_dataset->layout;
1697 if (layout->contents)
1698 free(layout->contents);
1699 if (layout->column_definition)
1700 free(layout->column_definition);
1701 if (layout->array_definition)
1702 free(layout->array_definition);
1703 if (layout->associate_definition)
1704 free(layout->associate_definition);
1705 if (layout->parameter_definition)
1706 free(layout->parameter_definition);
1707 if (layout->column_index)
1708 free(layout->column_index);
1709 if (layout->parameter_index)
1710 free(layout->parameter_index);
1711 if (layout->array_index)
1712 free(layout->array_index);
1713 SDDS_ZeroMemory(&SDDS_dataset->layout, sizeof(SDDS_LAYOUT));
1714 SDDS_ZeroMemory(SDDS_dataset, sizeof(SDDS_DATASET));
1715#if DEBUG
1716 fprintf(stderr, "done\n");
1717#endif
1718 return (1);
1719}
1720
1721/**
1722 * Updates the row count in the SDDS file for fixed row count mode.
1723 *
1724 * @param SDDS_dataset The SDDS dataset to update.
1725 * @return 1 on success, 0 on error.
1726 */
1727int32_t SDDS_UpdateRowCount(SDDS_DATASET *SDDS_dataset) {
1728 FILE *fp;
1729 SDDS_FILEBUFFER *fBuffer;
1730 int64_t offset, rows;
1731 int32_t rows32;
1732 char *outputEndianess = NULL;
1733
1734 if ((SDDS_dataset->layout.gzipFile) || (SDDS_dataset->layout.lzmaFile))
1735 return (1);
1736 if (!(fp = SDDS_dataset->layout.fp)) {
1737 SDDS_SetError("Unable to update page--file pointer is NULL (SDDS_UpdateRowCount)");
1738 return (0);
1739 }
1740#if DEBUG
1741 fprintf(stderr, "Updating rowcount in file %s with pointer %p\n", SDDS_dataset->layout.filename ? SDDS_dataset->layout.filename : "NULL", fp);
1742#endif
1743 fBuffer = &SDDS_dataset->fBuffer;
1744 if (!SDDS_FlushBuffer(fp, fBuffer)) {
1745 SDDS_SetError("Unable to write page--buffer flushing problem (SDDS_UpdateRowCount)");
1746 return (0);
1747 }
1748 offset = ftell(fp);
1749 if (SDDS_fseek(fp, SDDS_dataset->rowcount_offset, 0) == -1) {
1750 SDDS_SetError("Unable to update page--failure doing fseek (SDDS_UpdateRowCount)");
1751 return (0);
1752 }
1753 rows = SDDS_CountRowsOfInterest(SDDS_dataset) + SDDS_dataset->first_row_in_mem;
1754 if (SDDS_dataset->layout.data_mode.mode == SDDS_ASCII) {
1755 fprintf(fp, "%20" PRId64 "\n", rows);
1756 } else {
1757
1758 if (rows > INT32_MAX) {
1759 // Don't go over this limit because it has a different format
1760 SDDS_SetError("Unable to update page--failure writing number of rows (SDDS_UpdateRowCount)");
1761 return (0);
1762 }
1763 rows32 = (int32_t)rows;
1764 if ((outputEndianess = getenv("SDDS_OUTPUT_ENDIANESS"))) {
1765 if (((strncmp(outputEndianess, "big", 3) == 0) && (SDDS_IsBigEndianMachine() == 0)) || ((strncmp(outputEndianess, "little", 6) == 0) && (SDDS_IsBigEndianMachine() == 1)))
1766 SDDS_SwapLong(&rows32);
1767 }
1768 if (fwrite(&rows32, sizeof(rows32), 1, fp) != 1) {
1769 SDDS_SetError("Unable to update page--failure writing number of rows (SDDS_UpdateRowCount)");
1770 return (0);
1771 }
1772 }
1773 if (SDDS_fseek(fp, offset, 0) == -1) {
1774 SDDS_SetError("Unable to update page--failure doing fseek to end of page (SDDS_UpdateRowCount)");
1775 return (0);
1776 }
1777 return (1);
1778}
1779
1780/**
1781 * Sets the auto-read recovery mode for the SDDS dataset.
1782 *
1783 * @param SDDS_dataset The SDDS dataset to modify.
1784 * @param mode The mode to set (SDDS_AUTOREADRECOVER or SDDS_NOAUTOREADRECOVER).
1785 * @return 1 on success, 0 on error.
1786 */
1787int32_t SDDS_SetAutoReadRecovery(SDDS_DATASET *SDDS_dataset, uint32_t mode) {
1788 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_SetAutoReadRecovery"))
1789 return 0;
1790 if (mode & SDDS_AUTOREADRECOVER) {
1791 SDDS_dataset->autoRecover = 1;
1792 } else if (mode & SDDS_NOAUTOREADRECOVER) {
1793 SDDS_dataset->autoRecover = 0;
1794 } else {
1795 SDDS_SetError("Invalid Auto Read Recovery mode (SDDS_SetAutoReadRecovery).");
1796 return 0;
1797 }
1798 return 1;
1799}
1800
1801/**
1802 * Initializes the SDDS_DATASET structure for input from the search path.
1803 *
1804 * The search path is defined by calling `setSearchPath`. This function attempts to find the file
1805 * in the search path and initializes the SDDS dataset for input.
1806 *
1807 * @param SDDSin The SDDS_DATASET structure to be initialized.
1808 * @param file The name of the file to be opened for input.
1809 * @return 1 on success, 0 on failure.
1810 */
1812 char *filename;
1813 int32_t value;
1814 if (!(filename = findFileInSearchPath(file))) {
1815 char *s;
1816 if (!(s = SDDS_Malloc(sizeof(*s) * (strlen(file) + 100))))
1817 SDDS_SetError("file does not exist in search path (InitializeInputFromSearchPath)");
1818 else {
1819 sprintf(s, "file %s does not exist in search path (InitializeInputFromSearchPath)", file);
1820 SDDS_SetError(s);
1821 free(s);
1822 }
1823 return 0;
1824 }
1825 value = SDDS_InitializeInput(SDDSin, filename);
1826 free(filename);
1827 return value;
1828}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t SDDS_ReadAsciiPageLastRows(SDDS_DATASET *SDDS_dataset, int64_t last_rows)
Reads the last specified number of rows from an ASCII page of an SDDS dataset.
int32_t SDDS_ReadAsciiPage(SDDS_DATASET *SDDS_dataset, int64_t sparse_interval, int64_t sparse_offset, int32_t sparse_statistics)
Reads the next SDDS ASCII page into memory with optional data sparsity and statistics.
int32_t SDDS_FlushBuffer(FILE *fp, SDDS_FILEBUFFER *fBuffer)
int32_t SDDS_ReadBinaryPage(SDDS_DATASET *SDDS_dataset, int64_t sparse_interval, int64_t sparse_offset, int32_t sparse_statistics)
Reads a binary page from an SDDS dataset.
void SDDS_SwapLong(int32_t *data)
Swaps the endianness of a 32-bit integer.
int32_t SDDS_fseek(FILE *fp, int64_t offset, int32_t dir)
Sets the file position indicator for a given file stream with retry logic.
int32_t SDDS_ReadBinaryPageLastRows(SDDS_DATASET *SDDS_dataset, int64_t last_rows)
Reads the last specified number of rows from a binary page of an SDDS dataset.
void SDDS_DeferSavingLayout(SDDS_DATASET *SDDS_dataset, int32_t mode)
Definition SDDS_copy.c:603
int32_t SDDS_SaveLayout(SDDS_DATASET *SDDS_dataset)
Definition SDDS_copy.c:615
char * SDDS_command[SDDS_NUM_COMMANDS]
Array of supported SDDS command names.
Definition SDDS_data.c:81
int64_t SDDS_CountRowsOfInterest(SDDS_DATASET *SDDS_dataset)
Counts the number of rows marked as "of interest" in the current data table.
int32_t SDDS_SetAutoReadRecovery(SDDS_DATASET *SDDS_dataset, uint32_t mode)
int32_t SDDS_ReadPageLastRows(SDDS_DATASET *SDDS_dataset, int64_t last_rows)
int64_t SDDS_SetRowLimit(int64_t limit)
int32_t SDDS_GetColumnMemoryMode(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_UpdateRowCount(SDDS_DATASET *SDDS_dataset)
void SDDS_SetTerminateMode(uint32_t mode)
int32_t SDDS_ReadLayout(SDDS_DATASET *SDDS_dataset, FILE *fp)
Definition SDDS_input.c:518
int64_t SDDS_GetRowLimit()
int32_t SDDS_ReadPageSparse(SDDS_DATASET *SDDS_dataset, uint32_t mode, int64_t sparse_interval, int64_t sparse_offset, int32_t sparse_statistics)
int32_t SDDS_FreeStringData(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_InitializeInputFromSearchPath(SDDS_DATASET *SDDSin, char *file)
int32_t SDDS_IsQuoted(char *string, char *position, char quotation_mark)
Checks if a position in a string is within a quoted section.
Definition SDDS_input.c:218
int32_t SDDS_InitializeInput(SDDS_DATASET *SDDS_dataset, char *filename)
Definition SDDS_input.c:50
int32_t SDDS_GetNamelist(SDDS_DATASET *SDDS_dataset, char *buffer, int32_t buflen, FILE *fp)
Reads a namelist from a file into a buffer.
Definition SDDS_input.c:249
int32_t SDDS_InitializeHeaderlessInput(SDDS_DATASET *SDDS_dataset, char *filename)
Initializes the SDDS dataset for headerless input.
Definition SDDS_input.c:176
static MDB_THREAD_LOCK terminateModeLock
Global variable to set the terminate mode for the SDDS dataset.
int32_t SDDS_Terminate(SDDS_DATASET *SDDS_dataset)
void SDDS_FreeTableStrings(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_LZMAReadLayout(SDDS_DATASET *SDDS_dataset, struct lzmafile *lzmafp)
Definition SDDS_input.c:681
int32_t SDDS_ReadPage(SDDS_DATASET *SDDS_dataset)
static MDB_THREAD_LOCK SDDS_RowLimitLock
Global variable to set a limit on the number of rows read.
int32_t SDDS_GotoPage(SDDS_DATASET *SDDS_dataset, int32_t page_number)
Sets the current page of the SDDS dataset to the specified page number.
int32_t SDDS_GetLZMANamelist(SDDS_DATASET *SDDS_dataset, char *buffer, int32_t buflen, struct lzmafile *lzmafp)
Reads a namelist from an LZMA-compressed file into a buffer.
Definition SDDS_input.c:345
int32_t SDDS_CheckEndOfFile(SDDS_DATASET *SDDS_dataset)
void SDDS_SetColumnMemoryMode(SDDS_DATASET *SDDS_dataset, uint32_t mode)
Internal definitions and function declarations for SDDS with LZMA support.
int32_t SDDS_ProcessArrayDefinition(SDDS_DATASET *SDDS_dataset, char *s)
Process the array definition section of the SDDS dataset.
int32_t SDDS_ProcessParameterDefinition(SDDS_DATASET *SDDS_dataset, char *s)
Process the parameter definition section of the SDDS dataset.
int32_t SDDS_ProcessAssociateDefinition(SDDS_DATASET *SDDS_dataset, char *s)
Process the associate definition section of the SDDS dataset.
char * fgetsLZMASkipComments(SDDS_DATASET *SDDS_dataset, char *s, int32_t slen, struct lzmafile *lzmafp, char skip_char)
Reads a line from a LZMA-compressed file while skipping comment lines.
FILE * SDDS_ProcessIncludeCommand(SDDS_DATASET *SDDS_dataset, char *s)
Process the include command within the SDDS dataset.
int32_t SDDS_ProcessDataMode(SDDS_DATASET *SDDS_dataset, char *s)
Process the data mode section of the SDDS dataset.
uint32_t SDDS_GetSpecialCommentsModes(SDDS_DATASET *SDDS_dataset)
Retrieves the current special comments modes set in the SDDS dataset.
int32_t SDDS_ProcessDescription(SDDS_DATASET *SDDS_dataset, char *s)
Process the description section of the SDDS dataset.
void SDDS_ResetSpecialCommentsModes(SDDS_DATASET *SDDS_dataset)
Resets the special comments modes in the SDDS dataset.
int32_t SDDS_ProcessColumnDefinition(SDDS_DATASET *SDDS_dataset, char *s)
Process the column definition section of the SDDS dataset.
void SDDS_SetError(char *error_text)
Records an error message in the SDDS error stack.
Definition SDDS_utils.c:421
int32_t SDDS_ZeroMemory(void *mem, int64_t n_bytes)
Sets a block of memory to zero.
int32_t SDDS_FreeArrayDefinition(ARRAY_DEFINITION *source)
Frees memory allocated for an array definition.
char * fgetsSkipComments(SDDS_DATASET *SDDS_dataset, char *s, int32_t slen, FILE *fp, char skip_char)
Reads a line from a file while skipping comment lines.
int32_t SDDS_SetMemory(void *mem, int64_t n_elements, int32_t data_type,...)
Initializes a memory block with a sequence of values based on a specified data type.
int32_t SDDS_CheckDataset(SDDS_DATASET *SDDS_dataset, const char *caller)
Validates the SDDS dataset pointer.
Definition SDDS_utils.c:618
void * SDDS_Malloc(size_t size)
Allocates memory of a specified size.
Definition SDDS_utils.c:705
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
int32_t SDDS_IsBigEndianMachine()
Determines whether the current machine uses big-endian byte ordering.
int32_t SDDS_MPI_ReadPage(SDDS_DATASET *SDDS_dataset)
Reads a page from an SDDS dataset using MPI.
int32_t SDDS_MPI_Terminate(SDDS_DATASET *SDDS_dataset)
Terminates the SDDS dataset by freeing all allocated resources and closing MPI files.
#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
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.
char * findFileInSearchPath(const char *filename)
Finds a file within the configured search path.
Definition searchPath.c:57
FILE * UnpackFopen(char *filename, unsigned long mode, short *popenUsed, char **tmpFileUsed)
Opens a file, potentially unpacking it based on its extension and mode.
Definition unpack.c:89