SDDS ToolKit Programs and Libraries for C and Python
All Classes Files Functions Variables Macros Pages
SDDS_output.c
Go to the documentation of this file.
1/**
2 * @file SDDS_output.c
3 * @brief This file contains the implementation of the SDDS output routines.
4 *
5 * This file provides functions for outputting data in the
6 * Self-Describing Data Sets (SDDS) format. It includes functions for
7 * creating and writing SDDS files, as well as functions for defining
8 * and appending data to the SDDS files.
9 *
10 * @copyright
11 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
12 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
13 *
14 * @license
15 * This file is distributed under the terms of the Software License Agreement
16 * found in the file LICENSE included with this distribution.
17 *
18 * @author M. Borland, C. Saunders, R. Soliday, H. Shang
19 */
20
21#include "SDDS.h"
22#include "SDDS_internal.h"
23#include "mdb.h"
24#include <ctype.h>
25
26#if defined(_WIN32)
27# include <fcntl.h>
28# include <io.h>
29# if defined(__BORLANDC__)
30# define _setmode(handle, amode) setmode(handle, amode)
31# endif
32#else
33# include <unistd.h>
34#endif
35
36#if SDDS_VERSION != 5
37# error "SDDS_VERSION does not match version of this file"
38#endif
39
40#undef DEBUG
41
42/* Allows "temporarily" closing a file. Use SDDS_ReconnectFile() to open it
43 * again in the same position. Updates the present page and flushes the
44 * table.
45 */
46
47#if SDDS_MPI_IO
48int32_t SDDS_MPI_DisconnectFile(SDDS_DATASET *SDDS_dataset);
49int32_t SDDS_MPI_ReconnectFile(SDDS_DATASET *SDDS_dataset);
50#endif
51
52/**
53 * @brief Disconnects the SDDS dataset from its associated file.
54 *
55 * This function terminates the connection between the SDDS dataset and the file it is currently linked to. It ensures that all pending data is flushed to the file, closes the file handle, and updates the dataset's internal state to reflect that it is no longer connected to any file.
56 *
57 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure to be disconnected.
58 *
59 * @return
60 * - @c 1 on successful disconnection.
61 * - @c 0 if an error occurred during disconnection. In this case, an error message is set internally.
62 *
63 * @note
64 * - If the dataset is already disconnected, this function will return an error.
65 * - This function is not thread-safe if the dataset is being accessed concurrently.
66 *
67 * @warning
68 * - Ensure that no further operations are performed on the dataset after disconnection unless it is reconnected.
69 */
70int32_t SDDS_DisconnectFile(SDDS_DATASET *SDDS_dataset) {
71#if SDDS_MPI_IO
72 if (SDDS_dataset->parallel_io)
73 return SDDS_MPI_DisconnectFile(SDDS_dataset);
74#endif
75 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_DisconnectFile"))
76 return 0;
77 if (!SDDS_dataset->layout.filename) {
78 SDDS_SetError("Can't disconnect file. No filename given. (SDDS_DisconnectFile)");
79 return 0;
80 }
81 if (SDDS_dataset->layout.gzipFile) {
82 SDDS_SetError("Can't disconnect file because it is a gzip file. (SDDS_DisconnectFile)");
83 return 0;
84 }
85 if (SDDS_dataset->layout.lzmaFile) {
86 SDDS_SetError("Can't disconnect file because it is a lzma or xz file. (SDDS_DisconnectFile)");
87 return 0;
88 }
89 if (SDDS_dataset->layout.disconnected) {
90 SDDS_SetError("Can't disconnect file. Already disconnected. (SDDS_DisconnectFile)");
91 return 0;
92 }
93 if (SDDS_dataset->page_started && !SDDS_UpdatePage(SDDS_dataset, FLUSH_TABLE)) {
94 SDDS_SetError("Can't disconnect file. Problem updating page. (SDDS_DisconnectFile)");
95 return 0;
96 }
97 if (fclose(SDDS_dataset->layout.fp)) {
98 SDDS_SetError("Can't disconnect file. Problem closing file. (SDDS_DisconnectFile)");
99 return 0;
100 }
101 SDDS_dataset->layout.disconnected = 1;
102 return 1;
103}
104
105/**
106 * @brief Reconnects the SDDS dataset to its previously associated file.
107 *
108 * This function re-establishes the connection between the SDDS dataset and the file it was previously linked to before being disconnected. It opens the file in read/write mode, seeks to the appropriate position, and updates the dataset's internal state to reflect that it is connected.
109 *
110 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure to be reconnected.
111 *
112 * @return
113 * - @c 1 on successful reconnection.
114 * - @c 0 if an error occurred during reconnection. In this case, an error message is set internally.
115 *
116 * @pre
117 * - The dataset must have been previously disconnected using SDDS_DisconnectFile.
118 * - The dataset must have a valid filename set.
119 *
120 * @note
121 * - Reconnection will fail if the file is not accessible or if the dataset was not properly disconnected.
122 *
123 * @warning
124 * - Ensure that the file has not been modified externally in a way that could disrupt the dataset's state.
125 */
126int32_t SDDS_ReconnectFile(SDDS_DATASET *SDDS_dataset) {
127#if SDDS_MPI_IO
128 if (SDDS_dataset->parallel_io)
129 return SDDS_MPI_ReconnectFile(SDDS_dataset);
130#endif
131 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_ReconnectFile"))
132 return 0;
133 if (!SDDS_dataset->layout.disconnected || !SDDS_dataset->layout.filename) {
134 SDDS_SetError("Can't reconnect file. Not disconnected or missing filename. (SDDS_ReconnectFile)");
135 return 0;
136 }
137 if (!(SDDS_dataset->layout.fp = fopen(SDDS_dataset->layout.filename, FOPEN_READ_AND_WRITE_MODE))) {
138 char s[1024];
139 sprintf(s, "Unable to open file %s (SDDS_ReconnectFile)", SDDS_dataset->layout.filename);
140 SDDS_SetError(s);
141 return 0;
142 }
143 if (fseek(SDDS_dataset->layout.fp, 0, 2) == -1) {
144 SDDS_SetError("Can't reconnect file. Fseek failed. (SDDS_ReconnectFile)");
145 return 0;
146 }
147 SDDS_dataset->original_layout.fp = SDDS_dataset->layout.fp;
148 SDDS_dataset->layout.disconnected = 0;
149 return 1;
150}
151
152/**
153 * @brief Disconnects the input file from the SDDS dataset.
154 *
155 * This function severs the connection between the SDDS dataset and its input file. It closes the file handle, updates the dataset's internal state to indicate disconnection, and returns the current file position before closing. After disconnection, the dataset cannot read further data from the input file until it is reconnected.
156 *
157 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure whose input file is to be disconnected.
158 *
159 * @return
160 * - On success, returns the current file position (as obtained by @c ftell) before disconnection.
161 * - On failure, returns @c -1 and sets an internal error message.
162 *
163 * @note
164 * - This function cannot disconnect compressed input files (gzip, lzma, xz).
165 * - Attempting to disconnect an already disconnected dataset will result in an error.
166 *
167 * @warning
168 * - Ensure that no further read operations are performed on the dataset after disconnection unless it is reconnected.
169 */
171 long position;
172#if SDDS_MPI_IO
173 if (SDDS_dataset->parallel_io) {
174 SDDS_SetError("Error: MPI mode not supported yet in SDDS_DisconnectInputFile");
175 return -1;
176 }
177#endif
178 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_DisconnectInputFile"))
179 return -1;
180 if (!SDDS_dataset->layout.filename) {
181 SDDS_SetError("Can't disconnect file. No filename given. (SDDS_DisconnectInputFile)");
182 return -1;
183 }
184 if (SDDS_dataset->layout.gzipFile) {
185 SDDS_SetError("Can't disconnect file because it is a gzip file. (SDDS_DisconnectInputFile)");
186 return -1;
187 }
188 if (SDDS_dataset->layout.lzmaFile) {
189 SDDS_SetError("Can't disconnect file because it is a lzma or xz file. (SDDS_DisconnectInputFile)");
190 return -1;
191 }
192 if (SDDS_dataset->layout.disconnected) {
193 SDDS_SetError("Can't disconnect file. Already disconnected. (SDDS_DisconnectInputFile)");
194 return -1;
195 }
196 position = ftell(SDDS_dataset->layout.fp);
197 if (fclose(SDDS_dataset->layout.fp)) {
198 SDDS_SetError("Can't disconnect file. Problem closing file. (SDDS_DisconnectInputFile)");
199 return -1;
200 }
201 SDDS_dataset->layout.disconnected = 1;
202 return position;
203}
204
205/**
206 * @brief Reconnects the input file for the SDDS dataset at a specified position.
207 *
208 * This function re-establishes the connection between the SDDS dataset and its input file, positioning the file pointer at the specified byte offset. This allows the dataset to resume reading from a specific location within the input file.
209 *
210 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure to reconnect.
211 * @param[in] position The byte offset position in the input file where reconnection should occur.
212 *
213 * @return
214 * - @c 1 on successful reconnection.
215 * - @c 0 on failure. In this case, an internal error message is set.
216 *
217 * @pre
218 * - The dataset must have been previously disconnected using SDDS_DisconnectInputFile.
219 * - The dataset must have a valid filename set.
220 * - The specified position must be valid within the input file.
221 *
222 * @note
223 * - Reconnection will fail if the input file is compressed (gzip, lzma, xz).
224 * - The function seeks to the specified position after opening the file.
225 *
226 * @warning
227 * - Ensure that the specified position does not disrupt the dataset's data integrity.
228 */
229int32_t SDDS_ReconnectInputFile(SDDS_DATASET *SDDS_dataset, long position) {
230#if SDDS_MPI_IO
231 if (SDDS_dataset->parallel_io) {
232 SDDS_SetError("Error: MPI mode not supported yet in SDDS_ReconnectInputFile");
233 return 0;
234 }
235#endif
236 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_ReconnectInputFile"))
237 return 0;
238 if (!SDDS_dataset->layout.disconnected || !SDDS_dataset->layout.filename) {
239 SDDS_SetError("Can't reconnect file. Not disconnected or missing filename. (SDDS_ReconnectInputFile)");
240 return 0;
241 }
242 if (!(SDDS_dataset->layout.fp = fopen(SDDS_dataset->layout.filename, FOPEN_READ_MODE))) {
243 char s[1024];
244 sprintf(s, "Unable to open file %s (SDDS_ReconnectInputFile)", SDDS_dataset->layout.filename);
245 SDDS_SetError(s);
246 return 0;
247 }
248 if (fseek(SDDS_dataset->layout.fp, position, SEEK_SET) == -1) {
249 SDDS_SetError("Can't reconnect file. Fseek failed. (SDDS_ReconnectInputFile)");
250 return 0;
251 }
252 SDDS_dataset->original_layout.fp = SDDS_dataset->layout.fp;
253 SDDS_dataset->layout.disconnected = 0;
254 return 1;
255}
256
257/* appends to a file by adding a new page */
258
259/**
260 * @brief Initializes the SDDS dataset for appending data by adding a new page to an existing file.
261 *
262 * This function prepares the SDDS dataset for appending additional data to an existing SDDS file by initializing necessary data structures, verifying file integrity, and setting up for the addition of a new data page. It ensures that the file is writable, not compressed, and properly locked to prevent concurrent modifications.
263 *
264 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure to be initialized for appending.
265 * @param[in] filename The name of the existing SDDS file to which data will be appended. If @c NULL, data will be appended to standard input.
266 *
267 * @return
268 * - @c 1 on successful initialization.
269 * - @c 0 on error. In this case, an internal error message is set describing the failure.
270 *
271 * @pre
272 * - The specified file must exist and be a valid SDDS file.
273 * - The file must not be compressed (gzip, lzma, xz) and must be accessible for read and write operations.
274 *
275 * @post
276 * - The dataset is ready to append data as a new page.
277 * - The file is locked to prevent concurrent writes.
278 *
279 * @note
280 * - If @c filename is @c NULL, the dataset will append data from standard input.
281 * - The function sets internal flags indicating whether the file was previously empty or had existing data.
282 *
283 * @warning
284 * - Appending to a compressed file is not supported and will result in an error.
285 * - Ensure that no other processes are accessing the file simultaneously to avoid conflicts.
286 */
287int32_t SDDS_InitializeAppend(SDDS_DATASET *SDDS_dataset, const char *filename) {
288 /* char *ptr, *datafile, *headerfile; */
289 char s[SDDS_MAXLINE];
290 int64_t endOfLayoutOffset, endOfFileOffset;
291 char *extension;
292
293 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_InitializeAppend"))
294 return 0;
295 if (!SDDS_ZeroMemory((void *)SDDS_dataset, sizeof(SDDS_DATASET))) {
296 sprintf(s, "Unable to initialize input for file %s--can't zero SDDS_DATASET structure (SDDS_InitializeAppend)", filename);
297 SDDS_SetError(s);
298 return 0;
299 }
300 SDDS_dataset->layout.popenUsed = SDDS_dataset->layout.gzipFile = SDDS_dataset->layout.lzmaFile = SDDS_dataset->layout.disconnected = 0;
301 SDDS_dataset->layout.depth = SDDS_dataset->layout.data_command_seen = SDDS_dataset->layout.commentFlags = SDDS_dataset->deferSavingLayout = 0;
302 if (!filename)
303 SDDS_dataset->layout.filename = NULL;
304 else if (!SDDS_CopyString(&SDDS_dataset->layout.filename, filename)) {
305 sprintf(s, "Memory allocation failure initializing file %s (SDDS_InitializeAppend)", filename);
306 SDDS_SetError(s);
307 return 0;
308 } else if ((extension = strrchr(filename, '.')) && ((strcmp(extension, ".gz") == 0) || (strcmp(extension, ".lzma") == 0) || (strcmp(extension, ".xz") == 0))) {
309 sprintf(s, "Cannot append to a compressed file %s (SDDS_InitializeAppend)", filename);
310 SDDS_SetError(s);
311 return 0;
312 }
313
314 SDDS_dataset->layout.popenUsed = 0;
315 if (!filename) {
316#if defined(_WIN32)
317 if (_setmode(_fileno(stdin), _O_BINARY) == -1) {
318 sprintf(s, "unable to set stdin to binary mode");
319 SDDS_SetError(s);
320 return 0;
321 }
322#endif
323 SDDS_dataset->layout.fp = stdin;
324 } else {
325 if (SDDS_FileIsLocked(filename)) {
326 sprintf(s, "unable to open file %s for appending--file is locked (SDDS_InitializeAppend)", filename);
327 SDDS_SetError(s);
328 return 0;
329 }
330 if (!(SDDS_dataset->layout.fp = fopen(filename, FOPEN_READ_AND_WRITE_MODE))) {
331 sprintf(s, "Unable to open file %s for appending (SDDS_InitializeAppend)", filename);
332 SDDS_SetError(s);
333 return 0;
334 }
335 if (!SDDS_LockFile(SDDS_dataset->layout.fp, filename, "SDDS_InitializeAppend"))
336 return 0;
337 }
338
339 if (!SDDS_ReadLayout(SDDS_dataset, SDDS_dataset->layout.fp))
340 return 0;
341 endOfLayoutOffset = ftell(SDDS_dataset->layout.fp);
342 if (SDDS_dataset->layout.n_columns &&
343 (!(SDDS_dataset->column_flag = (int32_t *)SDDS_Malloc(sizeof(int32_t) * SDDS_dataset->layout.n_columns)) ||
344 !(SDDS_dataset->column_order = (int32_t *)SDDS_Malloc(sizeof(int32_t) * SDDS_dataset->layout.n_columns)) ||
345 !SDDS_SetMemory(SDDS_dataset->column_flag, SDDS_dataset->layout.n_columns, SDDS_LONG, (int32_t)1, (int32_t)0) ||
346 !SDDS_SetMemory(SDDS_dataset->column_order, SDDS_dataset->layout.n_columns, SDDS_LONG, (int32_t)0, (int32_t)1))) {
347 SDDS_SetError("Unable to initialize input--memory allocation failure (SDDS_InitializeAppend)");
348 return 0;
349 }
350 if (fseek(SDDS_dataset->layout.fp, 0, 2) == -1) {
351 SDDS_SetError("Unable to initialize append--seek failure (SDDS_InitializeAppend)");
352 return 0;
353 }
354 endOfFileOffset = ftell(SDDS_dataset->layout.fp);
355 if (endOfFileOffset == endOfLayoutOffset)
356 SDDS_dataset->file_had_data = 0; /* appending to empty file */
357 else
358 SDDS_dataset->file_had_data = 1; /* appending to nonempty file */
359 SDDS_dataset->layout.layout_written = 1; /* its already in the file */
360 SDDS_dataset->mode = SDDS_WRITEMODE; /*writing */
361 return 1;
362}
363
364/**
365 * @brief Initializes the SDDS dataset for appending data to the last page of an existing file.
366 *
367 * This function sets up the SDDS dataset to append additional data rows to the last page of an existing SDDS file. It reads the existing file layout, determines the current state of data (including row counts), and prepares internal data structures to accommodate new data. The function also handles file locking, buffer management, and ensures that the file is ready for efficient data appending based on the specified update interval.
368 *
369 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure to be initialized for appending.
370 * @param[in] filename The name of the existing SDDS file to which data will be appended. If @c NULL, data will be appended to standard input.
371 * @param[in] updateInterval The number of rows to write before the dataset reallocates memory or flushes data. This parameter controls the frequency of memory allocation and disk I/O operations during the append process.
372 * @param[out] rowsPresentReturn Pointer to an @c int64_t variable where the function will store the number of rows present in the dataset after initialization. This provides information on the current dataset size.
373 *
374 * @return
375 * - @c 1 on successful initialization.
376 * - @c 0 on error. In this case, an internal error message is set detailing the issue.
377 *
378 * @pre
379 * - The specified file must exist and be a valid SDDS file.
380 * - The file must not be compressed (gzip, lzma, xz) and must be accessible for read and write operations.
381 *
382 * @post
383 * - The dataset is configured to append data to the last page of the file.
384 * - Internal structures are initialized to track row counts and manage memory efficiently based on the update interval.
385 * - The file is locked to prevent concurrent modifications.
386 * - @c rowsPresentReturn is updated with the current number of rows in the dataset.
387 *
388 * @note
389 * - If @c filename is @c NULL, data will be appended from standard input.
390 * - The function sets internal flags indicating whether the file already contained data prior to appending.
391 *
392 * @warning
393 * - Appending to a compressed file is not supported and will result in an error.
394 * - Ensure that no other processes are accessing the file simultaneously to avoid conflicts.
395 */
396int32_t SDDS_InitializeAppendToPage(SDDS_DATASET *SDDS_dataset, const char *filename, int64_t updateInterval, int64_t *rowsPresentReturn) {
397 /* char *ptr, *datafile, *headerfile; */
398 char s[SDDS_MAXLINE];
399 int64_t endOfLayoutOffset, endOfFileOffset, rowCountOffset, offset;
400 int32_t rowsPresent32;
401 int64_t rowsPresent;
402 char *extension;
403 int32_t previousBufferSize;
404
405 *rowsPresentReturn = -1;
406 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_InitializeAppendToPage"))
407 return 0;
408 if (!SDDS_ZeroMemory((void *)SDDS_dataset, sizeof(SDDS_DATASET))) {
409 sprintf(s, "Unable to initialize input for file %s--can't zero SDDS_DATASET structure (SDDS_InitializeAppendToPage)", filename);
410 SDDS_SetError(s);
411 return 0;
412 }
413 SDDS_dataset->layout.popenUsed = SDDS_dataset->layout.gzipFile = SDDS_dataset->layout.lzmaFile = SDDS_dataset->layout.disconnected = 0;
414 SDDS_dataset->layout.depth = SDDS_dataset->layout.data_command_seen = SDDS_dataset->layout.commentFlags = SDDS_dataset->deferSavingLayout = 0;
415 if (!filename)
416 SDDS_dataset->layout.filename = NULL;
417 else if (!SDDS_CopyString(&SDDS_dataset->layout.filename, filename)) {
418 sprintf(s, "Memory allocation failure initializing file %s (SDDS_InitializeAppendToPage)", filename);
419 SDDS_SetError(s);
420 return 0;
421 } else if ((extension = strrchr(filename, '.')) && ((strcmp(extension, ".gz") == 0) || (strcmp(extension, ".lzma") == 0) || (strcmp(extension, ".xz") == 0))) {
422 sprintf(s, "Cannot append to a compressed file %s (SDDS_InitializeAppendToPage)", filename);
423 SDDS_SetError(s);
424 return 0;
425 }
426
427 if (!filename) {
428#if defined(_WIN32)
429 if (_setmode(_fileno(stdin), _O_BINARY) == -1) {
430 sprintf(s, "unable to set stdin to binary mode");
431 SDDS_SetError(s);
432 return 0;
433 }
434#endif
435 SDDS_dataset->layout.fp = stdin;
436 } else {
437 if (SDDS_FileIsLocked(filename)) {
438 sprintf(s, "unable to open file %s for appending--file is locked (SDDS_InitializeAppendToPage)", filename);
439 SDDS_SetError(s);
440 return 0;
441 }
442 if (!(SDDS_dataset->layout.fp = fopen(filename, FOPEN_READ_AND_WRITE_MODE))) {
443 sprintf(s, "Unable to open file %s for appending (SDDS_InitializeAppendToPage)", filename);
444 SDDS_SetError(s);
445 return 0;
446 }
447 if (!SDDS_LockFile(SDDS_dataset->layout.fp, filename, "SDDS_InitializeAppendToPage")) {
448 return 0;
449 }
450 }
451
452 if (!SDDS_ReadLayout(SDDS_dataset, SDDS_dataset->layout.fp)) {
453 return 0;
454 }
455 endOfLayoutOffset = ftell(SDDS_dataset->layout.fp);
456 if (SDDS_dataset->layout.n_columns &&
457 (!(SDDS_dataset->column_flag = (int32_t *)SDDS_Malloc(sizeof(int32_t) * SDDS_dataset->layout.n_columns)) ||
458 !(SDDS_dataset->column_order = (int32_t *)SDDS_Malloc(sizeof(int32_t) * SDDS_dataset->layout.n_columns)) ||
459 !SDDS_SetMemory(SDDS_dataset->column_flag, SDDS_dataset->layout.n_columns, SDDS_LONG, (int32_t)1, (int32_t)0) ||
460 !SDDS_SetMemory(SDDS_dataset->column_order, SDDS_dataset->layout.n_columns, SDDS_LONG, (int32_t)0, (int32_t)1))) {
461 SDDS_SetError("Unable to initialize input--memory allocation failure (SDDS_InitializeAppendToPage)");
462 return 0;
463 }
464 rowCountOffset = -1;
465 rowsPresent = 0;
466#ifdef DEBUG
467 fprintf(stderr, "Data mode is %s\n", SDDS_data_mode[SDDS_dataset->layout.data_mode.mode - 1]);
468#endif
469 SDDS_dataset->pagecount_offset = NULL;
470 previousBufferSize = SDDS_SetDefaultIOBufferSize(0);
471 if (!SDDS_dataset->layout.data_mode.no_row_counts) {
472 /* read pages to get to the last page */
473 while (SDDS_ReadPageSparse(SDDS_dataset, 0, 10000, 0, 0) > 0) {
474 rowCountOffset = SDDS_dataset->rowcount_offset;
475 offset = ftell(SDDS_dataset->layout.fp);
476 fseek(SDDS_dataset->layout.fp, rowCountOffset, 0);
477
478 if (SDDS_dataset->layout.data_mode.mode == SDDS_BINARY) {
479 if (fread(&rowsPresent32, sizeof(rowsPresent32), 1, SDDS_dataset->layout.fp) == 0) {
480 SDDS_SetError("Error: row count not present or not correct length");
481 return 0;
482 }
483 if (SDDS_dataset->swapByteOrder) {
484 SDDS_SwapLong(&rowsPresent32);
485 }
486 if (rowsPresent32 == INT32_MIN) {
487 if (fread(&rowsPresent, sizeof(rowsPresent), 1, SDDS_dataset->layout.fp) == 0) {
488 SDDS_SetError("Error: row count not present or not correct length");
489 return 0;
490 }
491 if (SDDS_dataset->swapByteOrder) {
492 SDDS_SwapLong64(&rowsPresent);
493 }
494 } else {
495 rowsPresent = rowsPresent32;
496 }
497 } else {
498 char buffer[30];
499 if (!fgets(buffer, 30, SDDS_dataset->layout.fp) || strlen(buffer) != 21 || sscanf(buffer, "%" SCNd64, &rowsPresent) != 1) {
500#ifdef DEBUG
501 fprintf(stderr, "buffer for row count data: >%s<\n", buffer);
502#endif
503 SDDS_SetError("Unable to initialize input--row count not present or not correct length (SDDS_InitializeAppendToPage)");
504 SDDS_SetDefaultIOBufferSize(previousBufferSize);
505 return 0;
506 }
507 }
508 fseek(SDDS_dataset->layout.fp, offset, 0);
509#ifdef DEBUG
510 fprintf(stderr, "%" PRId64 " rows present\n", rowsPresent);
511#endif
512 }
513 if (rowCountOffset == -1) {
514 SDDS_SetDefaultIOBufferSize(previousBufferSize);
515 SDDS_SetError("Unable to initialize input--problem finding row count offset (SDDS_InitializeAppendToPage)");
516 return 0;
517 }
518 }
519 SDDS_SetDefaultIOBufferSize(previousBufferSize);
520 SDDS_dataset->fBuffer.bytesLeft = SDDS_dataset->fBuffer.bufferSize;
521
522#ifdef DEBUG
523 fprintf(stderr, "Starting page with %" PRId64 " rows\n", updateInterval);
524#endif
525 if (!SDDS_StartPage(SDDS_dataset, updateInterval)) {
526 SDDS_SetError("Unable to initialize input--problem starting page (SDDS_InitializeAppendToPage)");
527 return 0;
528 }
529
530 /* seek to the end of the file */
531 if (fseek(SDDS_dataset->layout.fp, 0, 2) == -1) {
532 SDDS_SetError("Unable to initialize append--seek failure (SDDS_InitializeAppendToPage)");
533 return 0;
534 }
535 endOfFileOffset = ftell(SDDS_dataset->layout.fp);
536 if (endOfFileOffset == endOfLayoutOffset)
537 SDDS_dataset->file_had_data = 0; /* appending to empty file */
538 else {
539 SDDS_dataset->file_had_data = 1; /* appending to nonempty file */
540 if (rowCountOffset != -1) {
541 SDDS_dataset->rowcount_offset = rowCountOffset;
542 SDDS_dataset->n_rows_written = rowsPresent;
543 SDDS_dataset->first_row_in_mem = rowsPresent;
544 SDDS_dataset->last_row_written = -1;
545 *rowsPresentReturn = rowsPresent;
546 SDDS_dataset->writing_page = 1;
547 }
548 }
549#ifdef DEBUG
550 fprintf(stderr, "rowcount_offset = %" PRId64 ", n_rows_written = %" PRId64 ", first_row_in_mem = %" PRId64 ", last_row_written = %" PRId64 "\n", SDDS_dataset->rowcount_offset, SDDS_dataset->n_rows_written, SDDS_dataset->first_row_in_mem, SDDS_dataset->last_row_written);
551#endif
552 SDDS_dataset->page_number = 1;
553 SDDS_dataset->layout.layout_written = 1; /* its already in the file */
554 SDDS_dataset->mode = SDDS_WRITEMODE; /*writing */
555 return 1;
556}
557
558/**
559 * @brief Initializes the SDDS output dataset.
560 *
561 * This function sets up the SDDS dataset for output operations by initializing the necessary structures,
562 * configuring the data mode (ASCII, Binary, or Parallel), handling file opening (including compressed files),
563 * and setting dataset metadata such as description and contents. It ensures that the dataset is ready
564 * for writing data according to the specified parameters.
565 *
566 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure to be initialized for output.
567 * @param[in] data_mode The data mode for the output dataset. Acceptable values are:
568 * - @c SDDS_ASCII: ASCII text format.
569 * - @c SDDS_BINARY: Binary format.
570 * - @c SDDS_PARALLEL: Parallel processing mode.
571 * @param[in] lines_per_row The number of lines per row in the output dataset. This parameter is used
572 * only for ASCII output and is typically set to 1.
573 * @param[in] description A string containing the description of the output dataset. Pass @c NULL
574 * if no description is desired.
575 * @param[in] contents A string detailing the contents of the output dataset. Pass @c NULL if no contents are desired.
576 * @param[in] filename The name of the file to which the dataset will be written. If @c NULL, the dataset
577 * will be written to standard output.
578 *
579 * @return
580 * - @c 1 on successful initialization.
581 * - @c 0 if an error occurred during initialization. In this case, an error message is set internally.
582 *
583 * @pre
584 * - The @c SDDS_dataset pointer must be valid and point to a properly allocated SDDS_DATASET structure.
585 *
586 * @post
587 * - The dataset is configured for output according to the specified parameters.
588 * - The output file is opened and locked if a filename is provided.
589 * - The dataset's internal state reflects the initialization status.
590 *
591 * @note
592 * - When using compressed file formats (e.g., .gz, .lzma, .xz), the output mode is forced to binary.
593 * - Environment variable @c SDDS_OUTPUT_ENDIANESS can be set to "big" or "little" to declare the byte order.
594 * - For ASCII output, ensure that @c lines_per_row is set appropriately to match the data structure.
595 *
596 * @warning
597 * - Appending to compressed files is not supported and will result in an error.
598 * - Ensure that the specified file is not locked by another process to avoid initialization failures.
599 * - Changing data mode after initialization is not supported and may lead to undefined behavior.
600 */
601int32_t SDDS_InitializeOutput(SDDS_DATASET *SDDS_dataset, int32_t data_mode, int32_t lines_per_row, const char *description, const char *contents, const char *filename) {
602 char s[SDDS_MAXLINE];
603 char *extension;
604 char *outputEndianess = NULL;
605
606 if (data_mode == SDDS_PARALLEL)
607 return SDDS_Parallel_InitializeOutput(SDDS_dataset, description, contents, filename);
608
609 if (sizeof(gzFile) != sizeof(void *)) {
610 SDDS_SetError("gzFile is not the same size as void *, possible corruption of the SDDS_LAYOUT structure");
611 return (0);
612 }
613 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_InitializeOutput"))
614 return 0;
615 if (!SDDS_ZeroMemory((void *)SDDS_dataset, sizeof(SDDS_DATASET))) {
616 sprintf(s, "Unable to initialize output for file %s--can't zero SDDS_DATASET structure (SDDS_InitializeOutput)", filename);
617 SDDS_SetError(s);
618 return 0;
619 }
620 SDDS_dataset->layout.popenUsed = SDDS_dataset->layout.gzipFile = SDDS_dataset->layout.lzmaFile = SDDS_dataset->layout.disconnected = 0;
621 SDDS_dataset->layout.depth = SDDS_dataset->layout.data_command_seen = SDDS_dataset->layout.commentFlags = SDDS_dataset->deferSavingLayout = 0;
622 if (!filename) {
623#if defined(_WIN32)
624 if (_setmode(_fileno(stdout), _O_BINARY) == -1) {
625 sprintf(s, "unable to set stdout to binary mode");
626 SDDS_SetError(s);
627 return 0;
628 }
629#endif
630 SDDS_dataset->layout.fp = stdout;
631 } else {
632 if (SDDS_FileIsLocked(filename)) {
633 sprintf(s, "unable to open file %s for writing--file is locked (SDDS_InitializeOutput)", filename);
634 SDDS_SetError(s);
635 return 0;
636 }
637 if ((extension = strrchr(filename, '.')) && ((strcmp(extension, ".xz") == 0) || (strcmp(extension, ".lzma") == 0))) {
638 SDDS_dataset->layout.lzmaFile = 1;
639 data_mode = SDDS_BINARY; /* force binary mode for output lzma files. The reading of ascii lzma files is flaky because of the lzma_gets command, plus the output files will be much smaller */
640 if (!(SDDS_dataset->layout.lzmafp = lzma_open(filename, FOPEN_WRITE_MODE))) {
641 sprintf(s, "Unable to open file %s for writing (SDDS_InitializeOutput)", filename);
642 SDDS_SetError(s);
643 return 0;
644 }
645 SDDS_dataset->layout.fp = SDDS_dataset->layout.lzmafp->fp;
646 } else {
647 if (!(SDDS_dataset->layout.fp = fopen(filename, FOPEN_WRITE_MODE))) {
648 sprintf(s, "Unable to open file %s for writing (SDDS_InitializeOutput)", filename);
649 SDDS_SetError(s);
650 return 0;
651 }
652 }
653 if (!SDDS_LockFile(SDDS_dataset->layout.fp, filename, "SDDS_InitializeOutput"))
654 return 0;
655#if defined(zLib)
656 if ((extension = strrchr(filename, '.')) && (strcmp(extension, ".gz") == 0)) {
657 SDDS_dataset->layout.gzipFile = 1;
658 if ((SDDS_dataset->layout.gzfp = gzdopen(fileno(SDDS_dataset->layout.fp), FOPEN_WRITE_MODE)) == NULL) {
659 sprintf(s, "Unable to open compressed file %s for writing (SDDS_InitializeOutput)", filename);
660 SDDS_SetError(s);
661 return 0;
662 }
663 }
664#endif
665 }
666 SDDS_dataset->page_number = SDDS_dataset->page_started = 0;
667 SDDS_dataset->file_had_data = SDDS_dataset->layout.layout_written = 0;
668 if (!filename)
669 SDDS_dataset->layout.filename = NULL;
670 else if (!SDDS_CopyString(&SDDS_dataset->layout.filename, filename)) {
671 sprintf(s, "Memory allocation failure initializing file %s (SDDS_InitializeOutput)", filename);
672 SDDS_SetError(s);
673 return 0;
674 }
675 if ((outputEndianess = getenv("SDDS_OUTPUT_ENDIANESS"))) {
676 if (strncmp(outputEndianess, "big", 3) == 0)
677 SDDS_dataset->layout.byteOrderDeclared = SDDS_BIGENDIAN;
678 else if (strncmp(outputEndianess, "little", 6) == 0)
679 SDDS_dataset->layout.byteOrderDeclared = SDDS_LITTLEENDIAN;
680 } else {
681 SDDS_dataset->layout.byteOrderDeclared = SDDS_IsBigEndianMachine() ? SDDS_BIGENDIAN : SDDS_LITTLEENDIAN;
682 }
683
684 if (data_mode < 0 || data_mode > SDDS_NUM_DATA_MODES) {
685 sprintf(s, "Invalid data mode for file %s (SDDS_InitializeOutput)", filename ? filename : "stdout");
686 SDDS_SetError(s);
687 return 0;
688 }
689 if (data_mode == SDDS_ASCII && lines_per_row <= 0) {
690 sprintf(s, "Invalid number of lines per row for file %s (SDDS_InitializeOutput)", filename ? filename : "stdout");
691 SDDS_SetError(s);
692 return 0;
693 }
694 SDDS_dataset->layout.version = SDDS_VERSION;
695 SDDS_dataset->layout.data_mode.mode = data_mode;
696 SDDS_dataset->layout.data_mode.lines_per_row = lines_per_row;
697 SDDS_dataset->layout.data_mode.no_row_counts = 0;
698 SDDS_dataset->layout.data_mode.fixed_row_count = 0;
699 SDDS_dataset->layout.data_mode.fsync_data = 0;
700 SDDS_dataset->layout.data_mode.column_memory_mode = DEFAULT_COLUMN_MEMORY_MODE;
701 /*This is only temporary, soon the default will be column major order */
702 SDDS_dataset->layout.data_mode.column_major = 0;
703 if (description && !SDDS_CopyString(&SDDS_dataset->layout.description, description)) {
704 sprintf(s, "Memory allocation failure initializing file %s (SDDS_InitializeOutput)", filename ? filename : "stdout");
705 SDDS_SetError(s);
706 return 0;
707 }
708 if (contents && !SDDS_CopyString(&SDDS_dataset->layout.contents, contents)) {
709 sprintf(s, "Memory allocation failure initializing file %s (SDDS_InitializeOutput)", filename ? filename : "stdout");
710 SDDS_SetError(s);
711 return 0;
712 }
713 SDDS_dataset->mode = SDDS_WRITEMODE; /*writing */
714 SDDS_dataset->pagecount_offset = NULL;
715 SDDS_dataset->parallel_io = 0;
716 return (1);
717}
718
719/**
720 * @brief Initializes the SDDS output dataset for parallel processing.
721 *
722 * This function configures the SDDS dataset for parallel output operations. It sets the dataset's
723 * description, contents, and filename, ensuring that the output is in binary mode as parallel
724 * processing with compressed files is not supported. The function initializes necessary structures
725 * and prepares the dataset for efficient parallel data writing.
726 *
727 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure to be initialized for parallel output.
728 * @param[in] description A string containing the description of the dataset. Pass @c NULL if no description is desired.
729 * @param[in] contents A string detailing the contents of the dataset. Pass @c NULL if no contents are desired.
730 * @param[in] filename The name of the file to which the dataset will be written. If @c NULL, the dataset
731 * will be written to standard output.
732 *
733 * @return
734 * - @c 1 on successful initialization.
735 * - @c 0 if an error occurred during initialization. In this case, an error message is set internally.
736 *
737 * @pre
738 * - The @c SDDS_dataset pointer must be valid and point to a properly allocated SDDS_DATASET structure.
739 * - The dataset memory should have been zeroed prior to calling this function (handled externally).
740 *
741 * @post
742 * - The dataset is configured for parallel binary output.
743 * - The dataset's internal state reflects the initialization status.
744 *
745 * @note
746 * - Parallel output does not support compressed file formats.
747 * - The output mode is set to binary regardless of the specified data mode.
748 * - Environment variable @c SDDS_OUTPUT_ENDIANESS can be set to "big" or "little" to declare the byte order.
749 *
750 * @warning
751 * - Attempting to use parallel initialization with compressed files will result in an error.
752 * - Ensure that no other processes are accessing the file simultaneously to prevent initialization failures.
753 */
754int32_t SDDS_Parallel_InitializeOutput(SDDS_DATASET *SDDS_dataset, const char *description, const char *contents, const char *filename) {
755 /* SDDS_DATASET *SDDS_dataset; */
756 char s[SDDS_MAXLINE];
757 char *outputEndianess = NULL;
758
759 /* SDDS_dataset = &(MPI_dataset->sdds_dataset); */
760 if (sizeof(gzFile) != sizeof(void *)) {
761 SDDS_SetError("gzFile is not the same size as void *, possible corruption of the SDDS_LAYOUT structure");
762 return (0);
763 }
764 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_InitializeOutput"))
765 return 0;
766 /* if (!SDDS_ZeroMemory((void *)SDDS_dataset, sizeof(SDDS_DATASET))) {
767 sprintf(s,
768 "Unable to initialize output for file %s--can't zero SDDS_DATASET structure (SDDS_InitializeOutput)",
769 filename);
770 SDDS_SetError(s);
771 return 0;
772 } */
773 /*the sdds dataset memory has been zeroed in the SDDS_MPI_Setup */
774 SDDS_dataset->layout.popenUsed = SDDS_dataset->layout.gzipFile = SDDS_dataset->layout.lzmaFile = SDDS_dataset->layout.disconnected = 0;
775 SDDS_dataset->layout.depth = SDDS_dataset->layout.data_command_seen = SDDS_dataset->layout.commentFlags = SDDS_dataset->deferSavingLayout = 0;
776 SDDS_dataset->layout.fp = NULL;
777
778 SDDS_dataset->page_number = SDDS_dataset->page_started = 0;
779 SDDS_dataset->file_had_data = SDDS_dataset->layout.layout_written = 0;
780 if (!filename)
781 SDDS_dataset->layout.filename = NULL;
782 else if (!SDDS_CopyString(&SDDS_dataset->layout.filename, filename)) {
783 sprintf(s, "Memory allocation failure initializing file %s (SDDS_InitializeOutput)", filename);
784 SDDS_SetError(s);
785 return 0;
786 }
787 if ((outputEndianess = getenv("SDDS_OUTPUT_ENDIANESS"))) {
788 if (strncmp(outputEndianess, "big", 3) == 0)
789 SDDS_dataset->layout.byteOrderDeclared = SDDS_BIGENDIAN;
790 else if (strncmp(outputEndianess, "little", 6) == 0)
791 SDDS_dataset->layout.byteOrderDeclared = SDDS_LITTLEENDIAN;
792 } else {
793 SDDS_dataset->layout.byteOrderDeclared = SDDS_IsBigEndianMachine() ? SDDS_BIGENDIAN : SDDS_LITTLEENDIAN;
794 }
795 /* set big-endian for binary files, since it is the only type of MPI binary file.
796 SDDS_dataset->layout.byteOrderDeclared = SDDS_BIGENDIAN; */
797 SDDS_dataset->layout.version = SDDS_VERSION;
798 /* it turned out that hard to write ascii file in parallel, fixed it as SDDS_BINARY */
799 SDDS_dataset->layout.data_mode.mode = SDDS_BINARY;
800 SDDS_dataset->layout.data_mode.lines_per_row = 0;
801 SDDS_dataset->layout.data_mode.no_row_counts = 0;
802 SDDS_dataset->layout.data_mode.fixed_row_count = 0;
803 SDDS_dataset->layout.data_mode.fsync_data = 0;
804 SDDS_dataset->layout.data_mode.column_memory_mode = DEFAULT_COLUMN_MEMORY_MODE;
805 /*This is only temporary, soon the default will be column major order */
806 SDDS_dataset->layout.data_mode.column_major = 0;
807 if (description && !SDDS_CopyString(&SDDS_dataset->layout.description, description)) {
808 sprintf(s, "Memory allocation failure initializing file %s (SDDS_InitializeOutput)", filename ? filename : "stdout");
809 SDDS_SetError(s);
810 return 0;
811 }
812 if (contents && !SDDS_CopyString(&SDDS_dataset->layout.contents, contents)) {
813 sprintf(s, "Memory allocation failure initializing file %s (SDDS_InitializeOutput)", filename ? filename : "stdout");
814 SDDS_SetError(s);
815 return 0;
816 }
817 SDDS_dataset->layout.n_parameters = SDDS_dataset->layout.n_columns = SDDS_dataset->layout.n_arrays = SDDS_dataset->layout.n_associates = 0;
818 SDDS_dataset->mode = SDDS_WRITEMODE; /*writing */
819 SDDS_dataset->pagecount_offset = NULL;
820 SDDS_dataset->parallel_io = 1;
821 return (1);
822}
823
824/**
825 * @brief Sets the flag to enable or disable row counts in the SDDS dataset.
826 *
827 * This function configures the SDDS dataset to either include or exclude row counts in the output.
828 * Row counts provide metadata about the number of rows written, which can be useful for data integrity
829 * and validation. Disabling row counts can improve performance when such metadata is unnecessary.
830 *
831 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure to be configured.
832 * @param[in] value The flag value to set:
833 * - @c 0: Enable row counts (default behavior).
834 * - Non-zero: Disable row counts.
835 *
836 * @return
837 * - @c 1 on successful configuration.
838 * - @c 0 if an error occurred (e.g., attempting to change the flag after the layout has been written).
839 *
840 * @pre
841 * - The @c SDDS_dataset must be initialized and not have written the layout yet.
842 *
843 * @post
844 * - The dataset's configuration reflects the specified row count setting.
845 *
846 * @note
847 * - Changing the row count setting affects how data rows are managed and stored in the output file.
848 *
849 * @warning
850 * - This function cannot be called after the dataset layout has been written to the file or if the dataset is in read mode.
851 * - Disabling row counts may complicate data validation and integrity checks.
852 */
853int32_t SDDS_SetNoRowCounts(SDDS_DATASET *SDDS_dataset, int32_t value) {
854 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_SetNoRowCounts"))
855 return 0;
856 if (SDDS_dataset->layout.layout_written) {
857 SDDS_SetError("Can't change no_row_counts after writing the layout, or for a file you are reading.");
858 return 0;
859 }
860 SDDS_dataset->layout.data_mode.no_row_counts = value ? 1 : 0;
861 return 1;
862}
863
864/**
865 * @brief Writes the SDDS layout header to the output file.
866 *
867 * This function serializes and writes the layout information of the SDDS dataset to the output file.
868 * The layout defines the structure of the data tables, including parameters, arrays, columns, and
869 * associates. The function handles different file types, including standard, gzip-compressed, and
870 * LZMA-compressed files, and ensures that the layout is written in the correct byte order and format
871 * based on the dataset's configuration.
872 *
873 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure whose layout is to be written.
874 *
875 * @return
876 * - @c 1 on successful writing of the layout.
877 * - @c 0 if an error occurred during the writing process. An internal error message is set in this case.
878 *
879 * @pre
880 * - The dataset must be initialized and configured for output.
881 * - The layout must have been saved internally using SDDS_SaveLayout before calling this function.
882 * - The dataset must not be disconnected from the output file.
883 * - The layout must not have been previously written to the file.
884 *
885 * @post
886 * - The layout header is written to the output file in the appropriate format.
887 * - The dataset's internal state is updated to reflect that the layout has been written.
888 *
889 * @note
890 * - The function automatically determines the layout version based on the data types used in parameters, arrays, and columns.
891 * - Environment variable @c SDDS_OUTPUT_ENDIANESS can influence the byte order declared in the layout.
892 * - The function handles both binary and ASCII modes, adjusting the layout accordingly.
893 *
894 * @warning
895 * - Attempting to write the layout after it has already been written will result in an error.
896 * - The function does not support writing layouts to disconnected files.
897 * - Ensure that the output file is properly opened and writable before calling this function.
898 */
899int32_t SDDS_WriteLayout(SDDS_DATASET *SDDS_dataset) {
900 SDDS_LAYOUT *layout;
901#if defined(zLib)
902 gzFile gzfp;
903#endif
904 FILE *fp;
905 struct lzmafile *lzmafp;
906 int64_t i;
907 char *outputEndianess = NULL;
908
909#if SDDS_MPI_IO
910 if (SDDS_dataset->parallel_io)
911 return SDDS_MPI_WriteLayout(SDDS_dataset);
912#endif
913 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_WriteLayout"))
914 return 0;
915
916 if (!SDDS_SaveLayout(SDDS_dataset))
917 return 0;
918
919 layout = &SDDS_dataset->layout;
920
921 if (SDDS_dataset->layout.disconnected) {
922 SDDS_SetError("Can't write layout--file is disconnected (SDDS_WriteLayout)");
923 return 0;
924 }
925
926 if (layout->layout_written) {
927 SDDS_SetError("Can't write layout--already written to file (SDDS_WriteLayout)");
928 return 0;
929 }
930
931 if ((outputEndianess = getenv("SDDS_OUTPUT_ENDIANESS"))) {
932 if (strncmp(outputEndianess, "big", 3) == 0)
933 layout->byteOrderDeclared = SDDS_BIGENDIAN;
934 else if (strncmp(outputEndianess, "little", 6) == 0)
935 layout->byteOrderDeclared = SDDS_LITTLEENDIAN;
936 }
937
938 if (!layout->byteOrderDeclared)
939 layout->byteOrderDeclared = SDDS_IsBigEndianMachine() ? SDDS_BIGENDIAN : SDDS_LITTLEENDIAN;
940
941 layout->version = 1;
942 for (i = 0; i < layout->n_parameters; i++) {
943 if ((layout->parameter_definition[i].type == SDDS_ULONG) || (layout->parameter_definition[i].type == SDDS_USHORT)) {
944 layout->version = 2;
945 break;
946 }
947 }
948 for (i = 0; i < layout->n_arrays; i++) {
949 if ((layout->array_definition[i].type == SDDS_ULONG) || (layout->array_definition[i].type == SDDS_USHORT)) {
950 layout->version = 2;
951 break;
952 }
953 }
954 for (i = 0; i < layout->n_columns; i++) {
955 if ((layout->column_definition[i].type == SDDS_ULONG) || (layout->column_definition[i].type == SDDS_USHORT)) {
956 layout->version = 2;
957 break;
958 }
959 }
960 if ((layout->data_mode.column_major) && (layout->data_mode.mode == SDDS_BINARY)) {
961 layout->version = 3;
962 }
963 for (i = 0; i < layout->n_parameters; i++) {
964 if (layout->parameter_definition[i].type == SDDS_LONGDOUBLE) {
965 layout->version = 4;
966 break;
967 }
968 }
969 for (i = 0; i < layout->n_arrays; i++) {
970 if (layout->array_definition[i].type == SDDS_LONGDOUBLE) {
971 layout->version = 4;
972 break;
973 }
974 }
975 for (i = 0; i < layout->n_columns; i++) {
976 if (layout->column_definition[i].type == SDDS_LONGDOUBLE) {
977 layout->version = 4;
978 break;
979 }
980 }
981 if ((LDBL_DIG != 18) && (layout->version == 4)) {
982 if (getenv("SDDS_LONGDOUBLE_64BITS") == NULL) {
983 SDDS_SetError("Error: Operating system does not support 80bit float variables used by SDDS_LONGDOUBLE (SDDS_WriteLayout)\nSet SDDS_LONGDOUBLE_64BITS environment variable to read old files that used 64bit float variables for SDDS_LONGDOUBLE");
984 return 0;
985 }
986 }
987 for (i = 0; i < layout->n_parameters; i++) {
988 if ((layout->parameter_definition[i].type == SDDS_ULONG64) || (layout->parameter_definition[i].type == SDDS_LONG64)) {
989 layout->version = 5;
990 break;
991 }
992 }
993 for (i = 0; i < layout->n_arrays; i++) {
994 if ((layout->array_definition[i].type == SDDS_ULONG64) || (layout->array_definition[i].type == SDDS_LONG64)) {
995 layout->version = 5;
996 break;
997 }
998 }
999 for (i = 0; i < layout->n_columns; i++) {
1000 if ((layout->column_definition[i].type == SDDS_ULONG64) || (layout->column_definition[i].type == SDDS_LONG64)) {
1001 layout->version = 5;
1002 break;
1003 }
1004 }
1005
1006 // force layout version 5 because the row and column indexes are now 64bit long integers
1007 // layout->version = 5;
1008
1009#if defined(zLib)
1010 if (SDDS_dataset->layout.gzipFile) {
1011 if (!(gzfp = layout->gzfp)) {
1012 SDDS_SetError("Can't write SDDS layout--file pointer is NULL (SDDS_WriteLayout)");
1013 return 0;
1014 }
1015
1016 /* write out the layout data */
1017 if (!SDDS_GZipWriteVersion(layout->version, gzfp)) {
1018 SDDS_SetError("Can't write SDDS layout--error writing version (SDDS_WriteLayout)");
1019 return 0;
1020 }
1021 if (layout->version < 3) {
1022 if (SDDS_dataset->layout.data_mode.mode == SDDS_BINARY) {
1023 if (layout->byteOrderDeclared == SDDS_BIGENDIAN)
1024 gzprintf(gzfp, "!# big-endian\n");
1025 else
1026 gzprintf(gzfp, "!# little-endian\n");
1027 }
1028 if (SDDS_dataset->layout.data_mode.fixed_row_count) {
1029 gzprintf(gzfp, "!# fixed-rowcount\n");
1030 }
1031 }
1032 if (!SDDS_GZipWriteDescription(layout->description, layout->contents, gzfp)) {
1033 SDDS_SetError("Can't write SDDS layout--error writing description (SDDS_WriteLayout)");
1034 return 0;
1035 }
1036
1037 for (i = 0; i < layout->n_parameters; i++)
1038 if (!SDDS_GZipWriteParameterDefinition(layout->parameter_definition + i, gzfp)) {
1039 SDDS_SetError("Unable to write layout--error writing parameter definition (SDDS_WriteLayout)");
1040 return 0;
1041 }
1042
1043 for (i = 0; i < layout->n_arrays; i++)
1044 if (!SDDS_GZipWriteArrayDefinition(layout->array_definition + i, gzfp)) {
1045 SDDS_SetError("Unable to write layout--error writing array definition (SDDS_WriteLayout)");
1046 return 0;
1047 }
1048
1049 for (i = 0; i < layout->n_columns; i++)
1050 if (!SDDS_GZipWriteColumnDefinition(layout->column_definition + i, gzfp)) {
1051 SDDS_SetError("Unable to write layout--error writing column definition (SDDS_WriteLayout)");
1052 return 0;
1053 }
1054
1055# if RW_ASSOCIATES != 0
1056 for (i = 0; i < layout->n_associates; i++)
1057 if (!SDDS_GZipWriteAssociateDefinition(layout->associate_definition + i, gzfp)) {
1058 SDDS_SetError("Unable to write layout--error writing associated file data (SDDS_WriteLayout)");
1059 return 0;
1060 }
1061# endif
1062
1063 if (!SDDS_GZipWriteDataMode(layout, gzfp)) {
1064 SDDS_SetError("Unable to write layout--error writing data mode (SDDS_WriteLayout)");
1065 return 0;
1066 }
1067
1068 layout->layout_written = 1;
1069 /*gzflush(gzfp, Z_FULL_FLUSH); */
1070 } else {
1071#endif
1072 if (SDDS_dataset->layout.lzmaFile) {
1073 if (!(lzmafp = layout->lzmafp)) {
1074 SDDS_SetError("Can't write SDDS layout--file pointer is NULL (SDDS_WriteLayout)");
1075 return 0;
1076 }
1077
1078 /* write out the layout data */
1079 if (!SDDS_LZMAWriteVersion(layout->version, lzmafp)) {
1080 SDDS_SetError("Can't write SDDS layout--error writing version (SDDS_WriteLayout)");
1081 return 0;
1082 }
1083 if (layout->version < 3) {
1084 if (SDDS_dataset->layout.data_mode.mode == SDDS_BINARY) {
1085 if (layout->byteOrderDeclared == SDDS_BIGENDIAN)
1086 lzma_printf(lzmafp, "!# big-endian\n");
1087 else
1088 lzma_printf(lzmafp, "!# little-endian\n");
1089 }
1090 if (SDDS_dataset->layout.data_mode.fixed_row_count) {
1091 lzma_printf(lzmafp, "!# fixed-rowcount\n");
1092 }
1093 }
1094 if (!SDDS_LZMAWriteDescription(layout->description, layout->contents, lzmafp)) {
1095 SDDS_SetError("Can't write SDDS layout--error writing description (SDDS_WriteLayout)");
1096 return 0;
1097 }
1098 for (i = 0; i < layout->n_parameters; i++)
1099 if (!SDDS_LZMAWriteParameterDefinition(layout->parameter_definition + i, lzmafp)) {
1100 SDDS_SetError("Unable to write layout--error writing parameter definition (SDDS_WriteLayout)");
1101 return 0;
1102 }
1103 for (i = 0; i < layout->n_arrays; i++)
1104 if (!SDDS_LZMAWriteArrayDefinition(layout->array_definition + i, lzmafp)) {
1105 SDDS_SetError("Unable to write layout--error writing array definition (SDDS_WriteLayout)");
1106 return 0;
1107 }
1108 for (i = 0; i < layout->n_columns; i++)
1109 if (!SDDS_LZMAWriteColumnDefinition(layout->column_definition + i, lzmafp)) {
1110 SDDS_SetError("Unable to write layout--error writing column definition (SDDS_WriteLayout)");
1111 return 0;
1112 }
1113
1114#if RW_ASSOCIATES != 0
1115 for (i = 0; i < layout->n_associates; i++)
1116 if (!SDDS_LZMAWriteAssociateDefinition(layout->associate_definition + i, lzmafp)) {
1117 SDDS_SetError("Unable to write layout--error writing associated file data (SDDS_WriteLayout)");
1118 return 0;
1119 }
1120#endif
1121
1122 if (!SDDS_LZMAWriteDataMode(layout, lzmafp)) {
1123 SDDS_SetError("Unable to write layout--error writing data mode (SDDS_WriteLayout)");
1124 return 0;
1125 }
1126
1127 layout->layout_written = 1;
1128 } else {
1129
1130 if (!(fp = layout->fp)) {
1131 SDDS_SetError("Can't write SDDS layout--file pointer is NULL (SDDS_WriteLayout)");
1132 return 0;
1133 }
1134
1135 /* write out the layout data */
1136 if (!SDDS_WriteVersion(layout->version, fp)) {
1137 SDDS_SetError("Can't write SDDS layout--error writing version (SDDS_WriteLayout)");
1138 return 0;
1139 }
1140 if (layout->version < 3) {
1141 if (SDDS_dataset->layout.data_mode.mode == SDDS_BINARY) {
1142 if (layout->byteOrderDeclared == SDDS_BIGENDIAN)
1143 fprintf(fp, "!# big-endian\n");
1144 else
1145 fprintf(fp, "!# little-endian\n");
1146 }
1147 if (SDDS_dataset->layout.data_mode.fixed_row_count) {
1148 fprintf(fp, "!# fixed-rowcount\n");
1149 }
1150 }
1151 if (!SDDS_WriteDescription(layout->description, layout->contents, fp)) {
1152 SDDS_SetError("Can't write SDDS layout--error writing description (SDDS_WriteLayout)");
1153 return 0;
1154 }
1155
1156 for (i = 0; i < layout->n_parameters; i++)
1157 if (!SDDS_WriteParameterDefinition(layout->parameter_definition + i, fp)) {
1158 SDDS_SetError("Unable to write layout--error writing parameter definition (SDDS_WriteLayout)");
1159 return 0;
1160 }
1161
1162 for (i = 0; i < layout->n_arrays; i++)
1163 if (!SDDS_WriteArrayDefinition(layout->array_definition + i, fp)) {
1164 SDDS_SetError("Unable to write layout--error writing array definition (SDDS_WriteLayout)");
1165 return 0;
1166 }
1167
1168 for (i = 0; i < layout->n_columns; i++)
1169 if (!SDDS_WriteColumnDefinition(layout->column_definition + i, fp)) {
1170 SDDS_SetError("Unable to write layout--error writing column definition (SDDS_WriteLayout)");
1171 return 0;
1172 }
1173
1174#if RW_ASSOCIATES != 0
1175 for (i = 0; i < layout->n_associates; i++)
1176 if (!SDDS_WriteAssociateDefinition(layout->associate_definition + i, fp)) {
1177 SDDS_SetError("Unable to write layout--error writing associated file data (SDDS_WriteLayout)");
1178 return 0;
1179 }
1180#endif
1181
1182 if (!SDDS_WriteDataMode(layout, fp)) {
1183 SDDS_SetError("Unable to write layout--error writing data mode (SDDS_WriteLayout)");
1184 return 0;
1185 }
1186
1187 layout->layout_written = 1;
1188 fflush(fp);
1189 }
1190#if defined(zLib)
1191 }
1192#endif
1193 if (SDDS_SyncDataSet(SDDS_dataset) != 0)
1194 return 0;
1195 return (1);
1196}
1197
1198/**
1199 * @brief Writes the current data table to the output file.
1200 *
1201 * This function serializes and writes the current data table of the SDDS dataset to the output file.
1202 * It must be preceded by a call to @c SDDS_WriteLayout to ensure that the dataset layout is properly defined
1203 * in the output file. Depending on the data mode (ASCII or Binary), the function delegates the writing
1204 * process to the appropriate handler.
1205 *
1206 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset.
1207 *
1208 * @return
1209 * - @c 1 on successful writing of the data table.
1210 * - @c 0 if an error occurred during the write process. An error message is set internally in this case.
1211 *
1212 * @pre
1213 * - The dataset must be initialized and configured for output.
1214 * - @c SDDS_WriteLayout must have been called successfully before writing any pages.
1215 *
1216 * @post
1217 * - The current data table is written to the output file.
1218 * - The dataset state is synchronized with the file to ensure data integrity.
1219 *
1220 * @note
1221 * - The function supports parallel I/O modes if enabled.
1222 * - Ensure that the dataset is not disconnected from the output file before calling this function.
1223 *
1224 * @warning
1225 * - Attempting to write a page without defining the layout first will result in an error.
1226 * - Concurrent access to the dataset while writing pages may lead to undefined behavior.
1227 */
1228int32_t SDDS_WritePage(SDDS_DATASET *SDDS_dataset) {
1229 int32_t result;
1230#if SDDS_MPI_IO
1231 if (SDDS_dataset->parallel_io)
1232 return SDDS_MPI_WritePage(SDDS_dataset);
1233#endif
1234 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_WritePage"))
1235 return 0;
1236 if (!SDDS_dataset->layout.layout_written) {
1237 SDDS_SetError("Unable to write page--layout not written (SDDS_WritePage)");
1238 return 0;
1239 }
1240 if (SDDS_dataset->layout.disconnected) {
1241 SDDS_SetError("Can't write page--file is disconnected (SDDS_WritePage)");
1242 return 0;
1243 }
1244 if (SDDS_dataset->layout.data_mode.mode == SDDS_ASCII)
1245 result = SDDS_WriteAsciiPage(SDDS_dataset);
1246 else if (SDDS_dataset->layout.data_mode.mode == SDDS_BINARY)
1247 result = SDDS_WriteBinaryPage(SDDS_dataset);
1248 else {
1249 SDDS_SetError("Unable to write page--unknown data mode (SDDS_WritePage)");
1250 return 0;
1251 }
1252 if (result == 1)
1253 if (SDDS_SyncDataSet(SDDS_dataset) != 0)
1254 return 0;
1255 return (result);
1256}
1257
1258/**
1259 * @brief Updates the current page of the SDDS dataset.
1260 *
1261 * This function finalizes and writes the current page of the SDDS dataset based on the specified mode.
1262 * The mode can be either @c FLUSH_TABLE, indicating that the current page is complete and should be written to disk,
1263 * or @c 0 for other update operations. Depending on the data mode (ASCII or Binary), the function delegates
1264 * the update process to the appropriate handler.
1265 *
1266 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset.
1267 * @param[in] mode The update mode, which can be:
1268 * - @c FLUSH_TABLE: Indicates that the current page is complete and should be written to disk.
1269 * - @c 0: Represents a standard update without flushing the table.
1270 *
1271 * @return
1272 * - @c 1 on successful update of the current page.
1273 * - @c 0 if an error occurred during the update process. An error message is set internally in this case.
1274 *
1275 * @pre
1276 * - The dataset must be initialized and configured for output.
1277 * - A page must have been started before calling this function.
1278 *
1279 * @post
1280 * - The current page is updated and, if specified, written to the output file.
1281 * - The dataset state is synchronized with the file to ensure data integrity.
1282 *
1283 * @note
1284 * - The function supports parallel I/O modes if enabled.
1285 * - The @c FLUSH_TABLE mode ensures that all buffered data is written to the disk, which can be useful for data integrity.
1286 *
1287 * @warning
1288 * - Attempting to update a page without starting one will result in an error.
1289 * - Concurrent access to the dataset while updating pages may lead to undefined behavior.
1290 */
1291int32_t SDDS_UpdatePage(SDDS_DATASET *SDDS_dataset, uint32_t mode) {
1292 int32_t result;
1293 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_UpdatePage"))
1294 return 0;
1295 if (SDDS_dataset->layout.disconnected) {
1296 SDDS_SetError("Can't write page--file is disconnected (SDDS_UpdatePage)");
1297 return 0;
1298 }
1299 if (SDDS_dataset->page_started == 0) {
1300 SDDS_SetError("Can't update page--no page started (SDDS_UpdatePage)");
1301 return 0;
1302 }
1303 if (SDDS_dataset->layout.data_mode.mode == SDDS_ASCII)
1304 result = SDDS_UpdateAsciiPage(SDDS_dataset, mode);
1305 else if (SDDS_dataset->layout.data_mode.mode == SDDS_BINARY)
1306 result = SDDS_UpdateBinaryPage(SDDS_dataset, mode);
1307 else {
1308 SDDS_SetError("Unable to update page--unknown data mode (SDDS_UpdatePage)");
1309 return 0;
1310 }
1311 if (result == 1)
1312 if (SDDS_SyncDataSet(SDDS_dataset) != 0)
1313 return 0;
1314 return (result);
1315}
1316
1317/**
1318 * @brief Synchronizes the SDDS dataset with the disk by flushing buffered data.
1319 *
1320 * This function attempts to ensure that any buffered data associated with the SDDS dataset is written
1321 * to the disk using the @c fsync system call. However, on certain platforms such as VxWorks, Windows,
1322 * Linux, and macOS, this functionality is not implemented and the function simply returns success.
1323 * This behavior should be considered when relying on data synchronization across different operating systems.
1324 *
1325 * @param[in] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset.
1326 *
1327 * @return
1328 * - @c 0 on success, indicating that data synchronization is either not needed or was successful.
1329 * - A negative value (e.g., @c -1) on failure to synchronize the data, with an error message set internally.
1330 *
1331 * @note
1332 * - On unsupported platforms, the function does not perform any synchronization and returns success.
1333 * - The synchronization behavior depends on the operating system and its support for the @c fsync system call.
1334 *
1335 * @warning
1336 * - On platforms where synchronization is not implemented, relying on this function for data integrity is not possible.
1337 * - Ensure that critical data is handled appropriately, considering the limitations of the target operating system.
1338 */
1339int32_t SDDS_SyncDataSet(SDDS_DATASET *SDDS_dataset) {
1340#if defined(vxWorks) || defined(_WIN32) || defined(linux) || defined(__APPLE__)
1341 return (0);
1342#else
1343 if (!(SDDS_dataset->layout.fp)) {
1344 SDDS_SetError("Unable to sync file--file pointer is NULL (SDDS_SyncDataSet)");
1345 return (-1);
1346 }
1347 if (SDDS_dataset->layout.data_mode.fsync_data == 0)
1348 return (0);
1349 if (fsync(fileno(SDDS_dataset->layout.fp)) == 0)
1350 return (0);
1351 /*
1352 SDDS_SetError("Unable to sync file (SDDS_SyncDataSet)");
1353 return(-1);
1354 */
1355 /* This error should not be fatal */
1356 return (0);
1357#endif
1358}
1359
1360/**
1361 * @brief Defines a data parameter with a fixed numerical value.
1362 *
1363 * This function processes the definition of a data parameter within the SDDS dataset. It allows
1364 * the specification of a fixed numerical value for the parameter, which remains constant across
1365 * all data entries. The function validates the parameter name, type, and format string before
1366 * defining the parameter in the dataset.
1367 *
1368 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset.
1369 * @param[in] name A NULL-terminated string specifying the name of the parameter. This name must be unique within the dataset.
1370 * @param[in] symbol A NULL-terminated string specifying the symbol for the parameter. Pass @c NULL if no symbol is desired.
1371 * @param[in] units A NULL-terminated string specifying the units of the parameter. Pass @c NULL if no units are desired.
1372 * @param[in] description A NULL-terminated string providing a description of the parameter. Pass @c NULL if no description is desired.
1373 * @param[in] format_string A NULL-terminated string specifying the printf-style format for ASCII output. If @c NULL is passed, a default format is selected based on the parameter type.
1374 * @param[in] type An integer representing the data type of the parameter. Must be one of the following:
1375 * - @c SDDS_LONGDOUBLE
1376 * - @c SDDS_DOUBLE
1377 * - @c SDDS_FLOAT
1378 * - @c SDDS_LONG
1379 * - @c SDDS_ULONG
1380 * - @c SDDS_SHORT
1381 * - @c SDDS_USHORT
1382 * - @c SDDS_CHARACTER
1383 * - @c SDDS_STRING
1384 * @param[in] fixed_value A pointer to the numerical value that remains constant for this parameter across all data entries. This value is used to initialize the parameter's fixed value.
1385 *
1386 * @return
1387 * - On success, returns the index of the newly defined parameter within the dataset.
1388 * - Returns @c -1 on failure, with an error message set internally.
1389 *
1390 * @pre
1391 * - The dataset must be initialized and configured for output.
1392 * - The parameter name must be unique and valid.
1393 * - The fixed value must be non-NULL for numerical types and should be prepared appropriately.
1394 *
1395 * @post
1396 * - The parameter is defined within the dataset with the specified attributes and fixed value.
1397 * - The dataset's internal structures are updated to include the new parameter.
1398 *
1399 * @note
1400 * - For string-type parameters, the fixed value should be a NULL-terminated string.
1401 * - The function internally converts the fixed numerical value to a string representation if the parameter type is not @c SDDS_STRING.
1402 *
1403 * @warning
1404 * - Defining a parameter with an invalid type or format string will result in an error.
1405 * - Passing a NULL fixed value for non-string types will result in an error.
1406 */
1407int32_t SDDS_DefineParameter1(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, void *fixed_value) {
1408 char buffer[SDDS_MAXLINE];
1409 if (!SDDS_IsValidName(name, "parameter"))
1410 return -1;
1411 if (!fixed_value || type == SDDS_STRING)
1412 return SDDS_DefineParameter(SDDS_dataset, name, symbol, units, description, format_string, type, fixed_value);
1413 if (type <= 0 || type > SDDS_NUM_TYPES) {
1414 SDDS_SetError("Unknown data type (SDDS_DefineParameter1)");
1415 return (-1);
1416 }
1417 buffer[SDDS_MAXLINE - 1] = 0;
1418 if (!SDDS_SprintTypedValue(fixed_value, 0, type, format_string, buffer, 0) || buffer[SDDS_MAXLINE - 1] != 0) {
1419 SDDS_SetError("Unable to define fixed value for parameter (SDDS_DefineParameter1)");
1420 return (-1);
1421 }
1422 return SDDS_DefineParameter(SDDS_dataset, name, symbol, units, description, format_string, type, buffer);
1423}
1424
1425/**
1426 * @brief Defines a data parameter with a fixed string value.
1427 *
1428 * This function processes the definition of a data parameter within the SDDS dataset. It allows
1429 * the specification of a fixed string value for the parameter, which remains constant across
1430 * all data entries. The function validates the parameter name, type, and format string before
1431 * defining the parameter in the dataset.
1432 *
1433 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset.
1434 * @param[in] name A NULL-terminated string specifying the name of the parameter. This name must be unique within the dataset.
1435 * @param[in] symbol A NULL-terminated string specifying the symbol for the parameter. Pass @c NULL if no symbol is desired.
1436 * @param[in] units A NULL-terminated string specifying the units of the parameter. Pass @c NULL if no units are desired.
1437 * @param[in] description A NULL-terminated string providing a description of the parameter. Pass @c NULL if no description is desired.
1438 * @param[in] format_string A NULL-terminated string specifying the printf-style format for ASCII output. If @c NULL is passed, a default format is selected based on the parameter type.
1439 * @param[in] type An integer representing the data type of the parameter. Must be one of the following:
1440 * - @c SDDS_LONGDOUBLE
1441 * - @c SDDS_DOUBLE
1442 * - @c SDDS_FLOAT
1443 * - @c SDDS_LONG
1444 * - @c SDDS_ULONG
1445 * - @c SDDS_SHORT
1446 * - @c SDDS_USHORT
1447 * - @c SDDS_CHARACTER
1448 * - @c SDDS_STRING
1449 * @param[in] fixed_value A NULL-terminated string specifying the fixed value of the parameter. For non-string types, this string should be formatted appropriately using functions like @c sprintf.
1450 *
1451 * @return
1452 * - On success, returns the index of the newly defined parameter within the dataset.
1453 * - Returns @c -1 on failure, with an error message set internally.
1454 *
1455 * @pre
1456 * - The dataset must be initialized and configured for output.
1457 * - The parameter name must be unique and valid.
1458 * - The fixed value must be a valid string representation for the specified parameter type.
1459 *
1460 * @post
1461 * - The parameter is defined within the dataset with the specified attributes and fixed value.
1462 * - The dataset's internal structures are updated to include the new parameter.
1463 *
1464 * @note
1465 * - For numerical parameter types, the fixed value string should represent the numerical value correctly.
1466 * - The function internally handles the conversion of the fixed value string to the appropriate type based on the parameter's data type.
1467 *
1468 * @warning
1469 * - Defining a parameter with an invalid type or format string will result in an error.
1470 * - Passing an improperly formatted fixed value string for the specified type may lead to unexpected behavior.
1471 */
1472int32_t SDDS_DefineParameter(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, char *fixed_value) {
1473 SDDS_LAYOUT *layout;
1474 PARAMETER_DEFINITION *definition;
1475 char s[SDDS_MAXLINE];
1476 SORTED_INDEX *new_indexed_parameter;
1477 int32_t index, duplicate;
1478
1479 if (!SDDS_IsValidName(name, "parameter"))
1480 return -1;
1481 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_DefineParameter"))
1482 return (-1);
1483 if (!name) {
1484 SDDS_SetError("NULL name not allowed for parameter definition");
1485 return (-1);
1486 }
1487 layout = &SDDS_dataset->layout;
1488 if (!(layout->parameter_definition =
1489 SDDS_Realloc(layout->parameter_definition, sizeof(*layout->parameter_definition) * (layout->n_parameters + 1))) ||
1490 !(layout->parameter_index = SDDS_Realloc(layout->parameter_index, sizeof(*layout->parameter_index) * (layout->n_parameters + 1))) || !(new_indexed_parameter = (SORTED_INDEX *)SDDS_Malloc(sizeof(*new_indexed_parameter)))) {
1491 SDDS_SetError("Memory allocation failure (SDDS_DefineParameter)");
1492 return (-1);
1493 }
1494 if (!SDDS_CopyString(&new_indexed_parameter->name, name))
1495 return -1;
1496 index = binaryInsert((void **)layout->parameter_index, layout->n_parameters, new_indexed_parameter, SDDS_CompareIndexedNames, &duplicate);
1497 if (duplicate) {
1498 sprintf(s, "Parameter %s already exists (SDDS_DefineParameter)", name);
1499 SDDS_SetError(s);
1500 return (-1);
1501 }
1502 layout->parameter_index[index]->index = layout->n_parameters;
1503
1504 if (!SDDS_ZeroMemory(definition = layout->parameter_definition + layout->n_parameters, sizeof(PARAMETER_DEFINITION))) {
1505 SDDS_SetError("Unable to define parameter--can't zero memory for parameter definition (SDDS_DefineParameter)");
1506 return (-1);
1507 }
1508 definition->name = new_indexed_parameter->name;
1509 if (symbol && !SDDS_CopyString(&definition->symbol, symbol)) {
1510 SDDS_SetError("Memory allocation failure (SDDS_DefineParameter)");
1511 return (-1);
1512 }
1513 if (units && !SDDS_CopyString(&definition->units, units)) {
1514 SDDS_SetError("Memory allocation failure (SDDS_DefineParameter)");
1515 return (-1);
1516 }
1517 if (description && !SDDS_CopyString(&definition->description, description)) {
1518 SDDS_SetError("Memory allocation failure (SDDS_DefineParameter)");
1519 return (-1);
1520 }
1521 if (type <= 0 || type > SDDS_NUM_TYPES) {
1522 SDDS_SetError("Unknown data type (SDDS_DefineParameter)");
1523 return (-1);
1524 }
1525 definition->type = type;
1526 if (format_string) {
1527 if (!SDDS_VerifyPrintfFormat(format_string, type)) {
1528 SDDS_SetError("Invalid format string (SDDS_DefineParameter)");
1529 return (-1);
1530 }
1531 if (!SDDS_CopyString(&definition->format_string, format_string)) {
1532 SDDS_SetError("Memory allocation failure (SDDS_DefineParameter)");
1533 return (-1);
1534 }
1535 }
1536 if (fixed_value && !SDDS_CopyString(&(definition->fixed_value), fixed_value)) {
1537 SDDS_SetError("Couldn't copy fixed_value string (SDDS_DefineParameter)");
1538 return (-1);
1539 }
1540 definition->definition_mode = SDDS_NORMAL_DEFINITION;
1541 if (type == SDDS_STRING)
1542 definition->memory_number = SDDS_CreateRpnMemory(name, 1);
1543 else
1544 definition->memory_number = SDDS_CreateRpnMemory(name, 0);
1545 layout->n_parameters += 1;
1546 return (layout->n_parameters - 1);
1547}
1548
1549/**
1550 * @brief Defines a data array within the SDDS dataset.
1551 *
1552 * This function processes the definition of a data array in the SDDS dataset. It allows the user
1553 * to specify the array's name, symbol, units, description, format string, data type, field length,
1554 * number of dimensions, and associated group name. The function ensures that the array name is valid
1555 * and unique within the dataset before defining it.
1556 *
1557 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset.
1558 * @param[in] name A NULL-terminated string specifying the name of the array. This name must be unique within the dataset.
1559 * @param[in] symbol A NULL-terminated string specifying the symbol for the array. Pass @c NULL if no symbol is desired.
1560 * @param[in] units A NULL-terminated string specifying the units of the array. Pass @c NULL if no units are desired.
1561 * @param[in] description A NULL-terminated string providing a description of the array. Pass @c NULL if no description is desired.
1562 * @param[in] format_string A NULL-terminated string specifying the printf-style format for ASCII output. If @c NULL is passed, a default format is selected based on the array type.
1563 * @param[in] type An integer representing the data type of the array. Must be one of the following:
1564 * - @c SDDS_LONGDOUBLE
1565 * - @c SDDS_DOUBLE
1566 * - @c SDDS_FLOAT
1567 * - @c SDDS_LONG
1568 * - @c SDDS_ULONG
1569 * - @c SDDS_SHORT
1570 * - @c SDDS_USHORT
1571 * - @c SDDS_CHARACTER
1572 * - @c SDDS_STRING
1573 * @param[in] field_length An integer specifying the length of the field allotted to the array for ASCII output. If set to @c 0, the field length is ignored. If negative, the field length is set to the absolute value, and leading and trailing white-space are eliminated for @c SDDS_STRING types upon reading.
1574 * @param[in] dimensions An integer specifying the number of dimensions of the array. Must be greater than @c 0.
1575 * @param[in] group_name A NULL-terminated string specifying the name of the array group to which this array belongs. This allows related arrays to be grouped together (e.g., parallel arrays).
1576 *
1577 * @return
1578 * - On success, returns the index of the newly defined array within the dataset.
1579 * - Returns @c -1 on failure, with an error message set internally.
1580 *
1581 * @pre
1582 * - The dataset must be initialized and configured for output.
1583 * - The array name must be unique and valid.
1584 * - The specified data type must be supported by the dataset.
1585 *
1586 * @post
1587 * - The array is defined within the dataset with the specified attributes.
1588 * - The dataset's internal structures are updated to include the new array.
1589 *
1590 * @note
1591 * - For string-type arrays, the fixed value is managed differently, and leading/trailing white-space is handled based on the field length parameter.
1592 * - The function supports multi-dimensional arrays as specified by the @c dimensions parameter.
1593 *
1594 * @warning
1595 * - Defining an array with an invalid type, field length, or number of dimensions will result in an error.
1596 * - Attempting to define an array with a name that already exists within the dataset will result in an error.
1597 */
1598int32_t SDDS_DefineArray(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, int32_t field_length, int32_t dimensions, const char *group_name) {
1599 SDDS_LAYOUT *layout;
1600 ARRAY_DEFINITION *definition;
1601 char s[SDDS_MAXLINE];
1602 SORTED_INDEX *new_indexed_array;
1603 int32_t index, duplicate;
1604
1605 if (!SDDS_IsValidName(name, "array"))
1606 return -1;
1607 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_DefineArray"))
1608 return (-1);
1609 if (!name) {
1610 SDDS_SetError("NULL name not allowed for array definition");
1611 return (-1);
1612 }
1613 layout = &SDDS_dataset->layout;
1614 if (!(layout->array_definition =
1615 SDDS_Realloc(layout->array_definition, sizeof(*layout->array_definition) * (layout->n_arrays + 1))) ||
1616 !(layout->array_index = SDDS_Realloc(layout->array_index, sizeof(*layout->array_index) * (layout->n_arrays + 1))) || !(new_indexed_array = (SORTED_INDEX *)SDDS_Malloc(sizeof(*new_indexed_array)))) {
1617 SDDS_SetError("Memory allocation failure (SDDS_DefineArray)");
1618 return (-1);
1619 }
1620
1621 if (!SDDS_CopyString(&new_indexed_array->name, name))
1622 return -1;
1623 index = binaryInsert((void **)layout->array_index, layout->n_arrays, new_indexed_array, SDDS_CompareIndexedNames, &duplicate);
1624 if (duplicate) {
1625 sprintf(s, "Array %s already exists (SDDS_DefineArray)", name);
1626 SDDS_SetError(s);
1627 return (-1);
1628 }
1629 layout->array_index[index]->index = layout->n_arrays;
1630
1631 if (!SDDS_ZeroMemory(definition = layout->array_definition + layout->n_arrays, sizeof(ARRAY_DEFINITION))) {
1632 SDDS_SetError("Unable to define array--can't zero memory for array definition (SDDS_DefineArray)");
1633 return (-1);
1634 }
1635 definition->name = new_indexed_array->name;
1636 if ((symbol && !SDDS_CopyString(&definition->symbol, symbol)) || (units && !SDDS_CopyString(&definition->units, units)) || (description && !SDDS_CopyString(&definition->description, description)) || (group_name && !SDDS_CopyString(&definition->group_name, group_name))) {
1637 SDDS_SetError("Memory allocation failure (SDDS_DefineArray)");
1638 return (-1);
1639 }
1640 if (type <= 0 || type > SDDS_NUM_TYPES) {
1641 SDDS_SetError("Unknown data type (SDDS_DefineArray)");
1642 return (-1);
1643 }
1644 definition->type = type;
1645 if (format_string) {
1646 if (!SDDS_VerifyPrintfFormat(format_string, type)) {
1647 SDDS_SetError("Invalid format string (SDDS_DefineArray)");
1648 return (-1);
1649 }
1650 if (!SDDS_CopyString(&definition->format_string, format_string)) {
1651 SDDS_SetError("Memory allocation failure (SDDS_DefineArray)");
1652 return (-1);
1653 }
1654 }
1655 if ((definition->field_length = field_length) < 0 && type != SDDS_STRING) {
1656 SDDS_SetError("Invalid field length (SDDS_DefineArray)");
1657 return (-1);
1658 }
1659 if ((definition->dimensions = dimensions) < 1) {
1660 SDDS_SetError("Invalid number of dimensions for array (SDDS_DefineArray)");
1661 return (-1);
1662 }
1663 layout->n_arrays += 1;
1664 return (layout->n_arrays - 1);
1665}
1666
1667/**
1668 * @brief Defines a data column within the SDDS dataset.
1669 *
1670 * This function processes the definition of a data column in the SDDS dataset. It allows the user
1671 * to specify the column's name, symbol, units, description, format string, data type, and field length.
1672 * The function ensures that the column name is valid and unique within the dataset before defining it.
1673 *
1674 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset.
1675 * @param[in] name A NULL-terminated string specifying the name of the column. This name must be unique within the dataset.
1676 * @param[in] symbol A NULL-terminated string specifying the symbol for the column. Pass @c NULL if no symbol is desired.
1677 * @param[in] units A NULL-terminated string specifying the units of the column. Pass @c NULL if no units are desired.
1678 * @param[in] description A NULL-terminated string providing a description of the column. Pass @c NULL if no description is desired.
1679 * @param[in] format_string A NULL-terminated string specifying the printf-style format for ASCII output. If @c NULL is passed, a default format is selected based on the column type.
1680 * @param[in] type An integer representing the data type of the column. Must be one of the following:
1681 * - @c SDDS_LONGDOUBLE
1682 * - @c SDDS_DOUBLE
1683 * - @c SDDS_FLOAT
1684 * - @c SDDS_LONG
1685 * - @c SDDS_ULONG
1686 * - @c SDDS_SHORT
1687 * - @c SDDS_USHORT
1688 * - @c SDDS_CHARACTER
1689 * - @c SDDS_STRING
1690 * @param[in] field_length An integer specifying the length of the field allotted to the column for ASCII output. If set to @c 0, the field length is ignored. If negative, the field length is set to the absolute value, and leading and trailing white-space are eliminated for @c SDDS_STRING types upon reading.
1691 *
1692 * @return
1693 * - On success, returns the index of the newly defined column within the dataset.
1694 * - Returns @c -1 on failure, with an error message set internally.
1695 *
1696 * @pre
1697 * - The dataset must be initialized and configured for output.
1698 * - The column name must be unique and valid.
1699 * - The specified data type must be supported by the dataset.
1700 *
1701 * @post
1702 * - The column is defined within the dataset with the specified attributes.
1703 * - The dataset's internal structures are updated to include the new column.
1704 * - If rows have already been allocated, the data arrays are resized to accommodate the new column.
1705 *
1706 * @note
1707 * - For string-type columns, the fixed value is managed differently, and leading/trailing white-space is handled based on the field length parameter.
1708 * - The function ensures that data arrays are appropriately resized if data has already been allocated.
1709 *
1710 * @warning
1711 * - Defining a column with an invalid type, field length, or name will result in an error.
1712 * - Attempting to define a column with a name that already exists within the dataset will result in an error.
1713 * - Memory allocation failures during the definition process will lead to an error.
1714 */
1715int32_t SDDS_DefineColumn(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, int32_t field_length) {
1716 SDDS_LAYOUT *layout;
1717 COLUMN_DEFINITION *definition;
1718 char s[SDDS_MAXLINE];
1719 SORTED_INDEX *new_indexed_column;
1720 int32_t index;
1721 int32_t duplicate;
1722
1723 if (!SDDS_IsValidName(name, "column"))
1724 return -1;
1725 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_DefineColumn"))
1726 return (-1);
1727 if (!name) {
1728 SDDS_SetError("NULL name not allowed for column definition");
1729 return (-1);
1730 }
1731 layout = &SDDS_dataset->layout;
1732 if (!(layout->column_definition =
1733 SDDS_Realloc(layout->column_definition, sizeof(*layout->column_definition) * (layout->n_columns + 1))) ||
1734 !(layout->column_index = SDDS_Realloc(layout->column_index, sizeof(*layout->column_index) * (layout->n_columns + 1))) || !(new_indexed_column = (SORTED_INDEX *)SDDS_Malloc(sizeof(*new_indexed_column)))) {
1735 SDDS_SetError("Memory allocation failure (SDDS_DefineColumn)");
1736 return (-1);
1737 }
1738 if (!SDDS_CopyString(&new_indexed_column->name, name))
1739 return -1;
1740 index = binaryInsert((void **)layout->column_index, layout->n_columns, new_indexed_column, SDDS_CompareIndexedNames, &duplicate);
1741 if (duplicate) {
1742 sprintf(s, "Column %s already exists (SDDS_DefineColumn)", name);
1743 SDDS_SetError(s);
1744 return (-1);
1745 }
1746 layout->column_index[index]->index = layout->n_columns;
1747 if (!SDDS_ZeroMemory(definition = layout->column_definition + layout->n_columns, sizeof(COLUMN_DEFINITION))) {
1748 SDDS_SetError("Unable to define column--can't zero memory for column definition (SDDS_DefineColumn)");
1749 return (-1);
1750 }
1751 definition->name = new_indexed_column->name;
1752 if (symbol && !SDDS_CopyString(&definition->symbol, symbol)) {
1753 SDDS_SetError("Memory allocation failure (SDDS_DefineColumn)");
1754 return (-1);
1755 }
1756 if (units && !SDDS_CopyString(&definition->units, units)) {
1757 SDDS_SetError("Memory allocation failure (SDDS_DefineColumn)");
1758 return (-1);
1759 }
1760 if (description && !SDDS_CopyString(&definition->description, description)) {
1761 SDDS_SetError("Memory allocation failure (SDDS_DefineColumn)");
1762 return (-1);
1763 }
1764 if (type <= 0 || type > SDDS_NUM_TYPES) {
1765 SDDS_SetError("Unknown data type (SDDS_DefineColumn)");
1766 return (-1);
1767 }
1768 definition->type = type;
1769 if (format_string) {
1770 if (!SDDS_VerifyPrintfFormat(format_string, type)) {
1771 SDDS_SetError("Invalid format string (SDDS_DefineColumn)");
1772 return (-1);
1773 }
1774 if (!SDDS_CopyString(&definition->format_string, format_string)) {
1775 SDDS_SetError("Memory allocation failure (SDDS_DefineColumn)");
1776 return (-1);
1777 }
1778 }
1779 if ((definition->field_length = field_length) < 0 && type != SDDS_STRING) {
1780 SDDS_SetError("Invalid field length (SDDS_DefineColumn)");
1781 return (-1);
1782 }
1783
1784 if (SDDS_dataset->n_rows_allocated) {
1785 if (!SDDS_dataset->data) {
1786 SDDS_SetError("data array NULL but rows have been allocated! (SDDS_DefineColumn)");
1787 return (-1);
1788 }
1789 /* data already present--must resize data and parameter memory */
1790 if (!(SDDS_dataset->data = SDDS_Realloc(SDDS_dataset->data, sizeof(*SDDS_dataset->data) * (layout->n_columns + 1))) || !(SDDS_dataset->data[layout->n_columns] = calloc(SDDS_dataset->n_rows_allocated, SDDS_type_size[type - 1]))) {
1791 SDDS_SetError("Memory allocation failure (SDDS_DefineColumn)");
1792 return (-1);
1793 }
1794 }
1795
1796 /* not part of output: */
1797 definition->definition_mode = SDDS_NORMAL_DEFINITION;
1798 if (type == SDDS_STRING)
1799 definition->memory_number = SDDS_CreateRpnMemory(name, 1);
1800 else {
1801 definition->memory_number = SDDS_CreateRpnMemory(name, 0);
1802 }
1803 sprintf(s, "&%s", name);
1804 definition->pointer_number = SDDS_CreateRpnArray(s);
1805
1806 layout->n_columns += 1;
1807 return (layout->n_columns - 1);
1808}
1809
1810/**
1811 * @brief Defines a simple data column within the SDDS dataset.
1812 *
1813 * This function provides a simplified interface for defining a data column in the SDDS dataset.
1814 * It allows the user to specify only the column's name, units, and data type, while omitting optional
1815 * parameters such as symbol, description, format string, and field length. Internally, it calls
1816 * @c SDDS_DefineColumn with default values for the omitted parameters.
1817 *
1818 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset.
1819 * @param[in] name A NULL-terminated string specifying the name of the column. This name must be unique within the dataset.
1820 * @param[in] unit A NULL-terminated string specifying the units of the column. Pass @c NULL if no units are desired.
1821 * @param[in] type An integer representing the data type of the column. Must be one of the following:
1822 * - @c SDDS_LONGDOUBLE
1823 * - @c SDDS_DOUBLE
1824 * - @c SDDS_FLOAT
1825 * - @c SDDS_LONG
1826 * - @c SDDS_ULONG
1827 * - @c SDDS_SHORT
1828 * - @c SDDS_USHORT
1829 * - @c SDDS_CHARACTER
1830 * - @c SDDS_STRING
1831 *
1832 * @return
1833 * - @c 1 on successful definition of the column.
1834 * - @c 0 on failure, with an error message set internally.
1835 *
1836 * @pre
1837 * - The dataset must be initialized and configured for output.
1838 * - The column name must be unique and valid.
1839 *
1840 * @post
1841 * - The column is defined within the dataset with the specified name, units, and type.
1842 * - The dataset's internal structures are updated to include the new column.
1843 *
1844 * @note
1845 * - This function is intended for scenarios where only basic column attributes are needed.
1846 * - Optional parameters such as symbol, description, format string, and field length are set to default values.
1847 *
1848 * @warning
1849 * - Defining a column with an invalid type or name will result in an error.
1850 * - Attempting to define a column with a name that already exists within the dataset will result in an error.
1851 */
1852int32_t SDDS_DefineSimpleColumn(SDDS_DATASET *SDDS_dataset, const char *name, const char *unit, int32_t type) {
1853 if (SDDS_DefineColumn(SDDS_dataset, name, NULL, unit, NULL, NULL, type, 0) < 0)
1854 return 0;
1855 return (1);
1856}
1857
1858/**
1859 * @brief Defines a simple data parameter within the SDDS dataset.
1860 *
1861 * This function provides a simplified interface for defining a data parameter in the SDDS dataset.
1862 * It allows the user to specify only the parameter's name, units, and data type, while omitting
1863 * optional attributes such as symbol, description, format string, and fixed value. Internally,
1864 * it calls @c SDDS_DefineParameter with default values for the omitted parameters.
1865 *
1866 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset.
1867 * @param[in] name A NULL-terminated string specifying the name of the parameter. This name must be unique within the dataset.
1868 * @param[in] unit A NULL-terminated string specifying the units of the parameter. Pass @c NULL if no units are desired.
1869 * @param[in] type An integer representing the data type of the parameter. Must be one of the following:
1870 * - @c SDDS_LONGDOUBLE
1871 * - @c SDDS_DOUBLE
1872 * - @c SDDS_FLOAT
1873 * - @c SDDS_LONG
1874 * - @c SDDS_ULONG
1875 * - @c SDDS_SHORT
1876 * - @c SDDS_USHORT
1877 * - @c SDDS_CHARACTER
1878 * - @c SDDS_STRING
1879 *
1880 * @return
1881 * - @c 1 on successful definition of the parameter.
1882 * - @c 0 on failure, with an error message set internally.
1883 *
1884 * @pre
1885 * - The dataset must be initialized and configured for output.
1886 * - The parameter name must be unique and valid.
1887 *
1888 * @post
1889 * - The parameter is defined within the dataset with the specified name, units, and type.
1890 * - The dataset's internal structures are updated to include the new parameter.
1891 *
1892 * @note
1893 * - This function is intended for scenarios where only basic parameter attributes are needed.
1894 * - Optional parameters such as symbol, description, format string, and fixed value are set to default values.
1895 *
1896 * @warning
1897 * - Defining a parameter with an invalid type or name will result in an error.
1898 * - Attempting to define a parameter with a name that already exists within the dataset will result in an error.
1899 */
1900int32_t SDDS_DefineSimpleParameter(SDDS_DATASET *SDDS_dataset, const char *name, const char *unit, int32_t type) {
1901 if (SDDS_DefineParameter(SDDS_dataset, name, NULL, unit, NULL, NULL, type, NULL) < 0)
1902 return 0;
1903 return (1);
1904}
1905
1906/**
1907 * @brief Defines multiple simple data columns of the same data type within the SDDS dataset.
1908 *
1909 * This function provides a streamlined way to define multiple data columns in the SDDS dataset that share
1910 * the same data type. It allows the user to specify the names and units of the columns, while omitting
1911 * optional attributes such as symbol, description, format string, and field length. Internally, it calls
1912 * @c SDDS_DefineColumn for each column with default values for the omitted parameters.
1913 *
1914 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset.
1915 * @param[in] number The number of columns to define. Must be greater than or equal to @c 0.
1916 * @param[in] name An array of NULL-terminated strings specifying the names of the columns. Each name must be unique within the dataset.
1917 * @param[in] unit An array of NULL-terminated strings specifying the units of the columns. Pass @c NULL for elements where no units are desired.
1918 * @param[in] type An integer representing the data type for all the columns. Must be one of the following:
1919 * - @c SDDS_LONGDOUBLE
1920 * - @c SDDS_DOUBLE
1921 * - @c SDDS_FLOAT
1922 * - @c SDDS_LONG
1923 * - @c SDDS_ULONG
1924 * - @c SDDS_SHORT
1925 * - @c SDDS_USHORT
1926 * - @c SDDS_CHARACTER
1927 * - @c SDDS_STRING
1928 *
1929 * @return
1930 * - @c 1 on successful definition of all specified columns.
1931 * - @c 0 on failure to define any of the columns, with an error message set internally.
1932 *
1933 * @pre
1934 * - The dataset must be initialized and configured for output.
1935 * - The @c name array must contain unique and valid names for each column.
1936 * - The @c type must be a supported data type.
1937 *
1938 * @post
1939 * - All specified columns are defined within the dataset with the provided names and units.
1940 * - The dataset's internal structures are updated to include the new columns.
1941 *
1942 * @note
1943 * - Passing @c number as @c 0 results in no action and returns success.
1944 * - This function is optimized for defining multiple columns of the same type, enhancing code readability and efficiency.
1945 *
1946 * @warning
1947 * - Defining a column with an invalid type or name will result in an error.
1948 * - Attempting to define a column with a name that already exists within the dataset will result in an error.
1949 * - Ensure that the @c name and @c unit arrays are properly allocated and contain valid strings.
1950 */
1951int32_t SDDS_DefineSimpleColumns(SDDS_DATASET *SDDS_dataset, int32_t number, char **name, char **unit, int32_t type) {
1952 int32_t i;
1953 if (!number)
1954 return (1);
1955 if (!name)
1956 return 0;
1957 for (i = 0; i < number; i++)
1958 if (SDDS_DefineColumn(SDDS_dataset, name[i], NULL, unit ? unit[i] : NULL, NULL, NULL, type, 0) < 0)
1959 return 0;
1960 return (1);
1961}
1962
1963/**
1964 * @brief Defines multiple simple data parameters of the same data type within the SDDS dataset.
1965 *
1966 * This function provides a streamlined way to define multiple data parameters in the SDDS dataset that share
1967 * the same data type. It allows the user to specify the names and units of the parameters, while omitting
1968 * optional attributes such as symbol, description, format string, and fixed value. Internally, it calls
1969 * @c SDDS_DefineParameter for each parameter with default values for the omitted parameters.
1970 *
1971 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset.
1972 * @param[in] number The number of parameters to define. Must be greater than or equal to @c 0.
1973 * @param[in] name An array of NULL-terminated strings specifying the names of the parameters. Each name must be unique within the dataset.
1974 * @param[in] unit An array of NULL-terminated strings specifying the units of the parameters. Pass @c NULL for elements where no units are desired.
1975 * @param[in] type An integer representing the data type for all the parameters. Must be one of the following:
1976 * - @c SDDS_LONGDOUBLE
1977 * - @c SDDS_DOUBLE
1978 * - @c SDDS_FLOAT
1979 * - @c SDDS_LONG
1980 * - @c SDDS_ULONG
1981 * - @c SDDS_SHORT
1982 * - @c SDDS_USHORT
1983 * - @c SDDS_CHARACTER
1984 * - @c SDDS_STRING
1985 *
1986 * @return
1987 * - @c 1 on successful definition of all specified parameters.
1988 * - @c 0 on failure to define any of the parameters, with an error message set internally.
1989 *
1990 * @pre
1991 * - The dataset must be initialized and configured for output.
1992 * - The @c name array must contain unique and valid names for each parameter.
1993 * - The @c type must be a supported data type.
1994 *
1995 * @post
1996 * - All specified parameters are defined within the dataset with the provided names and units.
1997 * - The dataset's internal structures are updated to include the new parameters.
1998 *
1999 * @note
2000 * - Passing @c number as @c 0 results in no action and returns success.
2001 * - This function is optimized for defining multiple parameters of the same type, enhancing code readability and efficiency.
2002 *
2003 * @warning
2004 * - Defining a parameter with an invalid type or name will result in an error.
2005 * - Attempting to define a parameter with a name that already exists within the dataset will result in an error.
2006 * - Ensure that the @c name and @c unit arrays are properly allocated and contain valid strings.
2007 */
2008int32_t SDDS_DefineSimpleParameters(SDDS_DATASET *SDDS_dataset, int32_t number, char **name, char **unit, int32_t type) {
2009 int32_t i;
2010 if (!number)
2011 return (1);
2012 if (!name)
2013 return 0;
2014 for (i = 0; i < number; i++)
2015 if (SDDS_DefineParameter(SDDS_dataset, name[i], NULL, unit ? unit[i] : NULL, NULL, NULL, type, NULL) < 0)
2016 return 0;
2017 return (1);
2018}
2019
2020static uint32_t nameValidityFlags = 0;
2021/**
2022 * @brief Sets the validity flags for parameter and column names in the SDDS dataset.
2023 *
2024 * This function allows the user to configure the rules for validating names of parameters and columns
2025 * within the SDDS dataset. The validity flags determine the set of allowed characters and naming conventions.
2026 *
2027 * @param[in] flags A bitmask representing the desired name validity flags. Possible flags include:
2028 * - @c SDDS_ALLOW_ANY_NAME: Allows any name without restrictions.
2029 * - @c SDDS_ALLOW_V15_NAME: Enables compatibility with SDDS version 1.5 naming conventions.
2030 * - Additional flags as defined in the SDDS library.
2031 *
2032 * @return
2033 * - The previous name validity flags before the update.
2034 *
2035 * @pre
2036 * - The function can be called at any time before defining parameters or columns to influence name validation.
2037 *
2038 * @post
2039 * - The name validity flags are updated to reflect the specified rules.
2040 *
2041 * @note
2042 * - Changing name validity flags affects how subsequent parameter and column names are validated.
2043 * - It is recommended to set the desired validity flags before defining any dataset elements to avoid validation errors.
2044 *
2045 * @warning
2046 * - Improperly setting validity flags may lead to unintended acceptance or rejection of valid or invalid names.
2047 * - Ensure that the flags are set according to the desired naming conventions for your dataset.
2048 */
2049int32_t SDDS_SetNameValidityFlags(uint32_t flags) {
2050 uint32_t oldFlags;
2051 oldFlags = nameValidityFlags;
2052 nameValidityFlags = flags;
2053 return oldFlags;
2054}
2055
2056/**
2057 * @brief Checks if a given name is valid for a specified class within the SDDS dataset.
2058 *
2059 * This function validates whether the provided name adheres to the naming conventions and rules
2060 * defined by the current name validity flags for the specified class (e.g., parameter, column).
2061 * It ensures that the name contains only allowed characters and follows the required structure.
2062 *
2063 * @param[in] name The name to be validated. Must be a NULL-terminated string.
2064 * @param[in] class The class type to which the name belongs (e.g., "parameter", "column"). This is used
2065 * primarily for error reporting.
2066 *
2067 * @return
2068 * - @c 1 if the name is valid for the specified class.
2069 * - @c 0 if the name is invalid, with an error message set internally.
2070 *
2071 * @pre
2072 * - The name must be a valid NULL-terminated string.
2073 * - The class must be a valid NULL-terminated string representing a recognized class type.
2074 *
2075 * @post
2076 * - If the name is invalid, an error message is recorded detailing the reason.
2077 *
2078 * @note
2079 * - The validation rules are influenced by the current name validity flags set via @c SDDS_SetNameValidityFlags.
2080 * - Environment variables or other configuration settings may also affect name validity.
2081 *
2082 * @warning
2083 * - Using names that do not adhere to the validation rules will result in parameters or columns not being defined.
2084 * - Ensure that all names meet the required standards before attempting to define dataset elements.
2085 */
2086int32_t SDDS_IsValidName(const char *name, const char *class) {
2087 char *ptr;
2088 int32_t isValid = 1;
2089 char s[SDDS_MAXLINE];
2090 static char *validChars = "@:#+%-._$&/[]";
2091 static char *startChars = ".:";
2092
2093 if (nameValidityFlags & SDDS_ALLOW_ANY_NAME)
2094 return 1;
2095 ptr = (char *)name;
2096 if (strlen(name) == 0)
2097 isValid = 0;
2098 else if (!(nameValidityFlags & SDDS_ALLOW_V15_NAME)) {
2099 /* post V1.5 allows only alpha and startChars members as first character */
2100 /* V1.5 allows alpha, digits, and any validChars members */
2101 if (!(isalpha(*ptr) || strchr(startChars, *ptr)))
2102 isValid = 0;
2103 }
2104 while (isValid && *ptr) {
2105 if (!(isalnum(*ptr) || strchr(validChars, *ptr)))
2106 isValid = 0;
2107 ptr++;
2108 }
2109 if (!isValid) {
2110 sprintf(s, "The following %s name is invalid: >%s<\n(sddsconvert may be used to change the name)\n", class, name);
2111 SDDS_SetError(s);
2112 return 0;
2113 }
2114 return 1;
2115}
2116
2117/**
2118 * @brief Defines an associate for the SDDS dataset.
2119 *
2120 * This function defines an associate for the SDDS dataset, allowing the association of additional
2121 * files or data with the primary dataset. Associates can provide supplementary information or link
2122 * related datasets together. The function sets up the necessary attributes such as name, filename,
2123 * path, description, contents, and SDDS flag to describe the associate.
2124 *
2125 * **Note:** This function is **NOT USED** in the current implementation and will always return @c 0
2126 * unless compiled with @c RW_ASSOCIATES defined.
2127 *
2128 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset.
2129 * @param[in] name A NULL-terminated string specifying the name of the associate. This name must be unique within the dataset.
2130 * @param[in] filename A NULL-terminated string specifying the filename of the associate. Must be a valid filename.
2131 * @param[in] path A NULL-terminated string specifying the path to the associate. Pass @c NULL if no path is desired.
2132 * @param[in] description A NULL-terminated string providing a description of the associate. Pass @c NULL if no description is desired.
2133 * @param[in] contents A NULL-terminated string detailing the contents of the associate. Pass @c NULL if no contents are desired.
2134 * @param[in] sdds An integer flag indicating the type of associate. Typically used to specify whether the associate is an SDDS file.
2135 *
2136 * @return
2137 * - On success, returns the index of the newly defined associate within the dataset.
2138 * - Returns a negative value on failure, with an error message set internally.
2139 * - Returns @c 0 if @c RW_ASSOCIATES is not defined.
2140 *
2141 * @pre
2142 * - The dataset must be initialized and configured for output.
2143 * - @c RW_ASSOCIATES must be defined during compilation to use this feature.
2144 * - The associate name and filename must be unique and valid.
2145 *
2146 * @post
2147 * - The associate is defined within the dataset with the specified attributes.
2148 * - The dataset's internal structures are updated to include the new associate.
2149 *
2150 * @note
2151 * - Associates provide a mechanism to link additional data or files to the primary SDDS dataset.
2152 * - Properly defining associates can enhance data organization and accessibility.
2153 *
2154 * @warning
2155 * - Defining an associate with an invalid type, name, or filename will result in an error.
2156 * - Attempting to define an associate with a name that already exists within the dataset will result in an error.
2157 * - Ensure that the @c filename and @c path (if provided) are valid and accessible.
2158 */
2159int32_t SDDS_DefineAssociate(SDDS_DATASET *SDDS_dataset, const char *name, const char *filename, const char *path, const char *description, const char *contents, int32_t sdds) {
2160
2161#if RW_ASSOCIATES == 0
2162 return 0;
2163#else
2164 SDDS_LAYOUT *layout;
2165 ASSOCIATE_DEFINITION *definition;
2166 char s[SDDS_MAXLINE];
2167 if (!SDDS_IsValidName(name, "associate"))
2168 return -1;
2169 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_DefineAssociate"))
2170 return (-1);
2171 layout = &SDDS_dataset->layout;
2172 if (!(layout->associate_definition = SDDS_Realloc(layout->associate_definition, sizeof(*layout->associate_definition) * (layout->n_associates + 1)))) {
2173 SDDS_SetError("Memory allocation failure (SDDS_DefineAssociate)");
2174 return (-1);
2175 }
2176 if (!name) {
2177 SDDS_SetError("NULL name not allowed for associate file (SDDS_DefineAssociate)");
2178 return (-1);
2179 }
2180 if (!filename) {
2181 SDDS_SetError("NULL filename not allowed for associate file (SDDS_DefineAssociate)");
2182 return (-1);
2183 }
2184 if (SDDS_GetAssociateIndex(SDDS_dataset, name) >= 0) {
2185 sprintf(s, "Associate with name %s already exists (SDDS_DefineAssociate)", name);
2186 SDDS_SetError(s);
2187 return (-1);
2188 }
2189 if (!SDDS_ZeroMemory(definition = layout->associate_definition + layout->n_associates, sizeof(ASSOCIATE_DEFINITION))) {
2190 SDDS_SetError("Unable to define associate--can't zero memory for associate (SDDS_DefineAssociate)");
2191 return (-1);
2192 }
2193
2194 if (!SDDS_CopyString(&definition->name, name)) {
2195 SDDS_SetError("Memory allocation failure (SDDS_DefineAssociate)");
2196 return (-1);
2197 }
2198 if (!SDDS_CopyString(&definition->filename, filename)) {
2199 SDDS_SetError("Memory allocation failure (SDDS_DefineAssociate)");
2200 return (-1);
2201 }
2202 if (path && !SDDS_CopyString(&definition->path, path)) {
2203 SDDS_SetError("Memory allocation failure (SDDS_DefineAssociate)");
2204 return (-1);
2205 }
2206 if (contents && !SDDS_CopyString(&definition->contents, contents)) {
2207 SDDS_SetError("Memory allocation failure (SDDS_DefineAssociate)");
2208 return (-1);
2209 }
2210 if (description && !SDDS_CopyString(&definition->description, description)) {
2211 SDDS_SetError("Memory allocation failure (SDDS_DefineAssociate)");
2212 return (-1);
2213 }
2214 definition->sdds = sdds;
2215 layout->n_associates += 1;
2216 return (layout->n_associates - 1);
2217#endif
2218}
2219
2220/**
2221 * @brief Erases all data entries in the SDDS dataset.
2222 *
2223 * This function removes all data from the specified SDDS dataset, effectively resetting it to an empty state.
2224 * It frees any allocated memory associated with data columns, parameters, and arrays, ensuring that
2225 * all dynamic data is properly cleared. This is useful for reusing the dataset for new data without
2226 * retaining previous entries.
2227 *
2228 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset.
2229 *
2230 * @return
2231 * - @c 1 on successful erasure of all data.
2232 * - @c 0 on failure, with an error message set internally.
2233 *
2234 * @pre
2235 * - The dataset must be initialized and configured.
2236 *
2237 * @post
2238 * - All data rows are removed from the dataset.
2239 * - Memory allocated for data columns, parameters, and arrays is freed.
2240 * - The dataset is ready to accept new data entries.
2241 *
2242 * @note
2243 * - This function does not alter the dataset's layout definitions; only the data entries are cleared.
2244 * - After erasing data, the dataset can be reused to write new data tables without redefining the layout.
2245 *
2246 * @warning
2247 * - Erasing data is irreversible; ensure that any necessary data is backed up before calling this function.
2248 * - Concurrent access to the dataset while erasing data may lead to undefined behavior.
2249 */
2250int32_t SDDS_EraseData(SDDS_DATASET *SDDS_dataset) {
2251 SDDS_LAYOUT *layout;
2252 int64_t i, j;
2253 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_EraseData"))
2254 return 0;
2255 layout = &SDDS_dataset->layout;
2256 if (SDDS_dataset->data) {
2257 for (i = 0; i < layout->n_columns; i++) {
2258 if (!SDDS_dataset->data[i])
2259 continue;
2260 if (layout->column_definition[i].type == SDDS_STRING) {
2261 for (j = 0; j < SDDS_dataset->n_rows; j++) {
2262 if (((char **)SDDS_dataset->data[i])[j]) {
2263 free(((char **)SDDS_dataset->data[i])[j]);
2264 ((char **)SDDS_dataset->data[i])[j] = NULL;
2265 }
2266 }
2267 }
2268 }
2269 }
2270 SDDS_dataset->n_rows = 0;
2271
2272 if (SDDS_dataset->parameter) {
2273 for (i = 0; i < layout->n_parameters; i++) {
2274 if (!SDDS_dataset->parameter[i])
2275 continue;
2276 if (layout->parameter_definition[i].type == SDDS_STRING && *(char **)(SDDS_dataset->parameter[i])) {
2277 free(*(char **)(SDDS_dataset->parameter[i]));
2278 *(char **)SDDS_dataset->parameter[i] = NULL;
2279 }
2280 }
2281 }
2282
2283 if (SDDS_dataset->array) {
2284 for (i = 0; i < layout->n_arrays; i++) {
2285 if (SDDS_dataset->array[i].definition->type == SDDS_STRING) {
2286 for (j = 0; j < SDDS_dataset->array[i].elements; j++) {
2287 if (((char **)SDDS_dataset->array[i].data)[j]) {
2288 free(((char **)SDDS_dataset->array[i].data)[j]);
2289 ((char **)SDDS_dataset->array[i].data)[j] = NULL;
2290 }
2291 }
2292 }
2293 }
2294 }
2295
2296 return (1);
2297}
2298
2299/**
2300 * @brief Sets the row count mode for the SDDS dataset.
2301 *
2302 * This function configures how row counts are managed within the SDDS dataset. The row count mode
2303 * determines whether row counts are variable, fixed, or entirely omitted during data writing.
2304 * Proper configuration of row count modes can enhance data integrity and performance based on
2305 * specific use cases.
2306 *
2307 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset.
2308 * @param[in] mode The row count mode to be set. Must be one of the following:
2309 * - @c SDDS_VARIABLEROWCOUNT: Enables variable row counts, allowing the number of rows to vary.
2310 * - @c SDDS_FIXEDROWCOUNT: Sets a fixed row count mode, where the number of rows is constant.
2311 * - @c SDDS_NOROWCOUNT: Disables row counts, omitting them from the dataset.
2312 *
2313 * @return
2314 * - @c 1 on successful configuration of the row count mode.
2315 * - @c 0 on failure, with an error message set internally.
2316 *
2317 * @pre
2318 * - The dataset must be initialized and configured for output.
2319 * - The layout must not have been written to the file yet.
2320 *
2321 * @post
2322 * - The dataset's row count mode is updated according to the specified mode.
2323 *
2324 * @note
2325 * - Changing the row count mode affects how row metadata is handled during data writing.
2326 * - The @c SDDS_FIXEDROWCOUNT mode may require specifying additional parameters such as row increment.
2327 *
2328 * @warning
2329 * - Attempting to change the row count mode after the layout has been written to the file or while reading from a file will result in an error.
2330 * - Selecting an invalid row count mode will result in an error.
2331 */
2332int32_t SDDS_SetRowCountMode(SDDS_DATASET *SDDS_dataset, uint32_t mode) {
2333 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_SetRowCountMode"))
2334 return 0;
2335 if (SDDS_dataset->layout.layout_written) {
2336 SDDS_SetError("Can't change row count mode after writing the layout, or for a file you are reading.");
2337 return 0;
2338 }
2339 if (mode & SDDS_VARIABLEROWCOUNT) {
2340 SDDS_dataset->layout.data_mode.fixed_row_count = 0;
2341 SDDS_dataset->layout.data_mode.no_row_counts = 0;
2342 } else if (mode & SDDS_FIXEDROWCOUNT) {
2343 SDDS_dataset->layout.data_mode.fixed_row_count = 1;
2344 SDDS_dataset->layout.data_mode.fixed_row_increment = 500;
2345 SDDS_dataset->layout.data_mode.no_row_counts = 0;
2346 SDDS_dataset->layout.data_mode.fsync_data = 0;
2347 } else if (mode & SDDS_NOROWCOUNT) {
2348 SDDS_dataset->layout.data_mode.fixed_row_count = 0;
2349 SDDS_dataset->layout.data_mode.no_row_counts = 1;
2350 } else {
2351 SDDS_SetError("Invalid row count mode (SDDS_SetRowCountMode).");
2352 return 0;
2353 }
2354 if (!SDDS_SaveLayout(SDDS_dataset))
2355 return 0;
2356 return 1;
2357}
2358
2359/**
2360 * @brief Disables file synchronization for the SDDS dataset.
2361 *
2362 * This function disables the file synchronization feature for the specified SDDS dataset. File synchronization
2363 * ensures that all buffered data is immediately written to disk, enhancing data integrity. By disabling
2364 * this feature, the dataset will no longer perform synchronous writes, which can improve performance
2365 * but may risk data loss in the event of a system failure.
2366 *
2367 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset.
2368 *
2369 * @post
2370 * - File synchronization is disabled, meaning that @c SDDS_SyncDataSet will not call @c fsync.
2371 *
2372 * @note
2373 * - Disabling file synchronization can lead to improved performance, especially when writing large datasets.
2374 * - It is recommended to use this function only when performance is a higher priority than immediate data integrity.
2375 *
2376 * @warning
2377 * - Without file synchronization, there is a risk of data loss if the system crashes before buffered data is written to disk.
2378 * - Ensure that data integrity is managed through other means if synchronization is disabled.
2379 */
2380void SDDS_DisableFSync(SDDS_DATASET *SDDS_dataset) {
2381 SDDS_dataset->layout.data_mode.fsync_data = 0;
2382}
2383
2384/**
2385 * @brief Enables file synchronization for the SDDS dataset.
2386 *
2387 * This function enables the file synchronization feature for the specified SDDS dataset. File synchronization
2388 * ensures that all buffered data is immediately written to disk, enhancing data integrity. Enabling this
2389 * feature can be crucial for applications where data consistency and reliability are paramount.
2390 *
2391 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure representing the dataset.
2392 *
2393 * @post
2394 * - File synchronization is enabled, meaning that @c SDDS_SyncDataSet will call @c fsync to flush buffers to disk.
2395 *
2396 * @note
2397 * - Enabling file synchronization may impact performance due to the increased number of disk write operations.
2398 * - It is recommended to enable synchronization when data integrity is critical, such as in transactional systems.
2399 *
2400 * @warning
2401 * - Frequent synchronization can lead to reduced performance, especially when writing large amounts of data.
2402 * - Balance the need for data integrity with performance requirements based on the specific use case.
2403 */
2404void SDDS_EnableFSync(SDDS_DATASET *SDDS_dataset) {
2405 SDDS_dataset->layout.data_mode.fsync_data = 1;
2406}
2407
2408/**
2409 * @brief Synchronizes the SDDS dataset's file to disk.
2410 *
2411 * Performs a file synchronization operation on the specified SDDS dataset to ensure that
2412 * all buffered data is flushed to the storage medium. This is crucial for maintaining
2413 * data integrity, especially in scenarios where unexpected shutdowns or crashes may occur.
2414 *
2415 * ## Platform-Specific Behavior
2416 * - **vxWorks, Windows (_WIN32), macOS (__APPLE__)**:
2417 * - The function assumes that synchronization is always successful and returns `1`.
2418 * - **Other Platforms**:
2419 * - Attempts to flush the dataset's file buffer to disk using the `fsync` system call.
2420 * - Returns `1` if `fsync` succeeds, indicating successful synchronization.
2421 * - Returns `0` if `fsync` fails or if the dataset/file pointer is invalid.
2422 *
2423 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset
2424 * to be synchronized.
2425 * @return int32_t
2426 * - `1` on successful synchronization.
2427 * - `0` on failure.
2428 */
2429int32_t SDDS_DoFSync(SDDS_DATASET *SDDS_dataset) {
2430#if defined(vxWorks) || defined(_WIN32) || defined(__APPLE__)
2431 return 1;
2432#else
2433 if (SDDS_dataset && SDDS_dataset->layout.fp)
2434 return fsync(fileno(SDDS_dataset->layout.fp)) == 0;
2435 return 0;
2436#endif
2437}
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_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_SetDefaultIOBufferSize(int32_t newValue)
Definition SDDS_binary.c:66
void SDDS_SwapLong64(int64_t *data)
Swaps the endianness of a 64-bit integer.
int32_t SDDS_UpdateBinaryPage(SDDS_DATASET *SDDS_dataset, uint32_t mode)
Updates the binary page of an SDDS dataset.
void SDDS_SwapLong(int32_t *data)
Swaps the endianness of a 32-bit integer.
int32_t SDDS_WriteBinaryPage(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_SaveLayout(SDDS_DATASET *SDDS_dataset)
Definition SDDS_copy.c:615
int32_t SDDS_type_size[SDDS_NUM_TYPES]
Array of sizes for each supported data type.
Definition SDDS_data.c:62
char * SDDS_data_mode[SDDS_NUM_DATA_MODES]
Array of supported data modes.
Definition SDDS_data.c:33
int32_t SDDS_StartPage(SDDS_DATASET *SDDS_dataset, int64_t expected_n_rows)
int32_t SDDS_ReadLayout(SDDS_DATASET *SDDS_dataset, FILE *fp)
Definition SDDS_input.c:517
int32_t SDDS_ReadPageSparse(SDDS_DATASET *SDDS_dataset, uint32_t mode, int64_t sparse_interval, int64_t sparse_offset, int32_t sparse_statistics)
Internal definitions and function declarations for SDDS with LZMA support.
int32_t SDDS_LZMAWriteVersion(int32_t version_number, struct lzmafile *lzmafp)
Writes the SDDS protocol version to an LZMA-compressed file.
Definition SDDS_write.c:77
int32_t SDDS_LZMAWriteArrayDefinition(ARRAY_DEFINITION *array_definition, struct lzmafile *lzmafp)
Writes an array definition to an LZMA-compressed file.
Definition SDDS_write.c:722
int32_t SDDS_LZMAWriteColumnDefinition(COLUMN_DEFINITION *column, struct lzmafile *lzmafp)
Writes a column definition to an LZMA-compressed file.
Definition SDDS_write.c:356
int32_t SDDS_WriteAssociateDefinition(ASSOCIATE_DEFINITION *associate, FILE *fp)
Writes an associate definition to a standard file.
Definition SDDS_write.c:493
int32_t SDDS_LZMAWriteDescription(char *description, char *contents, struct lzmafile *lzmafp)
Writes the SDDS description section to an LZMA-compressed file.
Definition SDDS_write.c:280
int32_t SDDS_WriteVersion(int32_t version_number, FILE *fp)
Writes the SDDS protocol version to a standard file.
Definition SDDS_write.c:59
int32_t SDDS_WriteColumnDefinition(COLUMN_DEFINITION *column, FILE *fp)
Writes a column definition to a standard file.
Definition SDDS_write.c:329
int32_t SDDS_LZMAWriteDataMode(SDDS_LAYOUT *layout, struct lzmafile *lzmafp)
Writes the data mode section to an LZMA-compressed file.
Definition SDDS_write.c:614
int32_t SDDS_WriteArrayDefinition(ARRAY_DEFINITION *array_definition, FILE *fp)
Writes an array definition to a standard file.
Definition SDDS_write.c:692
int32_t SDDS_LZMAWriteAssociateDefinition(ASSOCIATE_DEFINITION *associate, struct lzmafile *lzmafp)
Writes an associate definition to an LZMA-compressed file.
Definition SDDS_write.c:520
int32_t SDDS_WriteDataMode(SDDS_LAYOUT *layout, FILE *fp)
Writes the data mode section to a standard file.
Definition SDDS_write.c:576
int32_t SDDS_WriteParameterDefinition(PARAMETER_DEFINITION *parameter, FILE *fp)
Writes a parameter definition to a standard file.
Definition SDDS_write.c:411
int32_t SDDS_WriteDescription(char *description, char *contents, FILE *fp)
Writes the SDDS description section to a standard file.
Definition SDDS_write.c:256
int32_t SDDS_LZMAWriteParameterDefinition(PARAMETER_DEFINITION *parameter, struct lzmafile *lzmafp)
Writes a parameter definition to an LZMA-compressed file.
Definition SDDS_write.c:438
void SDDS_DisableFSync(SDDS_DATASET *SDDS_dataset)
Disables file synchronization for the SDDS dataset.
int32_t SDDS_DefineParameter1(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, void *fixed_value)
Defines a data parameter with a fixed numerical value.
int32_t SDDS_InitializeAppend(SDDS_DATASET *SDDS_dataset, const char *filename)
Initializes the SDDS dataset for appending data by adding a new page to an existing file.
int32_t SDDS_InitializeOutput(SDDS_DATASET *SDDS_dataset, int32_t data_mode, int32_t lines_per_row, const char *description, const char *contents, const char *filename)
Initializes the SDDS output dataset.
int32_t SDDS_InitializeAppendToPage(SDDS_DATASET *SDDS_dataset, const char *filename, int64_t updateInterval, int64_t *rowsPresentReturn)
Initializes the SDDS dataset for appending data to the last page of an existing file.
int32_t SDDS_DefineSimpleColumn(SDDS_DATASET *SDDS_dataset, const char *name, const char *unit, int32_t type)
Defines a simple data column within the SDDS dataset.
int32_t SDDS_EraseData(SDDS_DATASET *SDDS_dataset)
Erases all data entries in the SDDS dataset.
int32_t SDDS_DisconnectFile(SDDS_DATASET *SDDS_dataset)
Disconnects the SDDS dataset from its associated file.
Definition SDDS_output.c:70
int32_t SDDS_SyncDataSet(SDDS_DATASET *SDDS_dataset)
Synchronizes the SDDS dataset with the disk by flushing buffered data.
int32_t SDDS_DefineAssociate(SDDS_DATASET *SDDS_dataset, const char *name, const char *filename, const char *path, const char *description, const char *contents, int32_t sdds)
Defines an associate for the SDDS dataset.
int32_t SDDS_Parallel_InitializeOutput(SDDS_DATASET *SDDS_dataset, const char *description, const char *contents, const char *filename)
Initializes the SDDS output dataset for parallel processing.
void SDDS_EnableFSync(SDDS_DATASET *SDDS_dataset)
Enables file synchronization for the SDDS dataset.
int32_t SDDS_DefineSimpleParameters(SDDS_DATASET *SDDS_dataset, int32_t number, char **name, char **unit, int32_t type)
Defines multiple simple data parameters of the same data type within the SDDS dataset.
int32_t SDDS_DefineSimpleParameter(SDDS_DATASET *SDDS_dataset, const char *name, const char *unit, int32_t type)
Defines a simple data parameter within the SDDS dataset.
int32_t SDDS_SetRowCountMode(SDDS_DATASET *SDDS_dataset, uint32_t mode)
Sets the row count mode for the SDDS dataset.
int32_t SDDS_DefineArray(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, int32_t field_length, int32_t dimensions, const char *group_name)
Defines a data array within the SDDS dataset.
int32_t SDDS_DefineSimpleColumns(SDDS_DATASET *SDDS_dataset, int32_t number, char **name, char **unit, int32_t type)
Defines multiple simple data columns of the same data type within the SDDS dataset.
int32_t SDDS_ReconnectInputFile(SDDS_DATASET *SDDS_dataset, long position)
Reconnects the input file for the SDDS dataset at a specified position.
int32_t SDDS_DoFSync(SDDS_DATASET *SDDS_dataset)
Synchronizes the SDDS dataset's file to disk.
int32_t SDDS_UpdatePage(SDDS_DATASET *SDDS_dataset, uint32_t mode)
Updates the current page of the SDDS dataset.
int32_t SDDS_SetNameValidityFlags(uint32_t flags)
Sets the validity flags for parameter and column names in the SDDS dataset.
int32_t SDDS_SetNoRowCounts(SDDS_DATASET *SDDS_dataset, int32_t value)
Sets the flag to enable or disable row counts in the SDDS dataset.
int32_t SDDS_WritePage(SDDS_DATASET *SDDS_dataset)
Writes the current data table to the output file.
int32_t SDDS_DefineColumn(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, int32_t field_length)
Defines a data column within the SDDS dataset.
int32_t SDDS_WriteLayout(SDDS_DATASET *SDDS_dataset)
Writes the SDDS layout header to the output file.
int32_t SDDS_ReconnectFile(SDDS_DATASET *SDDS_dataset)
Reconnects the SDDS dataset to its previously associated file.
int32_t SDDS_IsValidName(const char *name, const char *class)
Checks if a given name is valid for a specified class within the SDDS dataset.
long SDDS_DisconnectInputFile(SDDS_DATASET *SDDS_dataset)
Disconnects the input file from the SDDS dataset.
int32_t SDDS_DefineParameter(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, char *fixed_value)
Defines a data parameter with a fixed string value.
int64_t SDDS_CreateRpnMemory(const char *name, short is_string)
Stub function for creating RPN memory when RPN_SUPPORT is not enabled.
Definition SDDS_rpn.c:785
int64_t SDDS_CreateRpnArray(char *name)
Stub function for creating RPN arrays when RPN_SUPPORT is not enabled.
Definition SDDS_rpn.c:795
int32_t SDDS_FileIsLocked(const char *filename)
Determines if a specified file is locked.
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.
int SDDS_CompareIndexedNames(const void *s1, const void *s2)
Compares two SORTED_INDEX structures by their name fields.
int32_t SDDS_VerifyPrintfFormat(const char *string, int32_t type)
Verifies that a printf format string is compatible with a specified data type.
Definition SDDS_utils.c:750
int32_t SDDS_SprintTypedValue(void *data, int64_t index, int32_t type, const char *format, char *buffer, uint32_t mode)
Formats a data value of a specified type into a string buffer using an optional printf format string.
Definition SDDS_utils.c:151
int32_t SDDS_SetMemory(void *mem, int64_t n_elements, int32_t data_type,...)
Initializes a memory block with a sequence of values based on a specified data type.
int32_t SDDS_CheckDataset(SDDS_DATASET *SDDS_dataset, const char *caller)
Validates the SDDS dataset pointer.
Definition SDDS_utils.c:552
void * SDDS_Malloc(size_t size)
Allocates memory of a specified size.
Definition SDDS_utils.c:639
int32_t SDDS_LockFile(FILE *fp, const char *filename, const char *caller)
Attempts to lock a specified file.
int32_t SDDS_GetAssociateIndex(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the index of a named associate in the SDDS dataset.
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
int32_t SDDS_IsBigEndianMachine()
Determines whether the current machine uses big-endian byte ordering.
void * SDDS_Realloc(void *old_ptr, size_t new_size)
Reallocates memory to a new size.
Definition SDDS_utils.c:677
int32_t SDDS_MPI_WriteLayout(SDDS_DATASET *SDDS_dataset)
Writes the layout of the SDDS dataset to the MPI file.
int32_t SDDS_MPI_ReconnectFile(SDDS_DATASET *SDDS_dataset)
Reconnects the MPI file associated with the SDDS dataset.
int32_t SDDS_MPI_DisconnectFile(SDDS_DATASET *SDDS_dataset)
Disconnects the MPI file associated with the SDDS dataset.
int32_t SDDS_MPI_WritePage(SDDS_DATASET *SDDS_dataset)
Writes a page of data to the MPI file associated with the SDDS dataset.
#define SDDS_NUM_TYPES
Total number of defined SDDS data types.
Definition SDDStypes.h:97
#define SDDS_ULONG
Identifier for the unsigned 32-bit integer data type.
Definition SDDStypes.h:67
#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_LONG
Identifier for the signed 32-bit integer data type.
Definition SDDStypes.h:61
#define SDDS_USHORT
Identifier for the unsigned short integer data type.
Definition SDDStypes.h:79
#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
long binaryInsert(void **array, long members, void *newMember, int(*compare)(const void *c1, const void *c2), int32_t *duplicate)
Inserts a new member into a sorted array using binary search.
Definition binsert.c:39