SDDSlib
Loading...
Searching...
No Matches
SDDS_ascii.c
Go to the documentation of this file.
1/**
2 * @file SDDS_ascii.c
3 * @brief SDDS ascii data input and output routines
4 *
5 * This file contains the implementation of the SDDS ascii data input and output routines.
6 * It provides functions for writing void pointer data to an ASCII file stream.
7 * The functions support different data types such as short, unsigned short, long, unsigned long,
8 * long long, unsigned long long, float, double, long double, string, and character.
9 *
10 *
11 * @copyright
12 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
13 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
14 *
15 * @license
16 * This file is distributed under the terms of the Software License Agreement
17 * found in the file LICENSE included with this distribution.
18 *
19 * @author M. Borland, C. Saunders, R. Soliday, H. Shang
20 */
21
22#include "SDDS.h"
23#include "SDDS_internal.h"
24#include "mdb.h"
25#include <ctype.h>
26
27#undef DEBUG
28
29#define COMMENT_POSITION 40
30
31#if SDDS_VERSION != 5
32# error "SDDS_VERSION does not match the version number of this file"
33#endif
34
35/* Define a dynamically expanded text buffer for use by ReadAsciiParameters,
36 ReadAsciiArrays, and ReadAsciiPage. Since these routines never call each
37 other, it is okay that they share this buffer.
38*/
39#define INITIAL_BIG_BUFFER_SIZE SDDS_MAXLINE
40
41/**
42 * @brief Writes a typed value to an ASCII file stream.
43 *
44 * This function writes a value of a specified SDDS data type to an ASCII file stream.
45 * The data is provided as a void pointer, and the function handles various data types
46 * by casting the pointer appropriately based on the `type` parameter.
47 * For string data, special characters are escaped according to SDDS conventions.
48 *
49 * @param data Pointer to the data to be written. Should be castable to the type specified by `type`.
50 * @param index Array index of the data to be printed; use 0 if not an array.
51 * @param type The SDDS data type of the data variable. Possible values include SDDS_SHORT, SDDS_LONG, SDDS_FLOAT, etc.
52 * @param format Optional printf format string to use; pass NULL to use the default format for the data type.
53 * @param fp The FILE pointer to the ASCII file stream where the data will be written.
54 *
55 * @return Returns 1 on success; 0 on error (e.g., if data or fp is NULL, or an unknown data type is specified).
56 */
57int32_t SDDS_WriteTypedValue(void *data, int64_t index, int32_t type, char *format, FILE *fp) {
58 char c, *s;
59 short hasWhitespace;
60
61 if (!data) {
62 SDDS_SetError("Unable to write value--data pointer is NULL (SDDS_WriteTypedValue)");
63 return (0);
64 }
65 if (!fp) {
66 SDDS_SetError("Unable to print value--file pointer is NULL (SDDS_WriteTypedValue)");
67 return (0);
68 }
69 switch (type) {
70 case SDDS_SHORT:
71 fprintf(fp, format ? format : "%hd", *((short *)data + index));
72 break;
73 case SDDS_USHORT:
74 fprintf(fp, format ? format : "%hu", *((unsigned short *)data + index));
75 break;
76 case SDDS_LONG:
77 fprintf(fp, format ? format : "%" PRId32, *((int32_t *)data + index));
78 break;
79 case SDDS_ULONG:
80 fprintf(fp, format ? format : "%" PRIu32, *((uint32_t *)data + index));
81 break;
82 case SDDS_LONG64:
83 fprintf(fp, format ? format : "%" PRId64, *((int64_t *)data + index));
84 break;
85 case SDDS_ULONG64:
86 fprintf(fp, format ? format : "%" PRIu64, *((uint64_t *)data + index));
87 break;
88 case SDDS_FLOAT:
89 fprintf(fp, format ? format : "%15.8e", *((float *)data + index));
90 break;
91 case SDDS_DOUBLE:
92 fprintf(fp, format ? format : "%22.15e", *((double *)data + index));
93 break;
94 case SDDS_LONGDOUBLE:
95 if (LDBL_DIG == 18) {
96 fprintf(fp, format ? format : "%22.18Le", *((long double *)data + index));
97 } else {
98 fprintf(fp, format ? format : "%22.15Le", *((long double *)data + index));
99 }
100 break;
101 case SDDS_STRING:
102 /* ignores format string */
103 s = *((char **)data + index);
104 hasWhitespace = 0;
106 fputc('"', fp);
107 hasWhitespace = 1;
108 }
109 while (s && *s) {
110 c = *s++;
111 if (c == '!')
112 fputs("\\!", fp);
113 else if (c == '\\')
114 fputs("\\\\", fp);
115 else if (c == '"')
116 fputs("\\\"", fp);
117 else if (c == ' ')
118 fputc(' ', fp); /* don't escape plain spaces */
119 else if (isspace(c) || !isprint(c))
120 fprintf(fp, "\\%03o", c);
121 else
122 fputc(c, fp);
123 }
124 if (hasWhitespace)
125 fputc('"', fp);
126 break;
127 case SDDS_CHARACTER:
128 /* ignores format string */
129 c = *((char *)data + index);
130 if (c == '!')
131 fputs("\\!", fp);
132 else if (c == '\\')
133 fputs("\\\\", fp);
134 else if (c == '"')
135 fputs("\\\"", fp);
136 else if (!c || isspace(c) || !isprint(c))
137 fprintf(fp, "\\%03o", c);
138 else
139 fputc(c, fp);
140 break;
141 default:
142 SDDS_SetError("Unable to write value--unknown data type (SDDS_WriteTypedValue)");
143 return (0);
144 }
145 return (1);
146}
147
148/**
149 * @brief Writes a typed value to an LZMA compressed ASCII file stream.
150 *
151 * This function writes a single value from the provided data pointer to the given LZMA compressed file stream.
152 * The value is formatted as an ASCII string according to the specified data type and optional format string.
153 * Supports various data types including integers, floating-point numbers, strings, and characters.
154 *
155 * @param data Pointer to the data to be written. The data should be of the type specified by the @p type parameter.
156 * For array data types, @p data should point to the base of the array.
157 * @param index Zero-based index of the element to write if @p data is an array; use 0 if @p data is a single value.
158 * @param type The SDDS data type of the value to be written. Determines how the data is interpreted and formatted.
159 * Valid types include:
160 * - SDDS_SHORT
161 * - SDDS_USHORT
162 * - SDDS_LONG
163 * - SDDS_ULONG
164 * - SDDS_LONG64
165 * - SDDS_ULONG64
166 * - SDDS_FLOAT
167 * - SDDS_DOUBLE
168 * - SDDS_LONGDOUBLE
169 * - SDDS_STRING
170 * - SDDS_CHARACTER
171 * @param format Optional printf-style format string to specify the output format. If NULL, a default format is used
172 * based on the data type.
173 * @param lzmafp Pointer to the LZMA file stream where the data will be written.
174 *
175 * @return Returns 1 on success, or 0 on error. If an error occurs, an error message is set via SDDS_SetError().
176 *
177 * @note This function handles special character escaping for strings and characters to ensure correct parsing.
178 * For string and character types, special characters like '!', '\\', and '"' are escaped appropriately.
179 */
180int32_t SDDS_LZMAWriteTypedValue(void *data, int64_t index, int32_t type, char *format, struct lzmafile *lzmafp) {
181 char c, *s;
182 short hasWhitespace;
183
184 if (!data) {
185 SDDS_SetError("Unable to write value--data pointer is NULL (SDDS_LZMAWriteTypedValue)");
186 return (0);
187 }
188 if (!lzmafp) {
189 SDDS_SetError("Unable to print value--file pointer is NULL (SDDS_LZMAWriteTypedValue)");
190 return (0);
191 }
192 switch (type) {
193 case SDDS_SHORT:
194 lzma_printf(lzmafp, format ? format : "%hd", *((short *)data + index));
195 break;
196 case SDDS_USHORT:
197 lzma_printf(lzmafp, format ? format : "%hu", *((unsigned short *)data + index));
198 break;
199 case SDDS_LONG:
200 lzma_printf(lzmafp, format ? format : "%" PRId32, *((int32_t *)data + index));
201 break;
202 case SDDS_ULONG:
203 lzma_printf(lzmafp, format ? format : "%" PRIu32, *((uint32_t *)data + index));
204 break;
205 case SDDS_LONG64:
206 lzma_printf(lzmafp, format ? format : "%" PRId64, *((int64_t *)data + index));
207 break;
208 case SDDS_ULONG64:
209 lzma_printf(lzmafp, format ? format : "%" PRIu64, *((uint64_t *)data + index));
210 break;
211 case SDDS_FLOAT:
212 lzma_printf(lzmafp, format ? format : "%15.8e", *((float *)data + index));
213 break;
214 case SDDS_DOUBLE:
215 lzma_printf(lzmafp, format ? format : "%22.15e", *((double *)data + index));
216 break;
217 case SDDS_LONGDOUBLE:
218 if (LDBL_DIG == 18) {
219 lzma_printf(lzmafp, format ? format : "%22.18Le", *((long double *)data + index));
220 } else {
221 lzma_printf(lzmafp, format ? format : "%22.15Le", *((long double *)data + index));
222 }
223 break;
224 case SDDS_STRING:
225 /* ignores format string */
226 s = *((char **)data + index);
227 hasWhitespace = 0;
229 lzma_putc('"', lzmafp);
230 hasWhitespace = 1;
231 }
232 while (s && *s) {
233 c = *s++;
234 if (c == '!')
235 lzma_puts("\\!", lzmafp);
236 else if (c == '\\')
237 lzma_puts("\\\\", lzmafp);
238 else if (c == '"')
239 lzma_puts("\\\"", lzmafp);
240 else if (c == ' ')
241 lzma_putc(' ', lzmafp); /* don't escape plain spaces */
242 else if (isspace(c) || !isprint(c))
243 lzma_printf(lzmafp, "\\%03o", c);
244 else
245 lzma_putc(c, lzmafp);
246 }
247 if (hasWhitespace)
248 lzma_putc('"', lzmafp);
249 break;
250 case SDDS_CHARACTER:
251 /* ignores format string */
252 c = *((char *)data + index);
253 if (c == '!')
254 lzma_puts("\\!", lzmafp);
255 else if (c == '\\')
256 lzma_puts("\\\\", lzmafp);
257 else if (c == '"')
258 lzma_puts("\\\"", lzmafp);
259 else if (!c || isspace(c) || !isprint(c))
260 lzma_printf(lzmafp, "\\%03o", c);
261 else
262 lzma_putc(c, lzmafp);
263 break;
264 default:
265 SDDS_SetError("Unable to write value--unknown data type (SDDS_LZMAWriteTypedValue)");
266 return (0);
267 }
268 return (1);
269}
270
271#if defined(zLib)
272/**
273 * @brief Writes a typed value to a GZIP compressed ASCII file stream.
274 *
275 * This function writes a single value from the provided data pointer to the given GZIP compressed file stream.
276 * The value is formatted as an ASCII string according to the specified data type and optional format string.
277 * Supports various data types including integers, floating-point numbers, strings, and characters.
278 *
279 * @param data Pointer to the data to be written. The data should be of the type specified by the @p type parameter.
280 * For array data types, @p data should point to the base of the array.
281 * @param index Zero-based index of the element to write if @p data is an array; use 0 if @p data is a single value.
282 * @param type The SDDS data type of the value to be written. Determines how the data is interpreted and formatted.
283 * Valid types include:
284 * - SDDS_SHORT
285 * - SDDS_USHORT
286 * - SDDS_LONG
287 * - SDDS_ULONG
288 * - SDDS_LONG64
289 * - SDDS_ULONG64
290 * - SDDS_FLOAT
291 * - SDDS_DOUBLE
292 * - SDDS_LONGDOUBLE
293 * - SDDS_STRING
294 * - SDDS_CHARACTER
295 * @param format Optional printf-style format string to specify the output format. If NULL, a default format is used
296 * based on the data type.
297 * @param gzfp Pointer to the GZIP file stream where the data will be written.
298 *
299 * @return Returns 1 on success, or 0 on error. If an error occurs, an error message is set via SDDS_SetError().
300 *
301 * @note This function handles special character escaping for strings and characters to ensure correct parsing.
302 * For string and character types, special characters like '!', '\\', and '"' are escaped appropriately.
303 */
304int32_t SDDS_GZipWriteTypedValue(void *data, int64_t index, int32_t type, char *format, gzFile gzfp) {
305 char c, *s;
306 short hasWhitespace;
307
308 if (!data) {
309 SDDS_SetError("Unable to write value--data pointer is NULL (SDDS_GZipWriteTypedValue)");
310 return (0);
311 }
312 if (!gzfp) {
313 SDDS_SetError("Unable to print value--file pointer is NULL (SDDS_GZipWriteTypedValue)");
314 return (0);
315 }
316 switch (type) {
317 case SDDS_SHORT:
318 gzprintf(gzfp, format ? format : "%hd", *((short *)data + index));
319 break;
320 case SDDS_USHORT:
321 gzprintf(gzfp, format ? format : "%hu", *((unsigned short *)data + index));
322 break;
323 case SDDS_LONG:
324 gzprintf(gzfp, format ? format : "%" PRId32, *((int32_t *)data + index));
325 break;
326 case SDDS_ULONG:
327 gzprintf(gzfp, format ? format : "%" PRIu32, *((uint32_t *)data + index));
328 break;
329 case SDDS_LONG64:
330 gzprintf(gzfp, format ? format : "%" PRId64, *((int64_t *)data + index));
331 break;
332 case SDDS_ULONG64:
333 gzprintf(gzfp, format ? format : "%" PRIu64, *((uint64_t *)data + index));
334 break;
335 case SDDS_FLOAT:
336 gzprintf(gzfp, format ? format : "%15.8e", *((float *)data + index));
337 break;
338 case SDDS_DOUBLE:
339 gzprintf(gzfp, format ? format : "%22.15e", *((double *)data + index));
340 break;
341 case SDDS_LONGDOUBLE:
342 if (LDBL_DIG == 18) {
343 gzprintf(gzfp, format ? format : "%22.18Le", *((long double *)data + index));
344 } else {
345 gzprintf(gzfp, format ? format : "%22.15Le", *((long double *)data + index));
346 }
347 break;
348 case SDDS_STRING:
349 /* ignores format string */
350 s = *((char **)data + index);
351 hasWhitespace = 0;
353 gzputc(gzfp, '"');
354 hasWhitespace = 1;
355 }
356 while (s && *s) {
357 c = *s++;
358 if (c == '!')
359 gzputs(gzfp, "\\!");
360 else if (c == '\\')
361 gzputs(gzfp, "\\\\");
362 else if (c == '"')
363 gzputs(gzfp, "\\\"");
364 else if (c == ' ')
365 gzputc(gzfp, ' '); /* don't escape plain spaces */
366 else if (isspace(c) || !isprint(c))
367 gzprintf(gzfp, "\\%03o", c);
368 else
369 gzputc(gzfp, c);
370 }
371 if (hasWhitespace)
372 gzputc(gzfp, '"');
373 break;
374 case SDDS_CHARACTER:
375 /* ignores format string */
376 c = *((char *)data + index);
377 if (c == '!')
378 gzputs(gzfp, "\\!");
379 else if (c == '\\')
380 gzputs(gzfp, "\\\\");
381 else if (c == '"')
382 gzputs(gzfp, "\\\"");
383 else if (!c || isspace(c) || !isprint(c))
384 gzprintf(gzfp, "\\%03o", c);
385 else
386 gzputc(gzfp, c);
387 break;
388 default:
389 SDDS_SetError("Unable to write value--unknown data type (SDDS_GZipWriteTypedValue)");
390 return (0);
391 }
392 return (1);
393}
394#endif
395
396/**
397 * @brief Writes a page of data in ASCII format to the SDDS dataset.
398 *
399 * This function writes the current page of data from the SDDS dataset to an ASCII file.
400 * It handles writing to regular files, as well as LZMA and GZIP compressed files if enabled.
401 * The function writes the page number, parameters, arrays, and rows of data according to the SDDS format.
402 *
403 * @param SDDS_dataset Pointer to the SDDS dataset containing the data to be written.
404 *
405 * @return Returns 1 on success, or 0 on error. If an error occurs, an error message is set via SDDS_SetError().
406 *
407 * @note This function checks the dataset for consistency before writing. It also updates internal state variables
408 * such as the last row written and the number of rows written.
409 */
410int32_t SDDS_WriteAsciiPage(SDDS_DATASET *SDDS_dataset) {
411#if defined(zLib)
412 gzFile gzfp;
413#endif
414 FILE *fp;
415 struct lzmafile *lzmafp;
416 int64_t i, rows;
417
418 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_WriteAsciiPage"))
419 return (0);
420#if defined(zLib)
421 if (SDDS_dataset->layout.gzipFile) {
422 if (!(gzfp = SDDS_dataset->layout.gzfp)) {
423 SDDS_SetError("Unable to write page--file pointer is NULL (SDDS_WriteAsciiPage)");
424 return (0);
425 }
426 if (SDDS_dataset->layout.data_mode.no_row_counts && (SDDS_dataset->page_number > 1 || SDDS_dataset->file_had_data))
427 gzputc(gzfp, '\n');
428 gzprintf(gzfp, "! page number %" PRId32 "\n", SDDS_dataset->page_number);
429
430 if (!SDDS_GZipWriteAsciiParameters(SDDS_dataset, gzfp) || !SDDS_GZipWriteAsciiArrays(SDDS_dataset, gzfp))
431 return 0;
432 rows = 0;
433 if (SDDS_dataset->layout.n_columns) {
434 rows = SDDS_CountRowsOfInterest(SDDS_dataset);
435 if (!SDDS_dataset->layout.data_mode.no_row_counts) {
436 SDDS_dataset->rowcount_offset = gztell(gzfp);
437 if (SDDS_dataset->layout.data_mode.fixed_row_count) {
438 gzprintf(gzfp, "%20" PRId64 "\n", ((rows / SDDS_dataset->layout.data_mode.fixed_row_increment) + 2) * SDDS_dataset->layout.data_mode.fixed_row_increment);
439 } else
440 gzprintf(gzfp, "%20" PRId64 "\n", rows);
441 }
442 for (i = 0; i < SDDS_dataset->n_rows; i++)
443 if (SDDS_dataset->row_flag[i] && !SDDS_GZipWriteAsciiRow(SDDS_dataset, i, gzfp))
444 return 0;
445 }
446 SDDS_dataset->last_row_written = SDDS_dataset->n_rows - 1;
447 SDDS_dataset->n_rows_written = rows;
448 SDDS_dataset->writing_page = 1;
449 /*gzflush(gzfp, Z_FULL_FLUSH); */
450 } else {
451#endif
452 if (SDDS_dataset->layout.lzmaFile) {
453 if (!(lzmafp = SDDS_dataset->layout.lzmafp)) {
454 SDDS_SetError("Unable to write page--file pointer is NULL (SDDS_WriteAsciiPage)");
455 return (0);
456 }
457 if (SDDS_dataset->layout.data_mode.no_row_counts && (SDDS_dataset->page_number > 1 || SDDS_dataset->file_had_data))
458 lzma_putc('\n', lzmafp);
459 lzma_printf(lzmafp, "! page number %" PRId32 "\n", SDDS_dataset->page_number);
460
461 if (!SDDS_LZMAWriteAsciiParameters(SDDS_dataset, lzmafp) || !SDDS_LZMAWriteAsciiArrays(SDDS_dataset, lzmafp))
462 return 0;
463 rows = 0;
464 if (SDDS_dataset->layout.n_columns) {
465 rows = SDDS_CountRowsOfInterest(SDDS_dataset);
466 if (!SDDS_dataset->layout.data_mode.no_row_counts) {
467 SDDS_dataset->rowcount_offset = lzma_tell(lzmafp);
468 if (SDDS_dataset->layout.data_mode.fixed_row_count)
469 lzma_printf(lzmafp, "%20" PRId64 "\n", ((rows / SDDS_dataset->layout.data_mode.fixed_row_increment) + 2) * SDDS_dataset->layout.data_mode.fixed_row_increment);
470 else
471 lzma_printf(lzmafp, "%20" PRId64 "\n", rows);
472 }
473 for (i = 0; i < SDDS_dataset->n_rows; i++)
474 if (SDDS_dataset->row_flag[i] && !SDDS_LZMAWriteAsciiRow(SDDS_dataset, i, lzmafp))
475 return 0;
476 }
477 SDDS_dataset->last_row_written = SDDS_dataset->n_rows - 1;
478 SDDS_dataset->n_rows_written = rows;
479 SDDS_dataset->writing_page = 1;
480 } else {
481 if (!(fp = SDDS_dataset->layout.fp)) {
482 SDDS_SetError("Unable to write page--file pointer is NULL (SDDS_WriteAsciiPage)");
483 return (0);
484 }
485 if (SDDS_dataset->layout.data_mode.no_row_counts && (SDDS_dataset->page_number > 1 || SDDS_dataset->file_had_data))
486 fputc('\n', fp);
487 fprintf(fp, "! page number %" PRId32 "\n", SDDS_dataset->page_number);
488
489 if (!SDDS_WriteAsciiParameters(SDDS_dataset, fp) || !SDDS_WriteAsciiArrays(SDDS_dataset, fp))
490 return 0;
491 rows = 0;
492 if (SDDS_dataset->layout.n_columns) {
493 rows = SDDS_CountRowsOfInterest(SDDS_dataset);
494 if (!SDDS_dataset->layout.data_mode.no_row_counts) {
495 SDDS_dataset->rowcount_offset = ftell(fp);
496 if (SDDS_dataset->layout.data_mode.fixed_row_count)
497 fprintf(fp, "%20" PRId64 "\n", ((rows / SDDS_dataset->layout.data_mode.fixed_row_increment) + 2) * SDDS_dataset->layout.data_mode.fixed_row_increment);
498 else
499 fprintf(fp, "%20" PRId64 "\n", rows);
500 }
501 for (i = 0; i < SDDS_dataset->n_rows; i++)
502 if (SDDS_dataset->row_flag[i] && !SDDS_WriteAsciiRow(SDDS_dataset, i, fp))
503 return 0;
504 }
505 SDDS_dataset->last_row_written = SDDS_dataset->n_rows - 1;
506 SDDS_dataset->n_rows_written = rows;
507 SDDS_dataset->writing_page = 1;
508 fflush(fp);
509 }
510#if defined(zLib)
511 }
512#endif
513
514 return (1);
515}
516
517/**
518 * @brief Writes the parameter data of an SDDS dataset in ASCII format to a file.
519 *
520 * This function writes all parameters of the SDDS dataset to the provided file pointer in ASCII format.
521 * Only parameters that do not have fixed values are written. Each parameter value is written on a new line.
522 *
523 * @param SDDS_dataset Pointer to the SDDS dataset containing the parameter data.
524 * @param fp File pointer to the ASCII file where the parameter data will be written.
525 *
526 * @return Returns 1 on success, or 0 on error. If an error occurs, an error message is set via SDDS_SetError().
527 *
528 * @note The function checks the dataset for consistency before writing. It uses SDDS_WriteTypedValue() to write
529 * each parameter value according to its data type.
530 */
531int32_t SDDS_WriteAsciiParameters(SDDS_DATASET *SDDS_dataset, FILE *fp) {
532 int32_t i;
533 SDDS_LAYOUT *layout;
534 /* char *predefined_format; */
535
536 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_WriteAsciiParameters"))
537 return (0);
538 layout = &SDDS_dataset->layout;
539 for (i = 0; i < layout->n_parameters; i++) {
540 if (layout->parameter_definition[i].fixed_value)
541 continue;
542 if (!SDDS_WriteTypedValue(SDDS_dataset->parameter[i], 0, layout->parameter_definition[i].type, NULL, fp)) {
543 SDDS_SetError("Unable to write ascii parameters (SDDS_WriteAsciiParameters)");
544 return 0;
545 }
546 fputc('\n', fp);
547 }
548 return (1);
549}
550
551/**
552 * @brief Writes the parameter data of an SDDS dataset in ASCII format to an LZMA compressed file.
553 *
554 * This function writes all parameters of the provided SDDS dataset to the specified LZMA compressed file in ASCII format.
555 * Only parameters that do not have fixed values are written. Each parameter value is written on a new line.
556 *
557 * @param SDDS_dataset Pointer to the SDDS dataset containing the parameter data.
558 * @param lzmafp Pointer to the LZMA file stream where the ASCII data will be written.
559 *
560 * @return Returns 1 on success, or 0 on error. If an error occurs, an error message is set via `SDDS_SetError()`.
561 *
562 * @note The function checks the dataset for consistency before writing. It uses `SDDS_LZMAWriteTypedValue()` to write
563 * each parameter value according to its data type.
564 */
565int32_t SDDS_LZMAWriteAsciiParameters(SDDS_DATASET *SDDS_dataset, struct lzmafile *lzmafp) {
566 int32_t i;
567 SDDS_LAYOUT *layout;
568 /* char *predefined_format; */
569
570 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_LZMAWriteAsciiParameters"))
571 return (0);
572 layout = &SDDS_dataset->layout;
573 for (i = 0; i < layout->n_parameters; i++) {
574 if (layout->parameter_definition[i].fixed_value)
575 continue;
576 if (!SDDS_LZMAWriteTypedValue(SDDS_dataset->parameter[i], 0, layout->parameter_definition[i].type, NULL, lzmafp)) {
577 SDDS_SetError("Unable to write ascii parameters (SDDS_LZMAWriteAsciiParameters)");
578 return 0;
579 }
580 lzma_putc('\n', lzmafp);
581 }
582 return (1);
583}
584
585#if defined(zLib)
586/**
587 * @brief Writes the parameter data of an SDDS dataset in ASCII format to a GZIP compressed file.
588 *
589 * This function writes all parameters of the provided SDDS dataset to the specified GZIP compressed file in ASCII format.
590 * Only parameters that do not have fixed values are written. Each parameter value is written on a new line.
591 *
592 * @param SDDS_dataset Pointer to the SDDS dataset containing the parameter data.
593 * @param gzfp Pointer to the GZIP file stream where the ASCII data will be written.
594 *
595 * @return Returns 1 on success, or 0 on error. If an error occurs, an error message is set via `SDDS_SetError()`.
596 *
597 * @note The function checks the dataset for consistency before writing. It uses `SDDS_GZipWriteTypedValue()` to write
598 * each parameter value according to its data type.
599 */
600int32_t SDDS_GZipWriteAsciiParameters(SDDS_DATASET *SDDS_dataset, gzFile gzfp) {
601 int32_t i;
602 SDDS_LAYOUT *layout;
603 /* char *predefined_format; */
604
605 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_GZipWriteAsciiParameters"))
606 return (0);
607 layout = &SDDS_dataset->layout;
608 for (i = 0; i < layout->n_parameters; i++) {
609 if (layout->parameter_definition[i].fixed_value)
610 continue;
611 if (!SDDS_GZipWriteTypedValue(SDDS_dataset->parameter[i], 0, layout->parameter_definition[i].type, NULL, gzfp)) {
612 SDDS_SetError("Unable to write ascii parameters (SDDS_GZipWriteAsciiParameters)");
613 return 0;
614 }
615 gzputc(gzfp, '\n');
616 }
617 return (1);
618}
619#endif
620
621/**
622 * @brief Writes the arrays of an SDDS dataset in ASCII format to a file.
623 *
624 * This function writes all arrays contained in the provided SDDS dataset to the specified file pointer in ASCII format.
625 * For each array, it writes the dimensions, a description line, and the array elements formatted according to their data type.
626 *
627 * @param SDDS_dataset Pointer to the SDDS dataset containing the arrays to be written.
628 * @param fp File pointer to the ASCII file where the array data will be written.
629 *
630 * @return Returns 1 on success, or 0 on error. If an error occurs, an error message is set via `SDDS_SetError()`.
631 *
632 * @note The function checks the dataset for consistency before writing. It uses `SDDS_WriteTypedValue()` to write
633 * each array element according to its data type. Each array element is written, with up to 6 elements per line.
634 */
635int32_t SDDS_WriteAsciiArrays(SDDS_DATASET *SDDS_dataset, FILE *fp) {
636 int32_t i, j;
637 SDDS_LAYOUT *layout;
638 /* char *predefined_format; */
639 ARRAY_DEFINITION *array_definition;
640 SDDS_ARRAY *array;
641
642 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_WriteAsciiArrays"))
643 return (0);
644 layout = &SDDS_dataset->layout;
645 for (j = 0; j < layout->n_arrays; j++) {
646 array_definition = layout->array_definition + j;
647 array = &SDDS_dataset->array[j];
648 for (i = 0; i < array_definition->dimensions; i++)
649 fprintf(fp, "%" PRId32 " ", array->dimension[i]);
650 fprintf(fp, " ! %" PRId32 "-dimensional array %s:\n", array_definition->dimensions, array_definition->name);
651 for (i = 0; i < array->elements;) {
652 if (!SDDS_WriteTypedValue(array->data, i, array_definition->type, NULL, fp)) {
653 SDDS_SetError("Unable to write array--couldn't write ASCII data (SDDS_WriteAsciiArrays)");
654 return (0);
655 }
656 i++;
657 if (i % 6 == 0 || i == array->elements)
658 fputc('\n', fp);
659 else
660 fputc(' ', fp);
661 }
662 }
663 return (1);
664}
665
666/**
667 * @brief Writes the arrays of an SDDS dataset in ASCII format to an LZMA compressed file.
668 *
669 * This function writes all arrays contained in the provided SDDS dataset to the specified LZMA compressed file in ASCII format.
670 * For each array, it writes the dimensions, a description line, and the array elements formatted according to their data type.
671 *
672 * @param SDDS_dataset Pointer to the SDDS dataset containing the arrays to be written.
673 * @param lzmafp Pointer to the LZMA file stream where the array data will be written.
674 *
675 * @return Returns 1 on success, or 0 on error. If an error occurs, an error message is set via `SDDS_SetError()`.
676 *
677 * @note The function checks the dataset for consistency before writing. It uses `SDDS_LZMAWriteTypedValue()` to write
678 * each array element according to its data type. Each array element is written, with up to 6 elements per line.
679 */
680int32_t SDDS_LZMAWriteAsciiArrays(SDDS_DATASET *SDDS_dataset, struct lzmafile *lzmafp) {
681 int32_t i, j;
682 SDDS_LAYOUT *layout;
683 /* char *predefined_format; */
684 ARRAY_DEFINITION *array_definition;
685 SDDS_ARRAY *array;
686
687 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_LZMAWriteAsciiArrays"))
688 return (0);
689 layout = &SDDS_dataset->layout;
690 for (j = 0; j < layout->n_arrays; j++) {
691 array_definition = layout->array_definition + j;
692 array = &SDDS_dataset->array[j];
693 for (i = 0; i < array_definition->dimensions; i++)
694 lzma_printf(lzmafp, "%" PRId32 " ", array->dimension[i]);
695 lzma_printf(lzmafp, " ! %" PRId32 "-dimensional array %s:\n", array_definition->dimensions, array_definition->name);
696 for (i = 0; i < array->elements;) {
697 if (!SDDS_LZMAWriteTypedValue(array->data, i, array_definition->type, NULL, lzmafp)) {
698 SDDS_SetError("Unable to write array--couldn't write ASCII data (SDDS_LZMAWriteAsciiArrays)");
699 return (0);
700 }
701 i++;
702 if (i % 6 == 0 || i == array->elements)
703 lzma_putc('\n', lzmafp);
704 else
705 lzma_putc(' ', lzmafp);
706 }
707 }
708 return (1);
709}
710
711#if defined(zLib)
712/**
713 * @brief Writes the arrays of an SDDS dataset in ASCII format to a GZIP compressed file.
714 *
715 * This function writes all arrays contained in the provided SDDS dataset to the specified GZIP compressed file in ASCII format.
716 * For each array, it writes the dimensions, a description line, and the array elements formatted according to their data type.
717 *
718 * @param SDDS_dataset Pointer to the SDDS dataset containing the arrays to be written.
719 * @param gzfp Pointer to the GZIP file stream where the array data will be written.
720 *
721 * @return Returns 1 on success, or 0 on error. If an error occurs, an error message is set via `SDDS_SetError()`.
722 *
723 * @note The function checks the dataset for consistency before writing. It uses `SDDS_GZipWriteTypedValue()` to write
724 * each array element according to its data type. Each array element is written, with up to 6 elements per line.
725 */
726int32_t SDDS_GZipWriteAsciiArrays(SDDS_DATASET *SDDS_dataset, gzFile gzfp) {
727 int32_t i, j;
728 SDDS_LAYOUT *layout;
729 /* char *predefined_format; */
730 ARRAY_DEFINITION *array_definition;
731 SDDS_ARRAY *array;
732
733 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_GZipWriteAsciiArrays"))
734 return (0);
735 layout = &SDDS_dataset->layout;
736 for (j = 0; j < layout->n_arrays; j++) {
737 array_definition = layout->array_definition + j;
738 array = &SDDS_dataset->array[j];
739 for (i = 0; i < array_definition->dimensions; i++)
740 gzprintf(gzfp, "%" PRId32 " ", array->dimension[i]);
741 gzprintf(gzfp, " ! %" PRId32 "-dimensional array %s:\n", array_definition->dimensions, array_definition->name);
742 for (i = 0; i < array->elements;) {
743 if (!SDDS_GZipWriteTypedValue(array->data, i, array_definition->type, NULL, gzfp)) {
744 SDDS_SetError("Unable to write array--couldn't write ASCII data (SDDS_GZipWriteAsciiArrays)");
745 return (0);
746 }
747 i++;
748 if (i % 6 == 0 || i == array->elements)
749 gzputc(gzfp, '\n');
750 else
751 gzputc(gzfp, ' ');
752 }
753 }
754 return (1);
755}
756#endif
757
758/**
759 * @brief Writes a single row of data in ASCII format to a file.
760 *
761 * This function writes the specified row from the SDDS dataset to the provided file pointer in ASCII format.
762 * The data is formatted according to the data types of the columns. Supports multi-line rows as specified by
763 * the data mode settings in the dataset layout.
764 *
765 * @param SDDS_dataset Pointer to the SDDS dataset containing the data.
766 * @param row Zero-based index of the row to write.
767 * @param fp File pointer to the ASCII file where the row data will be written.
768 *
769 * @return Returns 1 on success, or 0 on error. If an error occurs, an error message is set via `SDDS_SetError()`.
770 *
771 * @note The function checks the dataset for consistency before writing. It uses `SDDS_WriteTypedValue()` to write
772 * each column value according to its data type. The number of values per line is determined by the
773 * `lines_per_row` setting in the dataset layout.
774 */
775int32_t SDDS_WriteAsciiRow(SDDS_DATASET *SDDS_dataset, int64_t row, FILE *fp) {
776 int32_t newline_needed;
777 int64_t i, n_per_line, line;
778 /* int32_t embedded_quotes_present; */
779 SDDS_LAYOUT *layout;
780 /* char *predefined_format, *s; */
781
782 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_WriteAsciiRow"))
783 return (0);
784 layout = &SDDS_dataset->layout;
785 if (SDDS_dataset->layout.data_mode.lines_per_row <= 0)
786 SDDS_dataset->layout.data_mode.lines_per_row = 1;
787 n_per_line = SDDS_dataset->layout.n_columns / SDDS_dataset->layout.data_mode.lines_per_row;
788 line = 1;
789 newline_needed = 0;
790 for (i = 0; i < layout->n_columns; i++) {
791 if (!SDDS_WriteTypedValue(SDDS_dataset->data[i], row, layout->column_definition[i].type, NULL, fp)) {
792 SDDS_SetError("Unable to write ascii row (SDDS_WriteAsciiRow)");
793 return 0;
794 }
795 if ((i + 1) % n_per_line == 0 && line != SDDS_dataset->layout.data_mode.lines_per_row) {
796 newline_needed = 0;
797 fputc('\n', fp);
798 line++;
799 } else {
800 fputc(' ', fp);
801 newline_needed = 1;
802 }
803 }
804 if (newline_needed)
805 fputc('\n', fp);
806 return (1);
807}
808
809/**
810 * @brief Writes a single row of data in ASCII format to an LZMA compressed file.
811 *
812 * This function writes the specified row from the SDDS dataset to the provided LZMA compressed file in ASCII format.
813 * The data is formatted according to the data types of the columns. Supports multi-line rows as specified by
814 * the data mode settings in the dataset layout.
815 *
816 * @param SDDS_dataset Pointer to the SDDS dataset containing the data.
817 * @param row Zero-based index of the row to write.
818 * @param lzmafp Pointer to the LZMA file stream where the row data will be written.
819 *
820 * @return Returns 1 on success, or 0 on error. If an error occurs, an error message is set via `SDDS_SetError()`.
821 *
822 * @note The function checks the dataset for consistency before writing. It uses `SDDS_LZMAWriteTypedValue()` to write
823 * each column value according to its data type. The number of values per line is determined by the
824 * `lines_per_row` setting in the dataset layout.
825 */
826int32_t SDDS_LZMAWriteAsciiRow(SDDS_DATASET *SDDS_dataset, int64_t row, struct lzmafile *lzmafp) {
827 int32_t newline_needed;
828 int64_t i, n_per_line, line;
829 /* int32_t embedded_quotes_present; */
830 SDDS_LAYOUT *layout;
831 /* char *predefined_format, *s; */
832
833 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_LZMAWriteAsciiRow"))
834 return (0);
835 layout = &SDDS_dataset->layout;
836 if (SDDS_dataset->layout.data_mode.lines_per_row <= 0)
837 SDDS_dataset->layout.data_mode.lines_per_row = 1;
838 n_per_line = SDDS_dataset->layout.n_columns / SDDS_dataset->layout.data_mode.lines_per_row;
839 line = 1;
840 newline_needed = 0;
841 for (i = 0; i < layout->n_columns; i++) {
842 if (!SDDS_LZMAWriteTypedValue(SDDS_dataset->data[i], row, layout->column_definition[i].type, NULL, lzmafp)) {
843 SDDS_SetError("Unable to write ascii row (SDDS_LZMAWriteAsciiRow)");
844 return 0;
845 }
846 if ((i + 1) % n_per_line == 0 && line != SDDS_dataset->layout.data_mode.lines_per_row) {
847 newline_needed = 0;
848 lzma_putc('\n', lzmafp);
849 line++;
850 } else {
851 lzma_putc(' ', lzmafp);
852 newline_needed = 1;
853 }
854 }
855 if (newline_needed)
856 lzma_putc('\n', lzmafp);
857 return (1);
858}
859
860#if defined(zLib)
861/**
862 * @brief Writes a single row of data in ASCII format to a GZIP compressed file.
863 *
864 * This function writes the specified row from the SDDS dataset to the provided GZIP compressed file in ASCII format.
865 * The data is formatted according to the data types of the columns. Supports multi-line rows as specified by
866 * the data mode settings in the dataset layout.
867 *
868 * @param SDDS_dataset Pointer to the SDDS dataset containing the data.
869 * @param row Zero-based index of the row to write.
870 * @param gzfp Pointer to the GZIP file stream where the row data will be written.
871 *
872 * @return Returns 1 on success, or 0 on error. If an error occurs, an error message is set via `SDDS_SetError()`.
873 *
874 * @note The function checks the dataset for consistency before writing. It uses `SDDS_GZipWriteTypedValue()` to write
875 * each column value according to its data type. The number of values per line is determined by the
876 * `lines_per_row` setting in the dataset layout.
877 */
878int32_t SDDS_GZipWriteAsciiRow(SDDS_DATASET *SDDS_dataset, int64_t row, gzFile gzfp) {
879 int32_t newline_needed;
880 int64_t i, n_per_line, line;
881 /* int32_t embedded_quotes_present; */
882 SDDS_LAYOUT *layout;
883 /* char *predefined_format, *s; */
884
885 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_GZipWriteAsciiRow"))
886 return (0);
887 layout = &SDDS_dataset->layout;
888 if (SDDS_dataset->layout.data_mode.lines_per_row <= 0)
889 SDDS_dataset->layout.data_mode.lines_per_row = 1;
890 n_per_line = SDDS_dataset->layout.n_columns / SDDS_dataset->layout.data_mode.lines_per_row;
891 line = 1;
892 newline_needed = 0;
893 for (i = 0; i < layout->n_columns; i++) {
894 if (!SDDS_GZipWriteTypedValue(SDDS_dataset->data[i], row, layout->column_definition[i].type, NULL, gzfp)) {
895 SDDS_SetError("Unable to write ascii row (SDDS_GZipWriteAsciiRow)");
896 return 0;
897 }
898 if ((i + 1) % n_per_line == 0 && line != SDDS_dataset->layout.data_mode.lines_per_row) {
899 newline_needed = 0;
900 gzputc(gzfp, '\n');
901 line++;
902 } else {
903 gzputc(gzfp, ' ');
904 newline_needed = 1;
905 }
906 }
907 if (newline_needed)
908 gzputc(gzfp, '\n');
909 return (1);
910}
911#endif
912
913/**
914 * @brief Reads the parameters from an ASCII file into the SDDS dataset.
915 *
916 * This function reads parameter data from an ASCII file and stores it in the provided SDDS dataset.
917 * It supports reading from regular files, as well as GZIP and LZMA compressed files if enabled.
918 *
919 * @param SDDS_dataset Pointer to the SDDS dataset where the parameters will be stored.
920 *
921 * @return Returns 1 on success, 0 on error, or -1 if end-of-file is reached before any parameters are read.
922 *
923 * @note The function checks the dataset for consistency before reading. It handles fixed-value parameters appropriately.
924 * The function reads each parameter line by line, skipping comments, and stores the values after scanning them
925 * according to their data type.
926 */
928 int32_t i, first_read;
929 SDDS_LAYOUT *layout;
930#if defined(zLib)
931 gzFile gzfp;
932#endif
933 FILE *fp;
934 struct lzmafile *lzmafp;
935 char *bigBuffer = NULL;
936 int32_t bigBufferSize = 0;
937
938 layout = &SDDS_dataset->layout;
939 first_read = 1;
940 if (layout->n_parameters > 0) {
941 if (!(bigBuffer = SDDS_Malloc(sizeof(*bigBuffer) * (bigBufferSize = INITIAL_BIG_BUFFER_SIZE)))) {
942 SDDS_SetError("Unable to read parameters--buffer allocation failure (SDDS_ReadAsciiParameters)");
943 return (0);
944 }
945 }
946#if defined(zLib)
947 if (SDDS_dataset->layout.gzipFile) {
948 gzfp = layout->gzfp;
949 for (i = 0; i < layout->n_parameters; i++) {
950 if (layout->parameter_definition[i].definition_mode & SDDS_WRITEONLY_DEFINITION)
951 continue;
952 bigBuffer[0] = 0;
953 if (!layout->parameter_definition[i].fixed_value) {
954 if (!fgetsGZipSkipCommentsResize(SDDS_dataset, &bigBuffer, &bigBufferSize, gzfp, '!')) {
955 if (first_read) {
956 if (bigBuffer)
957 free(bigBuffer);
958 return (-1);
959 }
960 SDDS_SetError("Unable to read parameters--data ends prematurely (SDDS_ReadAsciiParameters)");
961 return (0);
962 }
963 first_read = 0;
964 bigBuffer[strlen(bigBuffer) - 1] = 0;
965 } else
966 strcpy(bigBuffer, layout->parameter_definition[i].fixed_value);
967 if (!SDDS_ScanData(bigBuffer, layout->parameter_definition[i].type, 0, SDDS_dataset->parameter[i], 0, 1)) {
968 SDDS_SetError("Unable to read page--parameter scanning error (SDDS_ReadAsciiParameters)");
969 return (0);
970 }
971 }
972 } else {
973#endif
974 if (SDDS_dataset->layout.lzmaFile) {
975 lzmafp = layout->lzmafp;
976 for (i = 0; i < layout->n_parameters; i++) {
977 if (layout->parameter_definition[i].definition_mode & SDDS_WRITEONLY_DEFINITION)
978 continue;
979 bigBuffer[0] = 0;
980 if (!layout->parameter_definition[i].fixed_value) {
981 if (!fgetsLZMASkipCommentsResize(SDDS_dataset, &bigBuffer, &bigBufferSize, lzmafp, '!')) {
982 if (first_read) {
983 if (bigBuffer)
984 free(bigBuffer);
985 return (-1);
986 }
987 SDDS_SetError("Unable to read parameters--data ends prematurely (SDDS_ReadAsciiParameters)");
988 return (0);
989 }
990 first_read = 0;
991 bigBuffer[strlen(bigBuffer) - 1] = 0;
992 } else
993 strcpy(bigBuffer, layout->parameter_definition[i].fixed_value);
994 if (!SDDS_ScanData(bigBuffer, layout->parameter_definition[i].type, 0, SDDS_dataset->parameter[i], 0, 1)) {
995 SDDS_SetError("Unable to read page--parameter scanning error (SDDS_ReadAsciiParameters)");
996 return (0);
997 }
998 }
999 } else {
1000 fp = layout->fp;
1001 for (i = 0; i < layout->n_parameters; i++) {
1002 if (layout->parameter_definition[i].definition_mode & SDDS_WRITEONLY_DEFINITION)
1003 continue;
1004 bigBuffer[0] = 0;
1005 if (!layout->parameter_definition[i].fixed_value) {
1006 if (!fgetsSkipCommentsResize(SDDS_dataset, &bigBuffer, &bigBufferSize, fp, '!')) {
1007 if (first_read) {
1008 if (bigBuffer)
1009 free(bigBuffer);
1010 return (-1);
1011 }
1012 SDDS_SetError("Unable to read parameters--data ends prematurely (SDDS_ReadAsciiParameters)");
1013 return (0);
1014 }
1015 first_read = 0;
1016 bigBuffer[strlen(bigBuffer) - 1] = 0;
1017 } else
1018 strcpy(bigBuffer, layout->parameter_definition[i].fixed_value);
1019 if (!SDDS_ScanData(bigBuffer, layout->parameter_definition[i].type, 0, SDDS_dataset->parameter[i], 0, 1)) {
1020 SDDS_SetError("Unable to read page--parameter scanning error (SDDS_ReadAsciiParameters)");
1021 return (0);
1022 }
1023 }
1024 }
1025#if defined(zLib)
1026 }
1027#endif
1028 if (bigBuffer)
1029 free(bigBuffer);
1030 return (1);
1031}
1032
1033/**
1034 * @brief Reads the arrays from an ASCII file into the SDDS dataset.
1035 *
1036 * This function reads array data from an ASCII file and stores it in the provided SDDS dataset.
1037 * It supports reading from regular files, as well as GZIP and LZMA compressed files if enabled.
1038 *
1039 * @param SDDS_dataset Pointer to the SDDS dataset where the arrays will be stored.
1040 *
1041 * @return Returns 1 on success, 0 on error, or -1 if end-of-file is reached before any arrays are read.
1042 *
1043 * @note The function checks the dataset for consistency before reading. It reads array dimensions and elements,
1044 * handling multi-dimensional arrays appropriately. The array elements are scanned and stored according
1045 * to their data types.
1046 */
1047int32_t SDDS_ReadAsciiArrays(SDDS_DATASET *SDDS_dataset) {
1048 int32_t i, j, length;
1049 SDDS_LAYOUT *layout;
1050 char *buffer = NULL;
1051 int32_t bufferSize = 0;
1052 char *bigBuffer = NULL;
1053 int32_t bigBufferSize = 0;
1054 char *bigBufferCopy;
1055 int32_t bigBufferCopySize;
1056 /* ARRAY_DEFINITION *array_definition; */
1057 SDDS_ARRAY *array;
1058#if defined(zLib)
1059 gzFile gzfp = NULL;
1060#endif
1061 FILE *fp = NULL;
1062 struct lzmafile *lzmafp = NULL;
1063
1064 layout = &SDDS_dataset->layout;
1065#if defined(zLib)
1066 if (SDDS_dataset->layout.gzipFile) {
1067 gzfp = layout->gzfp;
1068 } else {
1069#endif
1070 if (SDDS_dataset->layout.lzmaFile) {
1071 lzmafp = layout->lzmafp;
1072 } else {
1073 fp = layout->fp;
1074 }
1075#if defined(zLib)
1076 }
1077#endif
1078 if (layout->n_arrays > 0) {
1079 if (!(bigBuffer = SDDS_Malloc(sizeof(*bigBuffer) * (bigBufferSize = INITIAL_BIG_BUFFER_SIZE)))) {
1080 SDDS_SetError("Unable to read parameters--buffer allocation failure (SDDS_ReadAsciiArrays)");
1081 return (0);
1082 }
1083 }
1084 for (i = 0; i < layout->n_arrays; i++) {
1085#if defined(zLib)
1086 if (SDDS_dataset->layout.gzipFile) {
1087 if (!fgetsGZipSkipCommentsResize(SDDS_dataset, &bigBuffer, &bigBufferSize, gzfp, '!') || SDDS_StringIsBlank(bigBuffer)) {
1088 if (i == 0)
1089 return (-1);
1090 SDDS_SetError("Unable to read array--dimensions missing (SDDS_ReadAsciiArrays)");
1091 return (0);
1092 }
1093 } else {
1094#endif
1095 if (SDDS_dataset->layout.lzmaFile) {
1096 if (!fgetsLZMASkipCommentsResize(SDDS_dataset, &bigBuffer, &bigBufferSize, lzmafp, '!') || SDDS_StringIsBlank(bigBuffer)) {
1097 if (i == 0)
1098 return (-1);
1099 SDDS_SetError("Unable to read array--dimensions missing (SDDS_ReadAsciiArrays)");
1100 return (0);
1101 }
1102 } else {
1103 if (!fgetsSkipCommentsResize(SDDS_dataset, &bigBuffer, &bigBufferSize, fp, '!') || SDDS_StringIsBlank(bigBuffer)) {
1104 if (i == 0)
1105 return (-1);
1106 SDDS_SetError("Unable to read array--dimensions missing (SDDS_ReadAsciiArrays)");
1107 return (0);
1108 }
1109 }
1110#if defined(zLib)
1111 }
1112#endif
1113 if (!(array = SDDS_dataset->array + i)) {
1114 SDDS_SetError("Unable to read array--pointer to structure storage area is NULL (SDDS_ReadAsciiArrays)");
1115 return (0);
1116 }
1117 if (array->definition && !SDDS_FreeArrayDefinition(array->definition)) {
1118 SDDS_SetError("Unable to get array--array definition corrupted (SDDS_ReadAsciiArrays)");
1119 return (0);
1120 }
1121 if (!SDDS_CopyArrayDefinition(&array->definition, layout->array_definition + i)) {
1122 SDDS_SetError("Unable to read array--definition copy failed (SDDS_ReadAsciiArrays)");
1123 return (0);
1124 }
1125 /*if (array->dimension) free(array->dimension); */
1126 if (!(array->dimension = SDDS_Realloc(array->dimension, sizeof(*array->dimension) * array->definition->dimensions))) {
1127 SDDS_SetError("Unable to read array--allocation failure (SDDS_ReadAsciiArrays)");
1128 return (0);
1129 }
1130 array->elements = 1;
1131 if ((length = strlen(bigBuffer)) >= bufferSize) {
1132 if (!(buffer = SDDS_Realloc(buffer, sizeof(*buffer) * (bufferSize = 2 * length)))) {
1133 SDDS_SetError("Unable to scan data--allocation failure (SDDS_ReadAsciiArrays");
1134 return (0);
1135 }
1136 }
1137 for (j = 0; j < array->definition->dimensions; j++) {
1138 if (SDDS_GetToken(bigBuffer, buffer, SDDS_MAXLINE) <= 0 || sscanf(buffer, "%" SCNd32, array->dimension + j) != 1 || array->dimension[j] < 0) {
1139 SDDS_SetError("Unable to read array--dimensions missing or negative (SDDS_ReadAsciiArrays)");
1140 return (0);
1141 }
1142 array->elements *= array->dimension[j];
1143 }
1144 if (!array->elements)
1145 continue;
1146 if (array->data)
1147 free(array->data);
1148 array->data = array->pointer = NULL;
1149 if (!(array->data = SDDS_Realloc(array->data, array->elements * SDDS_type_size[array->definition->type - 1]))) {
1150 SDDS_SetError("Unable to read array--allocation failure (SDDS_ReadAsciiArrays)");
1151 return (0);
1152 }
1153 SDDS_ZeroMemory(array->data, array->elements * SDDS_type_size[array->definition->type - 1]);
1154 j = 0;
1155 bigBuffer[0] = 0;
1156 do {
1157 if (SDDS_StringIsBlank(bigBuffer)) {
1158 bigBuffer[0] = 0;
1159#if defined(zLib)
1160 if (SDDS_dataset->layout.gzipFile) {
1161 if (!fgetsGZipSkipCommentsResize(SDDS_dataset, &bigBuffer, &bigBufferSize, gzfp, '!') || SDDS_StringIsBlank(bigBuffer)) {
1162 SDDS_SetError("Unable to read array--dimensions missing (SDDS_ReadAsciiArrays)");
1163 return (0);
1164 }
1165 } else {
1166#endif
1167 if (SDDS_dataset->layout.lzmaFile) {
1168 if (!fgetsLZMASkipCommentsResize(SDDS_dataset, &bigBuffer, &bigBufferSize, lzmafp, '!') || SDDS_StringIsBlank(bigBuffer)) {
1169 SDDS_SetError("Unable to read array--dimensions missing (SDDS_ReadAsciiArrays)");
1170 return (0);
1171 }
1172 } else {
1173 if (!fgetsSkipCommentsResize(SDDS_dataset, &bigBuffer, &bigBufferSize, fp, '!') || SDDS_StringIsBlank(bigBuffer)) {
1174 SDDS_SetError("Unable to read array--dimensions missing (SDDS_ReadAsciiArrays)");
1175 return (0);
1176 }
1177 }
1178#if defined(zLib)
1179 }
1180#endif
1181 }
1182 /* copy the bigBuffer because SDDS_ScanData2 will change the bigBufferCopy pointer that SDDS_ScanData
1183 cannot do becuase bigBuffer is a static variable. This change was implemented to greatly improve
1184 the speed of reading a very large line of array elements. The previous version just did a lot of
1185 strcpy commands to these huge lines which was really slow. */
1186 bigBufferCopy = bigBuffer;
1187 bigBufferCopySize = strlen(bigBufferCopy);
1188 do {
1189 if (!SDDS_ScanData2(bigBufferCopy, &bigBufferCopy, &bigBufferCopySize, array->definition->type, array->definition->field_length, array->data, j, 0)) {
1190 SDDS_SetError("Unable to read array--error scanning data element (SDDS_ReadAsciiArrays)");
1191 return (0);
1192 }
1193 } while (++j < array->elements && !SDDS_StringIsBlank(bigBufferCopy));
1194 bigBuffer[0] = 0;
1195 } while (j < array->elements);
1196 }
1197 if (buffer)
1198 free(buffer);
1199 if (bigBuffer)
1200 free(bigBuffer);
1201 return (1);
1202}
1203
1204/**
1205 * @brief Reads the next SDDS ASCII page into memory with optional data sparsity and statistics.
1206 *
1207 * This function reads the next page of data from an ASCII SDDS file into the provided dataset.
1208 * It supports reading data with specified sparsity (interval and offset) and can compute statistics
1209 * such as average, median, minimum, or maximum over the sparse data.
1210 *
1211 * @param SDDS_dataset Pointer to the SDDS dataset where the data will be stored.
1212 * @param sparse_interval Interval for sparsity; read every nth row if greater than 1.
1213 * @param sparse_offset Offset for sparsity; number of initial rows to skip.
1214 * @param sparse_statistics Statistic to compute over the sparse data:
1215 * - 0: None
1216 * - 1: Average
1217 * - 2: Median
1218 * - 3: Minimum
1219 * - 4: Maximum
1220 *
1221 * @return Returns the page number on success, -1 if end-of-file is reached, or 0 on error.
1222 *
1223 * @note The function utilizes `SDDS_ReadAsciiPageDetailed()` to perform the actual reading.
1224 */
1225int32_t SDDS_ReadAsciiPage(SDDS_DATASET *SDDS_dataset, int64_t sparse_interval, int64_t sparse_offset, int32_t sparse_statistics) {
1226 return SDDS_ReadAsciiPageDetailed(SDDS_dataset, sparse_interval, sparse_offset, 0, sparse_statistics);
1227}
1228
1229/**
1230 * @brief Reads the last specified number of rows from an ASCII page of an SDDS dataset.
1231 *
1232 * This function reads only the last specified number of rows from the next ASCII page in the SDDS dataset.
1233 *
1234 * @param SDDS_dataset Pointer to the SDDS dataset where the data will be stored.
1235 * @param last_rows Number of rows to read from the end of the page.
1236 *
1237 * @return Returns the page number on success, -1 if end-of-file is reached, or 0 on error.
1238 *
1239 * @note The function utilizes `SDDS_ReadAsciiPageDetailed()` to perform the actual reading.
1240 */
1241int32_t SDDS_ReadAsciiPageLastRows(SDDS_DATASET *SDDS_dataset, int64_t last_rows) {
1242 return SDDS_ReadAsciiPageDetailed(SDDS_dataset, 1, 0, last_rows, 0);
1243}
1244
1245/**
1246 * @brief Reads a detailed page of data from an ASCII file into an SDDS dataset with optional sparsity and statistics.
1247 *
1248 * This function reads a page of data from an ASCII SDDS file into the provided dataset, supporting various options for data sparsity and statistical processing.
1249 * It allows specifying a sparse interval and offset to read every nth row starting from a specific offset, as well as reading only the last specified number of rows.
1250 * Additionally, it can compute statistical measures over the sparse data, such as average, median, minimum, or maximum.
1251 *
1252 * @param SDDS_dataset Pointer to the SDDS dataset where the data will be stored.
1253 * @param sparse_interval Interval for sparsity; reads every nth row if greater than 1. Use 1 to read every row.
1254 * @param sparse_offset Offset from the first row to start reading. Rows before this offset are skipped.
1255 * @param last_rows Number of last rows to read. If greater than 0, only the last @p last_rows rows are read, overriding @p sparse_interval and @p sparse_offset.
1256 * Use 0 to read all rows according to @p sparse_interval and @p sparse_offset.
1257 * @param sparse_statistics Statistical operation to perform over the sparse data:
1258 * - 0: None (no statistical operation)
1259 * - 1: Average
1260 * - 2: Median
1261 * - 3: Minimum
1262 * - 4: Maximum
1263 *
1264 * @return Returns the page number on success,
1265 * -1 if end-of-file is reached before any data is read,
1266 * 0 on error.
1267 *
1268 * @note This function handles reading from regular files, as well as GZIP and LZMA compressed files if enabled.
1269 * It updates the internal state of the dataset, including the page number and number of rows read.
1270 * If @p last_rows is specified and greater than 0, it overrides @p sparse_interval and @p sparse_offset.
1271 * In case of errors during reading, the function attempts to recover if @c autoRecover is enabled in the dataset.
1272 */
1273int32_t SDDS_ReadAsciiPageDetailed(SDDS_DATASET *SDDS_dataset, int64_t sparse_interval, int64_t sparse_offset, int64_t last_rows, int32_t sparse_statistics) {
1274 SDDS_LAYOUT *layout;
1275 int32_t no_row_counts, end_of_data, retval, lineCount;
1276 int64_t n_rows, i, j, k, rows_to_store;
1277 /* int32_t page_number; */
1278 char s[SDDS_MAXLINE];
1279 char *dataRead, *bigBufferCopy;
1280 int32_t bigBufferCopySize;
1281 char *bigBuffer = NULL;
1282 int32_t bigBufferSize = 0;
1283 /* char *ptr; */
1284#if defined(zLib)
1285 gzFile gzfp = NULL;
1286#endif
1287 FILE *fp = NULL;
1288 void **statData=NULL;
1289 double statResult;
1290 struct lzmafile *lzmafp = NULL;
1291 /* double value; */
1292
1293 if (SDDS_dataset->autoRecovered)
1294 return -1;
1295
1296 SDDS_SetReadRecoveryMode(SDDS_dataset, 0);
1297
1298#if defined(zLib)
1299 if (SDDS_dataset->layout.gzipFile) {
1300 gzfp = SDDS_dataset->layout.gzfp;
1301 } else {
1302#endif
1303 if (SDDS_dataset->layout.lzmaFile) {
1304 lzmafp = SDDS_dataset->layout.lzmafp;
1305 } else {
1306 fp = SDDS_dataset->layout.fp;
1307 }
1308#if defined(zLib)
1309 }
1310#endif
1311 if (SDDS_dataset->page_number == -1)
1312 /* end of file already hit */
1313 return -1;
1314#if defined(zLib)
1315 if (SDDS_dataset->layout.gzipFile) {
1316 if (gzeof(gzfp) && SDDS_dataset->page_number > 0)
1317 /* end of file and not first page about to be read */
1318 return SDDS_dataset->page_number = -1;
1319 } else {
1320#endif
1321 if (SDDS_dataset->layout.lzmaFile) {
1322 if (lzma_eof(lzmafp) && SDDS_dataset->page_number > 0)
1323 /* end of file and not first page about to be read */
1324 return SDDS_dataset->page_number = -1;
1325 } else {
1326 if (feof(fp) && SDDS_dataset->page_number > 0)
1327 /* end of file and not first page about to be read */
1328 return SDDS_dataset->page_number = -1;
1329 }
1330#if defined(zLib)
1331 }
1332#endif
1333 if (!SDDS_AsciiDataExpected(SDDS_dataset) && SDDS_dataset->page_number != 0)
1334 /* if no columns or arrays and only fixed value parameters, then only one "page" allowed */
1335 return (SDDS_dataset->page_number = -1);
1336
1337#if defined(zLib)
1338 if (SDDS_dataset->layout.gzipFile) {
1339 if (SDDS_dataset->page_number == 0)
1340 for (i = 0; i < SDDS_dataset->layout.data_mode.additional_header_lines; i++) {
1341 if (!fgetsGZipSkipComments(SDDS_dataset, s, SDDS_MAXLINE, gzfp, '!'))
1342 return (SDDS_dataset->page_number = -1); /* indicates end of data */
1343 }
1344 } else {
1345#endif
1346 if (SDDS_dataset->layout.lzmaFile) {
1347 if (SDDS_dataset->page_number == 0)
1348 for (i = 0; i < SDDS_dataset->layout.data_mode.additional_header_lines; i++) {
1349 if (!fgetsLZMASkipComments(SDDS_dataset, s, SDDS_MAXLINE, lzmafp, '!'))
1350 return (SDDS_dataset->page_number = -1); /* indicates end of data */
1351 }
1352 } else {
1353 if (SDDS_dataset->page_number == 0)
1354 for (i = 0; i < SDDS_dataset->layout.data_mode.additional_header_lines; i++) {
1355 if (!fgetsSkipComments(SDDS_dataset, s, SDDS_MAXLINE, fp, '!'))
1356 return (SDDS_dataset->page_number = -1); /* indicates end of data */
1357 }
1358 }
1359#if defined(zLib)
1360 }
1361#endif
1362
1363 /* the next call increments the page number */
1364 if (!SDDS_StartPage(SDDS_dataset, 0)) {
1365 SDDS_SetError("Unable to read page--couldn't start page (SDDS_ReadAsciiPage)");
1366 return (0);
1367 }
1368
1369 layout = &SDDS_dataset->layout;
1370
1371 if ((retval = SDDS_ReadAsciiParameters(SDDS_dataset)) < 1) {
1372 if (retval)
1373 return (SDDS_dataset->page_number = retval);
1374 SDDS_SetError("Unable to read page--couldn't read parameters (SDDS_ReadAsciiPage)");
1375 return (0);
1376 }
1377 if ((retval = SDDS_ReadAsciiArrays(SDDS_dataset)) < 1) {
1378 if (retval)
1379 return (SDDS_dataset->page_number = retval);
1380 SDDS_SetError("Unable to read page--couldn't read arrays (SDDS_ReadAsciiPage)");
1381 return (0);
1382 }
1383
1384 if (last_rows < 0)
1385 last_rows = 0;
1386 if (sparse_interval <= 0)
1387 sparse_interval = 1;
1388 if (sparse_offset < 0)
1389 sparse_offset = 0;
1390
1391 SDDS_dataset->rowcount_offset = -1;
1392 if (layout->n_columns) {
1393 if (!(bigBuffer = SDDS_Malloc(sizeof(*bigBuffer) * (bigBufferSize = INITIAL_BIG_BUFFER_SIZE)))) {
1394 SDDS_SetError("Unable to read parameters--buffer allocation failure (SDDS_ReadAsciiPage)");
1395 return (0);
1396 }
1397
1398 n_rows = 0;
1399 no_row_counts = 0;
1400 if (!SDDS_dataset->layout.data_mode.no_row_counts) {
1401 /* read the number of rows */
1402#if defined(zLib)
1403 if (SDDS_dataset->layout.gzipFile) {
1404 if (!fgetsGZipSkipComments(SDDS_dataset, s, SDDS_MAXLINE, gzfp, '!')) {
1405 if (bigBuffer)
1406 free(bigBuffer);
1407 return (SDDS_dataset->page_number = -1); /* indicates end of data */
1408 }
1409 } else {
1410#endif
1411 if (SDDS_dataset->layout.lzmaFile) {
1412 if (!fgetsLZMASkipComments(SDDS_dataset, s, SDDS_MAXLINE, lzmafp, '!')) {
1413 if (bigBuffer)
1414 free(bigBuffer);
1415 return (SDDS_dataset->page_number = -1); /* indicates end of data */
1416 }
1417 } else {
1418 do {
1419 SDDS_dataset->rowcount_offset = ftell(fp);
1420 if (!fgets(s, SDDS_MAXLINE, fp)) {
1421 if (bigBuffer)
1422 free(bigBuffer);
1423 return (SDDS_dataset->page_number = -1); /* indicates end of data */
1424 }
1425 } while (s[0] == '!');
1426 }
1427#if defined(zLib)
1428 }
1429#endif
1430 if (sscanf(s, "%" SCNd64, &n_rows) != 1 || n_rows < 0) {
1431 SDDS_SetError("Unable to read page--file has no (valid) number-of-rows entry (SDDS_ReadAsciiPage)");
1432 return (0);
1433 }
1434 if (n_rows > SDDS_GetRowLimit()) {
1435 /* number of rows is "unreasonably" large---treat like end-of-file */
1436 if (bigBuffer)
1437 free(bigBuffer);
1438 return (SDDS_dataset->page_number = -1);
1439 }
1440 if (last_rows) {
1441 sparse_interval = 1;
1442 sparse_offset = n_rows - last_rows;
1443 if (sparse_offset < 0)
1444 sparse_offset = 0;
1445 }
1446 rows_to_store = (n_rows - sparse_offset) / sparse_interval + 2;
1447 } else {
1448 // fix last_rows when no row count is available
1449 no_row_counts = 1;
1450 n_rows = TABLE_LENGTH_INCREMENT;
1451 rows_to_store = n_rows;
1452 }
1453
1454 if (rows_to_store >= SDDS_dataset->n_rows_allocated) {
1455 /* lengthen the page */
1456 if (!SDDS_LengthenTable(SDDS_dataset, rows_to_store - SDDS_dataset->n_rows_allocated)) {
1457 SDDS_SetError("Unable to read page--couldn't lengthen data page (SDDS_ReadAsciiPage)");
1458 return (0);
1459 }
1460 }
1461
1462 /* read the page values */
1463 j = end_of_data = k = 0;
1464 s[0] = 0;
1465 if (!no_row_counts && n_rows == 0) {
1466 SDDS_dataset->n_rows = 0;
1467 if (bigBuffer)
1468 free(bigBuffer);
1469 return (SDDS_dataset->page_number);
1470 }
1471 bigBuffer[0] = 0;
1472 bigBufferCopy = bigBuffer;
1473 do {
1474 if (j >= SDDS_dataset->n_rows_allocated) {
1475 /* lengthen the page */
1476 if (!SDDS_LengthenTable(SDDS_dataset, TABLE_LENGTH_INCREMENT)) {
1477 SDDS_SetError("Unable to read page--couldn't lengthen data page (SDDS_ReadAsciiPage)");
1478 return (0);
1479 }
1480 }
1481 lineCount = 0;
1482 dataRead = NULL;
1483 for (i = 0; i < SDDS_dataset->layout.n_columns; i++) {
1484 if (k == 0) {
1485 if (sparse_statistics != 0) {
1486 // Allocate buffer space for statistical sparsing
1487 if (i == 0) {
1488 statData = (void**)malloc(SDDS_dataset->layout.n_columns * sizeof(void*));
1489 }
1490 if (SDDS_FLOATING_TYPE(layout->column_definition[i].type)) {
1491 // Not ideal for SDDS_LONGDOUBLE but we may never run across this error
1492 statData[i] = (double*)calloc(sparse_interval, sizeof(double));
1493 }
1494 }
1495 }
1496
1497 if (layout->column_definition[i].definition_mode & SDDS_WRITEONLY_DEFINITION)
1498 continue;
1499 if (SDDS_StringIsBlank(bigBufferCopy)) {
1500 bigBuffer[0] = 0;
1501 bigBufferCopy = bigBuffer;
1502 dataRead = NULL;
1503#if defined(zLib)
1504 if (SDDS_dataset->layout.gzipFile) {
1505 if (!(dataRead = fgetsGZipSkipCommentsResize(SDDS_dataset, &bigBuffer, &bigBufferSize, gzfp, '!')) || SDDS_StringIsBlank(bigBuffer)) {
1506 SDDS_dataset->n_rows = j;
1507 if (no_row_counts) {
1508 /* legitmate end of data set */
1509 end_of_data = 1;
1510 break;
1511 }
1512 /* error, but may be recoverable */
1513 gzseek(gzfp, 0L, SEEK_END);
1514 if (SDDS_dataset->autoRecover) {
1515 SDDS_dataset->autoRecovered = 1;
1517 if (bigBuffer)
1518 free(bigBuffer);
1519 return (SDDS_dataset->page_number);
1520 }
1521 SDDS_SetError("Unable to read page (SDDS_ReadAsciiPage)");
1522 SDDS_SetReadRecoveryMode(SDDS_dataset, 1);
1523 return (0);
1524 }
1525 } else {
1526#endif
1527 if (SDDS_dataset->layout.lzmaFile) {
1528 if (!(dataRead = fgetsLZMASkipCommentsResize(SDDS_dataset, &bigBuffer, &bigBufferSize, lzmafp, '!')) || SDDS_StringIsBlank(bigBuffer)) {
1529 SDDS_dataset->n_rows = j;
1530 if (no_row_counts) {
1531 /* legitmate end of data set */
1532 end_of_data = 1;
1533 break;
1534 }
1535 /* error, but may be recoverable */
1536 lzma_seek(lzmafp, 0L, SEEK_END);
1537 if (SDDS_dataset->autoRecover) {
1538 SDDS_dataset->autoRecovered = 1;
1540 if (bigBuffer)
1541 free(bigBuffer);
1542 return (SDDS_dataset->page_number);
1543 }
1544 SDDS_SetError("Unable to read page (SDDS_ReadAsciiPage)");
1545 SDDS_SetReadRecoveryMode(SDDS_dataset, 1);
1546 return (0);
1547 }
1548 } else {
1549 if (!(dataRead = fgetsSkipCommentsResize(SDDS_dataset, &bigBuffer, &bigBufferSize, fp, '!')) || SDDS_StringIsBlank(bigBuffer)) {
1550 SDDS_dataset->n_rows = j;
1551 if (no_row_counts) {
1552 /* legitmate end of data set */
1553 end_of_data = 1;
1554 break;
1555 }
1556 /* error, but may be recoverable */
1557 fseek(fp, 0L, SEEK_END);
1558 if (SDDS_dataset->autoRecover) {
1559 SDDS_dataset->autoRecovered = 1;
1561 if (bigBuffer)
1562 free(bigBuffer);
1563 return (SDDS_dataset->page_number);
1564 }
1565 SDDS_SetError("Unable to read page (SDDS_ReadAsciiPage)");
1566 SDDS_SetReadRecoveryMode(SDDS_dataset, 1);
1567 return (0);
1568 }
1569 }
1570#if defined(zLib)
1571 }
1572#endif
1573 lineCount++;
1574 bigBufferCopy = bigBuffer;
1575 bigBufferCopySize = strlen(bigBufferCopy);
1576 }
1577 if (!SDDS_ScanData2(bigBufferCopy, &bigBufferCopy, &bigBufferCopySize, layout->column_definition[i].type, layout->column_definition[i].field_length, SDDS_dataset->data[i], j, 0)) {
1578 /* error, but may be recoverable */
1579 SDDS_dataset->n_rows = j;
1580#if defined(zLib)
1581 if (SDDS_dataset->layout.gzipFile) {
1582 gzseek(gzfp, 0L, SEEK_END);
1583 } else {
1584#endif
1585 if (SDDS_dataset->layout.lzmaFile) {
1586 lzma_seek(lzmafp, 0L, SEEK_END);
1587 } else {
1588 fseek(fp, 0L, SEEK_END);
1589 }
1590#if defined(zLib)
1591 }
1592#endif
1593 if (SDDS_dataset->autoRecover) {
1594 SDDS_dataset->autoRecovered = 1;
1596 if (bigBuffer)
1597 free(bigBuffer);
1598 return (SDDS_dataset->page_number);
1599 }
1600 SDDS_SetReadRecoveryMode(SDDS_dataset, 1);
1601 SDDS_SetError("Unable to read page--scanning error (SDDS_ReadAsciiPage)");
1602 return (0);
1603 }
1604 if (sparse_statistics != 0) {
1605 switch (layout->column_definition[i].type) {
1606 case SDDS_FLOAT:
1607 ((double*)statData[i])[k % sparse_interval] = (double)(((float*)SDDS_dataset->data[i])[j]);
1608 break;
1609 case SDDS_DOUBLE:
1610 ((double*)statData[i])[k % sparse_interval] = ((double*)SDDS_dataset->data[i])[j];
1611 break;
1612 case SDDS_LONGDOUBLE:
1613 ((double*)statData[i])[k % sparse_interval] = (double)(((long double*)SDDS_dataset->data[i])[j]);
1614 break;
1615 }
1616 if (SDDS_FLOATING_TYPE(layout->column_definition[i].type)) {
1617 if (sparse_statistics == 1) {
1618 // Sparse and get average statistics
1619 compute_average(&statResult, (double*)statData[i], (k % sparse_interval) + 1);
1620 } else if (sparse_statistics == 2) {
1621 // Sparse and get median statistics
1622 compute_median(&statResult, (double*)statData[i], (k % sparse_interval) + 1);
1623 } else if (sparse_statistics == 3) {
1624 // Sparse and get minimum statistics
1625 statResult = min_in_array((double*)statData[i], (k % sparse_interval) + 1);
1626 } else if (sparse_statistics == 4) {
1627 // Sparse and get maximum statistics
1628 statResult = max_in_array((double*)statData[i], (k % sparse_interval) + 1);
1629 }
1630 }
1631 switch (layout->column_definition[i].type) {
1632 case SDDS_FLOAT:
1633 ((float*)SDDS_dataset->data[i])[j] = statResult;
1634 break;
1635 case SDDS_DOUBLE:
1636 ((double*)SDDS_dataset->data[i])[j] = statResult;
1637 break;
1638 case SDDS_LONGDOUBLE:
1639 ((long double*)SDDS_dataset->data[i])[j] = statResult;
1640 break;
1641 }
1642 }
1643
1644#if defined(DEBUG)
1645 fprintf(stderr, "line remaining = %s\n", bigBuffer);
1646#endif
1647 }
1648 if (end_of_data)
1649 /* ran out of data for no_row_counts=1 */
1650 break;
1651 if (layout->data_mode.lines_per_row != 0 && lineCount != layout->data_mode.lines_per_row) {
1652 sprintf(s, "Unable to read page--line layout error at line %" PRId64 " of page %" PRId32 " (SDDS_ReadAsciiPage)", j + 1, SDDS_dataset->page_number);
1653 SDDS_SetError(s);
1654 /* data ends prematurely, which is an error that may be recoverable */
1655#if defined(zLib)
1656 if (SDDS_dataset->layout.gzipFile) {
1657 gzseek(gzfp, 0L, SEEK_END);
1658 } else {
1659#endif
1660 if (SDDS_dataset->layout.lzmaFile) {
1661 lzma_seek(lzmafp, 0L, SEEK_END);
1662 } else {
1663 fseek(fp, 0L, SEEK_END);
1664 }
1665#if defined(zLib)
1666 }
1667#endif
1668 if (SDDS_dataset->autoRecover) {
1669 SDDS_dataset->autoRecovered = 1;
1671 if (bigBuffer)
1672 free(bigBuffer);
1673 return (SDDS_dataset->page_number);
1674 }
1675 SDDS_SetReadRecoveryMode(SDDS_dataset, 1);
1676 SDDS_dataset->n_rows = j;
1677 return (0);
1678 }
1679 if (layout->data_mode.lines_per_row != 0) {
1680 bigBuffer[0] = 0;
1681 bigBufferCopy = bigBuffer;
1682 }
1683 if (--sparse_offset < 0 &&
1684 (((sparse_statistics == 0) && (k % sparse_interval == 0)) || ((sparse_statistics != 0) && (k % sparse_interval == sparse_interval - 1))))
1685 j++;
1686 k++;
1687 } while (k < n_rows || no_row_counts);
1688
1689 if (sparse_statistics != 0) {
1690 for (i = 0; i < SDDS_dataset->layout.n_columns; i++) {
1691 if (SDDS_FLOATING_TYPE(layout->column_definition[i].type)) {
1692 free(statData[i]);
1693 }
1694 }
1695 free(statData);
1696 }
1697
1698 if (end_of_data && !(SDDS_dataset->page_number == 1) && j == 0 && !dataRead) {
1699 /* For end of data in no_row_counts=1 mode for any page other than the first,
1700 * an end-of-file is not a valid way to end an empty page (only an incomplete line is)
1701 */
1702 if (bigBuffer)
1703 free(bigBuffer);
1704 return SDDS_dataset->page_number = -1;
1705 }
1706 SDDS_dataset->n_rows = j;
1707 }
1708 if (bigBuffer)
1709 free(bigBuffer);
1710
1711 return (SDDS_dataset->page_number);
1712}
1713
1714/**
1715 * @brief Scans a string and saves the parsed value into a data pointer according to the specified data type.
1716 *
1717 * This function extracts data from a string and stores it in the provided data pointer.
1718 * It handles various SDDS data types, including integers, floating-point numbers, strings, and characters.
1719 * The function supports both fixed-field and variable-field formats and can process parameters and column data.
1720 *
1721 * @param string Pointer to the input string containing the data to be scanned.
1722 * @param type The SDDS data type to interpret the scanned data as. Valid types include:
1723 * - SDDS_SHORT
1724 * - SDDS_USHORT
1725 * - SDDS_LONG
1726 * - SDDS_ULONG
1727 * - SDDS_LONG64
1728 * - SDDS_ULONG64
1729 * - SDDS_FLOAT
1730 * - SDDS_DOUBLE
1731 * - SDDS_LONGDOUBLE
1732 * - SDDS_STRING
1733 * - SDDS_CHARACTER
1734 * @param field_length Field length for fixed-field formats. Set to 0 for variable-field formats.
1735 * If negative, indicates left-padding should be removed.
1736 * @param data Void pointer to the data storage where the scanned value will be saved.
1737 * Must be pre-allocated and appropriate for the specified data type.
1738 * @param index The index within the data array where the value should be stored.
1739 * @param is_parameter Set to 1 if the data is from an SDDS parameter; set to 0 for column data.
1740 *
1741 * @return Returns 1 on success, or 0 on error.
1742 * If an error occurs, an error message is set via `SDDS_SetError()`.
1743 *
1744 * @note The function allocates a buffer internally to process the input string.
1745 * It handles escape sequences for strings and characters using `SDDS_InterpretEscapes()`.
1746 * For string data types, the function manages memory allocation for the data array elements.
1747 */
1748int32_t SDDS_ScanData(char *string, int32_t type, int32_t field_length, void *data, int64_t index, int32_t is_parameter) {
1749 char *buffer = NULL;
1750 int32_t abs_field_length, length;
1751 int32_t bufferSize = 0;
1752
1753 abs_field_length = abs(field_length);
1754 if (!string) {
1755 SDDS_SetError("Unable to scan data--input string is NULL (SDDS_ScanData)");
1756 return (0);
1757 }
1758 if (!data) {
1759 SDDS_SetError("Unable to scan data--data pointer is NULL (SDDS_ScanData)");
1760 return (0);
1761 }
1762 if (!(buffer = SDDS_Malloc(sizeof(*buffer) * (bufferSize = SDDS_MAXLINE)))) {
1763 SDDS_SetError("Unable to scan data--allocation failure (SDDS_ScanData)");
1764 return (0);
1765 }
1766 if ((length = strlen(string)) < abs_field_length)
1767 length = abs_field_length;
1768 if (bufferSize <= length) {
1769 if (!(buffer = SDDS_Realloc(buffer, sizeof(*buffer) * (bufferSize = 2 * length)))) {
1770 /* I allocate 2*length in the hopes that I won't need to realloc too often if I do this */
1771 SDDS_SetError("Unable to scan data--allocation failure (SDDS_ScanData)");
1772 return (0);
1773 }
1774 }
1775 if (type != SDDS_STRING) {
1776 /* for non-string data, fill buffer with string to be scanned */
1777 if (field_length) {
1778 /* fill with fixed number of characters */
1779 if (abs_field_length > (int32_t)strlen(string)) {
1780 strcpy(buffer, string);
1781 *string = 0;
1782 } else {
1783 strncpy(buffer, string, abs_field_length);
1784 buffer[field_length] = 0;
1785 strcpy(string, string + abs_field_length);
1786 }
1787 } else if (SDDS_GetToken(string, buffer, bufferSize) < 0) {
1788 SDDS_SetError("Unable to scan data--tokenizing error (SDDS_ScanData)");
1789 return (0);
1790 }
1791 }
1792 switch (type) {
1793 case SDDS_SHORT:
1794 if (sscanf(buffer, "%hd", ((short *)data) + index) == 1) {
1795 if (buffer)
1796 free(buffer);
1797 return (1);
1798 }
1799 break;
1800 case SDDS_USHORT:
1801 if (sscanf(buffer, "%hu", ((unsigned short *)data) + index) == 1) {
1802 if (buffer)
1803 free(buffer);
1804 return (1);
1805 }
1806 break;
1807 case SDDS_LONG:
1808 if (sscanf(buffer, "%" SCNd32, ((int32_t *)data) + index) == 1) {
1809 if (buffer)
1810 free(buffer);
1811 return (1);
1812 }
1813 break;
1814 case SDDS_ULONG:
1815 if (sscanf(buffer, "%" SCNu32, ((uint32_t *)data) + index) == 1) {
1816 if (buffer)
1817 free(buffer);
1818 return (1);
1819 }
1820 break;
1821 case SDDS_LONG64:
1822 if (sscanf(buffer, "%" SCNd64, ((int64_t *)data) + index) == 1) {
1823 if (buffer)
1824 free(buffer);
1825 return (1);
1826 }
1827 break;
1828 case SDDS_ULONG64:
1829 if (sscanf(buffer, "%" SCNu64, ((uint64_t *)data) + index) == 1) {
1830 if (buffer)
1831 free(buffer);
1832 return (1);
1833 }
1834 break;
1835 case SDDS_FLOAT:
1836 if (sscanf(buffer, "%f", ((float *)data) + index) == 1) {
1837 if (buffer)
1838 free(buffer);
1839 return (1);
1840 }
1841 break;
1842 case SDDS_DOUBLE:
1843 if (sscanf(buffer, "%lf", ((double *)data) + index) == 1) {
1844 if (buffer)
1845 free(buffer);
1846 return (1);
1847 }
1848 break;
1849 case SDDS_LONGDOUBLE:
1850 if (sscanf(buffer, "%Lf", ((long double *)data) + index) == 1) {
1851 if (buffer)
1852 free(buffer);
1853 return (1);
1854 }
1855 break;
1856 case SDDS_STRING:
1857 if (is_parameter) {
1858 int32_t len;
1859 if (((char **)data)[index]) {
1860 free(((char **)data)[index]);
1861 ((char **)data)[index] = NULL;
1862 }
1863 if ((len = strlen(string)) > 0) {
1864 if (string[len - 1] == '\r')
1865 string[len - 1] = 0;
1866 }
1867 if (string[0] == '"')
1868 SDDS_GetToken(string, buffer, bufferSize);
1869 else
1870 strcpy(buffer, string);
1871 SDDS_InterpretEscapes(buffer);
1872 if (SDDS_CopyString(((char **)data) + index, buffer)) {
1873 if (buffer)
1874 free(buffer);
1875 return (1);
1876 }
1877 } else {
1878 if (field_length) {
1879 if (abs_field_length > (int32_t)strlen(string)) {
1880 strcpy(buffer, string);
1881 *string = 0;
1882 } else {
1883 strncpy(buffer, string, abs_field_length);
1884 buffer[abs_field_length] = 0;
1885 strcpy(string, string + abs_field_length);
1886 }
1887 if (field_length < 0)
1888 SDDS_RemovePadding(buffer);
1889 } else if (SDDS_GetToken(string, buffer, bufferSize) < 0)
1890 break;
1891 if (((char **)data)[index]) {
1892 free(((char **)data)[index]);
1893 ((char **)data)[index] = NULL;
1894 }
1895 SDDS_InterpretEscapes(buffer);
1896 if (SDDS_CopyString(((char **)data) + index, buffer)) {
1897 if (buffer)
1898 free(buffer);
1899 return (1);
1900 }
1901 }
1902 break;
1903 case SDDS_CHARACTER:
1904 SDDS_InterpretEscapes(buffer);
1905 *(((char *)data) + index) = buffer[0];
1906 if (buffer)
1907 free(buffer);
1908 return (1);
1909 default:
1910 SDDS_SetError("Unknown data type encountered (SDDS_ScanData)");
1911 return (0);
1912 }
1913 SDDS_SetError("Unable to scan data--scanning or allocation error (SDDS_ScanData)");
1914 return (0);
1915}
1916
1917/**
1918 * @brief Scans a string and saves the parsed value into a data pointer, optimized for long strings.
1919 *
1920 * This function is similar to `SDDS_ScanData` but optimized for very long strings.
1921 * It modifies the input string by advancing the string pointer and reducing its length after each call,
1922 * which can improve performance when processing large amounts of data.
1923 *
1924 * @param string Pointer to the input string containing the data to be scanned.
1925 * @param pstring Pointer to the string pointer; this is updated to point to the next unread character.
1926 * @param strlength Pointer to the length of the string; this is updated as the string is consumed.
1927 * @param type The SDDS data type to interpret the scanned data as. Valid types include:
1928 * - SDDS_SHORT
1929 * - SDDS_USHORT
1930 * - SDDS_LONG
1931 * - SDDS_ULONG
1932 * - SDDS_LONG64
1933 * - SDDS_ULONG64
1934 * - SDDS_FLOAT
1935 * - SDDS_DOUBLE
1936 * - SDDS_LONGDOUBLE
1937 * - SDDS_STRING
1938 * - SDDS_CHARACTER
1939 * @param field_length Field length for fixed-field formats. Set to 0 for variable-field formats.
1940 * If negative, indicates left-padding should be removed.
1941 * @param data Void pointer to the data storage where the scanned value will be saved.
1942 * Must be pre-allocated and appropriate for the specified data type.
1943 * @param index The index within the data array where the value should be stored.
1944 * @param is_parameter Set to 1 if the data is from an SDDS parameter; set to 0 for column data.
1945 *
1946 * @return Returns 1 on success, or 0 on error.
1947 * If an error occurs, an error message is set via `SDDS_SetError()`.
1948 *
1949 * @note This function modifies the input string by advancing the pointer and reducing the length,
1950 * which can lead to the original string being altered after each call.
1951 * It is more efficient for processing very long strings compared to `SDDS_ScanData`.
1952 */
1953int32_t SDDS_ScanData2(char *string, char **pstring, int32_t *strlength, int32_t type, int32_t field_length, void *data, int64_t index, int32_t is_parameter) {
1954 char *buffer = NULL;
1955 int32_t abs_field_length, length;
1956 int32_t bufferSize = 0;
1957
1958 abs_field_length = abs(field_length);
1959 if (!string) {
1960 SDDS_SetError("Unable to scan data--input string is NULL (SDDS_ScanData2)");
1961 return (0);
1962 }
1963 if (!data) {
1964 SDDS_SetError("Unable to scan data--data pointer is NULL (SDDS_ScanData2)");
1965 return (0);
1966 }
1967 if (!(buffer = SDDS_Malloc(sizeof(*buffer) * (bufferSize = SDDS_MAXLINE)))) {
1968 SDDS_SetError("Unable to scan data--allocation failure (SDDS_ScanData2)");
1969 return (0);
1970 }
1971 length = *strlength;
1972 if (length < abs_field_length)
1973 length = abs_field_length;
1974 if (bufferSize <= length) {
1975 if (!(buffer = SDDS_Realloc(buffer, sizeof(*buffer) * (bufferSize = 2 * length)))) {
1976 /* I allocate 2*length in the hopes that I won't need to realloc too often if I do this */
1977 SDDS_SetError("Unable to scan data--allocation failure (SDDS_ScanData2)");
1978 return (0);
1979 }
1980 }
1981 if (type != SDDS_STRING) {
1982 /* for non-string data, fill buffer with string to be scanned */
1983 if (field_length) {
1984 /* fill with fixed number of characters */
1985 if (abs_field_length > *strlength) {
1986 strcpy(buffer, string);
1987 **pstring = 0;
1988 *strlength = 0;
1989 } else {
1990 strncpy(buffer, string, abs_field_length);
1991 buffer[abs_field_length] = 0;
1992 *pstring += abs_field_length;
1993 *strlength -= abs_field_length;
1994 }
1995 } else if (SDDS_GetToken2(string, pstring, strlength, buffer, bufferSize) < 0) {
1996 SDDS_SetError("Unable to scan data--tokenizing error (SDDS_ScanData2)");
1997 return (0);
1998 }
1999 }
2000 switch (type) {
2001 case SDDS_SHORT:
2002 if (sscanf(buffer, "%hd", ((short *)data) + index) == 1) {
2003 if (buffer)
2004 free(buffer);
2005 return (1);
2006 }
2007 break;
2008 case SDDS_USHORT:
2009 if (sscanf(buffer, "%hu", ((unsigned short *)data) + index) == 1) {
2010 if (buffer)
2011 free(buffer);
2012 return (1);
2013 }
2014 break;
2015 case SDDS_LONG:
2016 if (sscanf(buffer, "%" SCNd32, ((int32_t *)data) + index) == 1) {
2017 if (buffer)
2018 free(buffer);
2019 return (1);
2020 }
2021 break;
2022 case SDDS_ULONG:
2023 if (sscanf(buffer, "%" SCNu32, ((uint32_t *)data) + index) == 1) {
2024 if (buffer)
2025 free(buffer);
2026 return (1);
2027 }
2028 break;
2029 case SDDS_LONG64:
2030 if (sscanf(buffer, "%" SCNd64, ((int64_t *)data) + index) == 1) {
2031 if (buffer)
2032 free(buffer);
2033 return (1);
2034 }
2035 break;
2036 case SDDS_ULONG64:
2037 if (sscanf(buffer, "%" SCNu64, ((uint64_t *)data) + index) == 1) {
2038 if (buffer)
2039 free(buffer);
2040 return (1);
2041 }
2042 break;
2043 case SDDS_FLOAT:
2044 if (sscanf(buffer, "%f", ((float *)data) + index) == 1) {
2045 if (buffer)
2046 free(buffer);
2047 return (1);
2048 }
2049 break;
2050 case SDDS_DOUBLE:
2051 if (sscanf(buffer, "%lf", ((double *)data) + index) == 1) {
2052 if (buffer)
2053 free(buffer);
2054 return (1);
2055 }
2056 break;
2057 case SDDS_LONGDOUBLE:
2058 if (sscanf(buffer, "%Lf", ((long double *)data) + index) == 1) {
2059 if (buffer)
2060 free(buffer);
2061 return (1);
2062 }
2063 break;
2064 case SDDS_STRING:
2065 if (is_parameter) {
2066 int32_t len;
2067 if (((char **)data)[index]) {
2068 free(((char **)data)[index]);
2069 ((char **)data)[index] = NULL;
2070 }
2071 if ((len = *strlength) > 0) {
2072 if (*pstring[len - 1] == '\r') {
2073 *pstring[len - 1] = 0;
2074 *strlength -= 1;
2075 }
2076 }
2077 if (*pstring[0] == '"')
2078 SDDS_GetToken2(*pstring, pstring, strlength, buffer, bufferSize);
2079 else
2080 strcpy(buffer, string);
2081 SDDS_InterpretEscapes(buffer);
2082 if (SDDS_CopyString(((char **)data) + index, buffer)) {
2083 if (buffer)
2084 free(buffer);
2085 return (1);
2086 }
2087 } else {
2088 if (field_length) {
2089 if (abs_field_length > *strlength) {
2090 strcpy(buffer, string);
2091 **pstring = 0;
2092 *strlength = 0;
2093 } else {
2094 strncpy(buffer, string, abs_field_length);
2095 buffer[abs_field_length] = 0;
2096 *pstring += abs_field_length;
2097 *strlength -= abs_field_length;
2098 }
2099 if (field_length < 0)
2100 SDDS_RemovePadding(buffer);
2101 } else if (SDDS_GetToken2(string, pstring, strlength, buffer, bufferSize) < 0)
2102 break;
2103 if (((char **)data)[index]) {
2104 free(((char **)data)[index]);
2105 ((char **)data)[index] = NULL;
2106 }
2107 SDDS_InterpretEscapes(buffer);
2108 if (SDDS_CopyString(((char **)data) + index, buffer)) {
2109 if (buffer)
2110 free(buffer);
2111 return (1);
2112 }
2113 }
2114 break;
2115 case SDDS_CHARACTER:
2116 SDDS_InterpretEscapes(buffer);
2117 *(((char *)data) + index) = buffer[0];
2118 if (buffer)
2119 free(buffer);
2120 return 1;
2121 default:
2122 SDDS_SetError("Unknown data type encountered (SDDS_ScanData2)");
2123 return (0);
2124 }
2125 SDDS_SetError("Unable to scan data--scanning or allocation error (SDDS_ScanData2)");
2126 return (0);
2127}
2128
2129/**
2130 * @brief Checks whether the SDDS dataset expects ASCII data input.
2131 *
2132 * This function determines if the provided SDDS dataset is expecting ASCII data.
2133 * The dataset expects ASCII data if it has columns, arrays, or parameters without fixed values.
2134 * If the dataset only contains parameters with fixed values and no columns or arrays, it does not expect ASCII data.
2135 *
2136 * @param SDDS_dataset Pointer to the SDDS dataset to check.
2137 *
2138 * @return Returns 1 if ASCII data is expected, or 0 if ASCII data is not expected.
2139 */
2140int32_t SDDS_AsciiDataExpected(SDDS_DATASET *SDDS_dataset) {
2141 int32_t i;
2142 if (SDDS_dataset->layout.n_columns || SDDS_dataset->layout.n_arrays)
2143 return (1);
2144 for (i = 0; i < SDDS_dataset->layout.n_parameters; i++)
2145 if (!SDDS_dataset->layout.parameter_definition[i].fixed_value)
2146 return (1);
2147 return (0);
2148}
2149
2150/**
2151 * @brief Updates the current ASCII page of an SDDS dataset with new data.
2152 *
2153 * This function updates the ASCII page of the provided SDDS dataset, appending any new rows that have been added since the last write.
2154 * It handles updating the row count in the file and ensures data consistency.
2155 * If the dataset is not currently writing a page, it initiates a new page write.
2156 *
2157 * @param SDDS_dataset Pointer to the SDDS dataset to update.
2158 * @param mode Mode flags that control the update behavior. Common modes include:
2159 * - `FLUSH_TABLE`: Flushes the data table after writing.
2160 *
2161 * @return Returns 1 on success, or 0 on error.
2162 * If an error occurs, an error message is set via `SDDS_SetError()`.
2163 *
2164 * @note This function cannot be used with compressed files (GZIP or LZMA). It requires a regular ASCII file.
2165 * It also handles updating internal state variables such as the number of rows written and the last row written.
2166 */
2167int32_t SDDS_UpdateAsciiPage(SDDS_DATASET *SDDS_dataset, uint32_t mode) {
2168 FILE *fp;
2169 int32_t code;
2170 int64_t i, rows, offset;
2171 SDDS_FILEBUFFER *fBuffer;
2172
2173#ifdef DEBUG
2174 fprintf(stderr, "%" PRId64 " virtual rows present, first=%" PRId32 "\n", SDDS_CountRowsOfInterest(SDDS_dataset), SDDS_dataset->first_row_in_mem);
2175#endif
2176 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_UpdateAsciiPage"))
2177 return (0);
2178#if defined(zLib)
2179 if (SDDS_dataset->layout.gzipFile) {
2180 SDDS_SetError("Unable to perform page updates on a gzip file (SDDS_UpdateAsciiPage)");
2181 return 0;
2182 }
2183#endif
2184 if (SDDS_dataset->layout.lzmaFile) {
2185 SDDS_SetError("Unable to perform page updates on an .lzma or .xz file (SDDS_UpdateAsciiPage)");
2186 return 0;
2187 }
2188 if (!SDDS_dataset->writing_page) {
2189 if (!(code = SDDS_WriteAsciiPage(SDDS_dataset)))
2190 return 0;
2191 if (mode & FLUSH_TABLE) {
2192 SDDS_FreeTableStrings(SDDS_dataset);
2193 SDDS_dataset->first_row_in_mem = SDDS_CountRowsOfInterest(SDDS_dataset);
2194 SDDS_dataset->last_row_written = -1;
2195 SDDS_dataset->n_rows = 0;
2196 }
2197 return code;
2198 }
2199 if (!(fp = SDDS_dataset->layout.fp)) {
2200 SDDS_SetError("Unable to update page--file pointer is NULL (SDDS_UpdateAsciiPage)");
2201 return (0);
2202 }
2203 fBuffer = &SDDS_dataset->fBuffer;
2204 if (!SDDS_FlushBuffer(fp, fBuffer)) {
2205 SDDS_SetError("Unable to write page--buffer flushing problem (SDDS_UpdateAsciiPage)");
2206 return 0;
2207 }
2208 offset = ftell(fp);
2209
2210 rows = SDDS_CountRowsOfInterest(SDDS_dataset) + SDDS_dataset->first_row_in_mem;
2211 if (rows == SDDS_dataset->n_rows_written)
2212 return (1);
2213 if (rows < SDDS_dataset->n_rows_written) {
2214 SDDS_SetError("Unable to update page--new number of rows less than previous number (SDDS_UpdateAsciiPage)");
2215 return (0);
2216 }
2217 if ((!SDDS_dataset->layout.data_mode.fixed_row_count) || (((rows + rows - SDDS_dataset->n_rows_written) / SDDS_dataset->layout.data_mode.fixed_row_increment) != (rows / SDDS_dataset->layout.data_mode.fixed_row_increment))) {
2218 if (!SDDS_dataset->layout.data_mode.no_row_counts) {
2219 if (SDDS_fseek(fp, SDDS_dataset->rowcount_offset, SEEK_SET) == -1) {
2220 SDDS_SetError("Unable to update page--failure doing fseek (SDDS_UpdateAsciiPage)");
2221 return (0);
2222 }
2223 /* overwrite the existing row count */
2224 if (SDDS_dataset->layout.data_mode.fixed_row_count) {
2225 if ((rows - SDDS_dataset->n_rows_written) + 1 > SDDS_dataset->layout.data_mode.fixed_row_increment) {
2226 SDDS_dataset->layout.data_mode.fixed_row_increment = (rows - SDDS_dataset->n_rows_written) + 1;
2227 }
2228 fprintf(fp, "%20" PRId64 "\n", ((rows / SDDS_dataset->layout.data_mode.fixed_row_increment) + 2) * SDDS_dataset->layout.data_mode.fixed_row_increment);
2229 } else
2230 fprintf(fp, "%20" PRId64 "\n", rows);
2231 if (SDDS_fseek(fp, offset, SEEK_SET) == -1) {
2232 SDDS_SetError("Unable to update page--failure doing fseek to end of page (SDDS_UpdateAsciiPage)");
2233 return (0);
2234 }
2235 }
2236 }
2237 for (i = SDDS_dataset->last_row_written + 1; i < SDDS_dataset->n_rows; i++)
2238 if (SDDS_dataset->row_flag[i])
2239 SDDS_WriteAsciiRow(SDDS_dataset, i, fp);
2240 if (!SDDS_FlushBuffer(fp, fBuffer)) {
2241 SDDS_SetError("Unable to write page--buffer flushing problem (SDDS_UpdateAsciiPage)");
2242 return 0;
2243 }
2244 SDDS_dataset->last_row_written = SDDS_dataset->n_rows - 1;
2245 SDDS_dataset->n_rows_written = rows;
2246 if (mode & FLUSH_TABLE) {
2247 SDDS_FreeTableStrings(SDDS_dataset);
2248 SDDS_dataset->first_row_in_mem = rows;
2249 SDDS_dataset->last_row_written = -1;
2250 SDDS_dataset->n_rows = 0;
2251 }
2252 return (1);
2253}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t SDDS_UpdateAsciiPage(SDDS_DATASET *SDDS_dataset, uint32_t mode)
Updates the current ASCII page of an SDDS dataset with new data.
int32_t SDDS_ScanData2(char *string, char **pstring, int32_t *strlength, int32_t type, int32_t field_length, void *data, int64_t index, int32_t is_parameter)
Scans a string and saves the parsed value into a data pointer, optimized for long strings.
int32_t SDDS_LZMAWriteAsciiArrays(SDDS_DATASET *SDDS_dataset, struct lzmafile *lzmafp)
Writes the arrays of an SDDS dataset in ASCII format to an LZMA compressed file.
Definition SDDS_ascii.c:680
int32_t SDDS_ReadAsciiPageDetailed(SDDS_DATASET *SDDS_dataset, int64_t sparse_interval, int64_t sparse_offset, int64_t last_rows, int32_t sparse_statistics)
Reads a detailed page of data from an ASCII file into an SDDS dataset with optional sparsity and stat...
int32_t SDDS_WriteAsciiPage(SDDS_DATASET *SDDS_dataset)
Writes a page of data in ASCII format to the SDDS dataset.
Definition SDDS_ascii.c:410
int32_t SDDS_LZMAWriteAsciiParameters(SDDS_DATASET *SDDS_dataset, struct lzmafile *lzmafp)
Writes the parameter data of an SDDS dataset in ASCII format to an LZMA compressed file.
Definition SDDS_ascii.c:565
int32_t SDDS_WriteAsciiRow(SDDS_DATASET *SDDS_dataset, int64_t row, FILE *fp)
Writes a single row of data in ASCII format to a file.
Definition SDDS_ascii.c:775
int32_t SDDS_WriteAsciiParameters(SDDS_DATASET *SDDS_dataset, FILE *fp)
Writes the parameter data of an SDDS dataset in ASCII format to a file.
Definition SDDS_ascii.c:531
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_AsciiDataExpected(SDDS_DATASET *SDDS_dataset)
Checks whether the SDDS dataset expects ASCII data input.
int32_t SDDS_ReadAsciiArrays(SDDS_DATASET *SDDS_dataset)
Reads the arrays from an ASCII file into the SDDS dataset.
int32_t SDDS_LZMAWriteAsciiRow(SDDS_DATASET *SDDS_dataset, int64_t row, struct lzmafile *lzmafp)
Writes a single row of data in ASCII format to an LZMA compressed file.
Definition SDDS_ascii.c:826
int32_t SDDS_ScanData(char *string, int32_t type, int32_t field_length, void *data, int64_t index, int32_t is_parameter)
Scans a string and saves the parsed value into a data pointer according to the specified data type.
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_WriteTypedValue(void *data, int64_t index, int32_t type, char *format, FILE *fp)
Writes a typed value to an ASCII file stream.
Definition SDDS_ascii.c:57
int32_t SDDS_ReadAsciiParameters(SDDS_DATASET *SDDS_dataset)
Reads the parameters from an ASCII file into the SDDS dataset.
Definition SDDS_ascii.c:927
int32_t SDDS_LZMAWriteTypedValue(void *data, int64_t index, int32_t type, char *format, struct lzmafile *lzmafp)
Writes a typed value to an LZMA compressed ASCII file stream.
Definition SDDS_ascii.c:180
int32_t SDDS_WriteAsciiArrays(SDDS_DATASET *SDDS_dataset, FILE *fp)
Writes the arrays of an SDDS dataset in ASCII format to a file.
Definition SDDS_ascii.c:635
void SDDS_SetReadRecoveryMode(SDDS_DATASET *SDDS_dataset, int32_t mode)
Sets the read recovery mode for an SDDS dataset.
int32_t SDDS_FlushBuffer(FILE *fp, SDDS_FILEBUFFER *fBuffer)
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_type_size[SDDS_NUM_TYPES]
Array of sizes for each supported data type.
Definition SDDS_data.c:62
int32_t SDDS_LengthenTable(SDDS_DATASET *SDDS_dataset, int64_t n_additional_rows)
int32_t SDDS_StartPage(SDDS_DATASET *SDDS_dataset, int64_t expected_n_rows)
int64_t SDDS_CountRowsOfInterest(SDDS_DATASET *SDDS_dataset)
Counts the number of rows marked as "of interest" in the current data table.
int64_t SDDS_GetRowLimit()
void SDDS_FreeTableStrings(SDDS_DATASET *SDDS_dataset)
Internal definitions and function declarations for SDDS with LZMA support.
char * fgetsLZMASkipCommentsResize(SDDS_DATASET *SDDS_dataset, char **s, int32_t *slen, struct lzmafile *lzmafp, char skip_char)
Reads a line from a LZMA-compressed file with dynamic buffer resizing while skipping comment lines.
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.
void SDDS_InterpretEscapes(char *s)
Interprets and converts escape sequences in a string.
void SDDS_SetError(char *error_text)
Records an error message in the SDDS error stack.
Definition SDDS_utils.c:379
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_CheckDataset(SDDS_DATASET *SDDS_dataset, const char *caller)
Validates the SDDS dataset pointer.
Definition SDDS_utils.c:552
void * SDDS_Malloc(size_t size)
Allocates memory of a specified size.
Definition SDDS_utils.c:639
void SDDS_ClearErrors()
Clears all recorded error messages from the SDDS error stack.
Definition SDDS_utils.c:318
int32_t SDDS_StringIsBlank(char *s)
Checks if a string is blank (contains only whitespace characters).
int32_t SDDS_GetToken(char *s, char *buffer, int32_t buflen)
Extracts the next token from a string, handling quoted substrings and escape characters.
ARRAY_DEFINITION * SDDS_CopyArrayDefinition(ARRAY_DEFINITION **target, ARRAY_DEFINITION *source)
Creates a copy of an array definition.
int32_t SDDS_CopyString(char **target, const char *source)
Copies a source string to a target string with memory allocation.
Definition SDDS_utils.c:856
void * SDDS_Realloc(void *old_ptr, size_t new_size)
Reallocates memory to a new size.
Definition SDDS_utils.c:677
int32_t SDDS_GetToken2(char *s, char **st, int32_t *strlength, char *buffer, int32_t buflen)
Extracts the next token from a string, handling quoted substrings and escape characters,...
char * fgetsSkipCommentsResize(SDDS_DATASET *SDDS_dataset, char **s, int32_t *slen, FILE *fp, char skip_char)
Reads a line from a file with dynamic buffer resizing while skipping comment lines.
void SDDS_RemovePadding(char *s)
Removes leading and trailing whitespace from a string.
int32_t SDDS_HasWhitespace(char *string)
Checks if a string contains any whitespace characters.
#define SDDS_ULONG
Identifier for the unsigned 32-bit integer data type.
Definition SDDStypes.h:67
#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_ULONG64
Identifier for the unsigned 64-bit integer data type.
Definition SDDStypes.h:55
#define SDDS_FLOATING_TYPE(type)
Checks if the given type identifier corresponds to a floating-point type.
Definition SDDStypes.h:124
#define SDDS_LONG
Identifier for the signed 32-bit integer data type.
Definition SDDStypes.h:61
#define SDDS_SHORT
Identifier for the signed short integer data type.
Definition SDDStypes.h:73
#define SDDS_CHARACTER
Identifier for the character data type.
Definition SDDStypes.h:91
#define SDDS_USHORT
Identifier for the unsigned short integer data type.
Definition SDDStypes.h:79
#define SDDS_DOUBLE
Identifier for the double data type.
Definition SDDStypes.h:37
#define SDDS_LONGDOUBLE
Identifier for the long double data type.
Definition SDDStypes.h:31
#define SDDS_LONG64
Identifier for the signed 64-bit integer data type.
Definition SDDStypes.h:49
double max_in_array(double *array, long n)
Finds the maximum value in an array of doubles.
Definition findMinMax.c:318
double min_in_array(double *array, long n)
Finds the minimum value in an array of doubles.
Definition findMinMax.c:336
long compute_average(double *value, double *data, int64_t n)
Computes the average of an array of doubles.
Definition median.c:144
long compute_median(double *value, double *x, long n)
Computes the median of an array of doubles.
Definition median.c:29