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