SDDSlib
Loading...
Searching...
No Matches
SDDS_utils.c
Go to the documentation of this file.
1/**
2 * @file SDDS_utils.c
3 * @brief This file provides miscellaneous functions for interacting with SDDS objects.
4 *
5 * This file provides miscellaneous functions for interacting with SDDS objects.
6 *
7 * @copyright
8 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
9 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
10 *
11 * @license
12 * This file is distributed under the terms of the Software License Agreement
13 * found in the file LICENSE included with this distribution.
14 *
15 * @author M. Borland, C. Saunders, R. Soliday. H. Shang
16 */
17
18#include "SDDS.h"
19#include "SDDS_internal.h"
20#include "mdb.h"
21#include <ctype.h>
22#if !defined(_WIN32)
23# include <unistd.h>
24#endif
25#if defined(__APPLE__)
26/*lockf is not defined by unistd.h like it should be*/
27int lockf(int filedes, int function, off_t size);
28#endif
29
30/**
31 * @brief Prints a data value of a specified type using an optional printf format string.
32 *
33 * This function prints a single data value from a data array based on the specified type and index. It supports various data types defined by SDDS constants and allows customization of the output format.
34 *
35 * @param[in] data Pointer to the base address of the data array to be printed.
36 * @param[in] index The index of the item within the data array to be printed.
37 * @param[in] type The data type of the value to be printed, specified by one of the SDDS constants:
38 * - `SDDS_LONGDOUBLE`
39 * - `SDDS_DOUBLE`
40 * - `SDDS_FLOAT`
41 * - `SDDS_LONG`
42 * - `SDDS_ULONG`
43 * - `SDDS_SHORT`
44 * - `SDDS_USHORT`
45 * - `SDDS_CHARACTER`
46 * - `SDDS_STRING`
47 * @param[in] format (Optional) NULL-terminated string specifying a `printf` format. If `NULL`, a default format is used based on the data type.
48 * @param[in] fp Pointer to the `FILE` stream where the data will be printed.
49 * @param[in] mode Flags controlling the printing behavior. Valid values are:
50 * - `0`: Default behavior.
51 * - `SDDS_PRINT_NOQUOTES`: When printing strings, do not enclose them in quotes.
52 *
53 * @return Returns `1` on success. On failure, returns `0` and records an error message.
54 *
55 * @note This function assumes that the `data` pointer points to an array of the specified `type`, and `index` is within the bounds of this array.
56 *
57 * @see SDDS_SetError
58 */
59int32_t SDDS_PrintTypedValue(void *data, int64_t index, int32_t type, char *format, FILE *fp, uint32_t mode) {
60 char buffer[SDDS_PRINT_BUFLEN], *s;
61
62 if (!data) {
63 SDDS_SetError("Unable to print value--data pointer is NULL (SDDS_PrintTypedValue)");
64 return (0);
65 }
66 if (!fp) {
67 SDDS_SetError("Unable to print value--file pointer is NULL (SDDS_PrintTypedValue)");
68 return (0);
69 }
70 switch (type) {
71 case SDDS_SHORT:
72 fprintf(fp, format ? format : "%hd", *((short *)data + index));
73 break;
74 case SDDS_USHORT:
75 fprintf(fp, format ? format : "%hu", *((unsigned short *)data + index));
76 break;
77 case SDDS_LONG:
78 fprintf(fp, format ? format : "%" PRId32, *((int32_t *)data + index));
79 break;
80 case SDDS_ULONG:
81 fprintf(fp, format ? format : "%" PRIu32, *((uint32_t *)data + index));
82 break;
83 case SDDS_LONG64:
84 fprintf(fp, format ? format : "%" PRId64, *((int64_t *)data + index));
85 break;
86 case SDDS_ULONG64:
87 fprintf(fp, format ? format : "%" PRIu64, *((uint64_t *)data + index));
88 break;
89 case SDDS_FLOAT:
90 fprintf(fp, format ? format : "%15.8e", *((float *)data + index));
91 break;
92 case SDDS_DOUBLE:
93 fprintf(fp, format ? format : "%21.15e", *((double *)data + index));
94 break;
95 case SDDS_LONGDOUBLE:
96 if (LDBL_DIG == 18) {
97 fprintf(fp, format ? format : "%21.18Le", *((long double *)data + index));
98 } else {
99 fprintf(fp, format ? format : "%21.15Le", *((long double *)data + index));
100 }
101 break;
102 case SDDS_STRING:
103 s = *((char **)data + index);
104 if ((int32_t)strlen(s) > SDDS_PRINT_BUFLEN - 3) {
105 SDDS_SetError("Buffer size overflow (SDDS_PrintTypedValue)");
106 return 0;
107 }
108 SDDS_SprintTypedValue(data, index, type, format, buffer, mode);
109 fputs(buffer, fp);
110 break;
111 case SDDS_CHARACTER:
112 fprintf(fp, format ? format : "%c", *((char *)data + index));
113 break;
114 default:
115 SDDS_SetError("Unable to print value--unknown data type (SDDS_PrintTypedValue)");
116 return (0);
117 }
118 return (1);
119}
120
121/**
122 * @brief Formats a data value of a specified type into a string buffer using an optional printf format string.
123 *
124 * This function formats a single data value from a data array into a provided buffer. It is a wrapper for `SDDS_SprintTypedValueFactor` with a default scaling factor of 1.0.
125 *
126 * @param[in] data Pointer to the base address of the data array containing the value to be formatted.
127 * @param[in] index The index of the item within the data array to be formatted.
128 * @param[in] type The data type of the value, specified by one of the SDDS constants:
129 * - `SDDS_LONGDOUBLE`
130 * - `SDDS_DOUBLE`
131 * - `SDDS_FLOAT`
132 * - `SDDS_LONG`
133 * - `SDDS_ULONG`
134 * - `SDDS_SHORT`
135 * - `SDDS_USHORT`
136 * - `SDDS_CHARACTER`
137 * - `SDDS_STRING`
138 * @param[in] format (Optional) NULL-terminated string specifying a `printf` format. If `NULL`, a default format is used based on the data type.
139 * @param[out] buffer Pointer to a character array where the formatted string will be stored.
140 * @param[in] mode Flags controlling the formatting behavior. Valid values are:
141 * - `0`: Default behavior.
142 * - `SDDS_PRINT_NOQUOTES`: When formatting strings, do not enclose them in quotes.
143 *
144 * @return Returns `1` on success. On failure, returns `0` and records an error message.
145 *
146 * @note This function uses a default scaling factor of 1.0.
147 *
148 * @see SDDS_SprintTypedValueFactor
149 * @see SDDS_SetError
150 */
151int32_t SDDS_SprintTypedValue(void *data, int64_t index, int32_t type, const char *format, char *buffer, uint32_t mode) {
152 return SDDS_SprintTypedValueFactor(data, index, type, format, buffer, mode, 1.0);
153}
154
155/**
156 * @brief Reallocates memory to a new size and zero-initializes the additional space.
157 *
158 * This function extends the standard `realloc` functionality by zero-initializing any newly allocated memory beyond the original size. It ensures that memory is consistently reallocated and initialized across different build configurations.
159 *
160 * @param[in] data Pointer to the base address of the data array containing the value to be formatted.
161 * @param[in] index The index of the item within the data array to be formatted.
162 * @param[in] type The data type of the value, specified by one of the SDDS constants:
163 * - `SDDS_LONGDOUBLE`
164 * - `SDDS_DOUBLE`
165 * - `SDDS_FLOAT`
166 * - `SDDS_LONG`
167 * - `SDDS_ULONG`
168 * - `SDDS_SHORT`
169 * - `SDDS_USHORT`
170 * - `SDDS_CHARACTER`
171 * - `SDDS_STRING`
172 * @param[in] format (Optional) NULL-terminated string specifying a `printf` format. If `NULL`, a default format is used based on the data type.
173 * @param[out] buffer Pointer to a character array where the formatted string will be stored.
174 * @param[in] mode Flags controlling the formatting behavior. Valid values are:
175 * - `0`: Default behavior.
176 * - `SDDS_PRINT_NOQUOTES`: When formatting strings, do not enclose them in quotes.
177 * @param[in] factor Scaling factor to be applied to the value before formatting. The value is multiplied by this factor.
178 *
179 * @return Returns `1` on success. On failure, returns `0` and records an error message.
180 *
181 * @note This function handles string types by optionally enclosing them in quotes, unless `SDDS_PRINT_NOQUOTES` is specified in `mode`.
182 *
183 * @see SDDS_SprintTypedValue
184 * @see SDDS_SetError
185 */
186int32_t SDDS_SprintTypedValueFactor(void *data, int64_t index, int32_t type, const char *format, char *buffer, uint32_t mode, double factor) {
187 char buffer2[SDDS_PRINT_BUFLEN], *s;
188 short printed;
189
190 if (!data) {
191 SDDS_SetError("Unable to print value--data pointer is NULL (SDDS_SprintTypedValueFactor)");
192 return (0);
193 }
194 if (!buffer) {
195 SDDS_SetError("Unable to print value--buffer pointer is NULL (SDDS_SprintTypedValueFactor)");
196 return (0);
197 }
198 switch (type) {
199 case SDDS_SHORT:
200 sprintf(buffer, format ? format : "%hd", (short)(*((short *)data + index) * (factor)));
201 break;
202 case SDDS_USHORT:
203 sprintf(buffer, format ? format : "%hu", (unsigned short)(*((unsigned short *)data + index) * (factor)));
204 break;
205 case SDDS_LONG:
206 sprintf(buffer, format ? format : "%" PRId32, (int32_t)(*((int32_t *)data + index) * (factor)));
207 break;
208 case SDDS_ULONG:
209 sprintf(buffer, format ? format : "%" PRIu32, (uint32_t)(*((uint32_t *)data + index) * (factor)));
210 break;
211 case SDDS_LONG64:
212 sprintf(buffer, format ? format : "%" PRId64, (int64_t)(*((int64_t *)data + index) * (factor)));
213 break;
214 case SDDS_ULONG64:
215 sprintf(buffer, format ? format : "%" PRIu64, (uint64_t)(*((uint64_t *)data + index) * (factor)));
216 break;
217 case SDDS_FLOAT:
218 sprintf(buffer, format ? format : "%15.8e", (float)(*((float *)data + index) * (factor)));
219 break;
220 case SDDS_DOUBLE:
221 sprintf(buffer, format ? format : "%21.15e", (double)(*((double *)data + index) * (factor)));
222 break;
223 case SDDS_LONGDOUBLE:
224 if (LDBL_DIG == 18) {
225 sprintf(buffer, format ? format : "%21.18Le", (long double)(*((long double *)data + index) * (factor)));
226 } else {
227 sprintf(buffer, format ? format : "%21.15Le", (long double)(*((long double *)data + index) * (factor)));
228 }
229 break;
230 case SDDS_STRING:
231 s = *((char **)data + index);
232 if ((int32_t)strlen(s) > SDDS_PRINT_BUFLEN - 3) {
233 SDDS_SetError("Buffer size overflow (SDDS_SprintTypedValue)");
234 return (0);
235 }
236 if (!(mode & SDDS_PRINT_NOQUOTES)) {
237 printed = 0;
238 if (!s || SDDS_StringIsBlank(s))
239 sprintf(buffer, "\"\"");
240 else if (strchr(s, '"')) {
241 strcpy(buffer2, s);
242 SDDS_EscapeQuotes(buffer2, '"');
243 if (SDDS_HasWhitespace(buffer2))
244 sprintf(buffer, "\"%s\"", buffer2);
245 else
246 strcpy(buffer, buffer2);
247 } else if (SDDS_HasWhitespace(s))
248 sprintf(buffer, "\"%s\"", s);
249 else {
250 sprintf(buffer, format ? format : "%s", s);
251 printed = 1;
252 }
253 if (!printed) {
254 sprintf(buffer2, format ? format : "%s", buffer);
255 strcpy(buffer, buffer2);
256 }
257 } else {
258 sprintf(buffer, format ? format : "%s", s);
259 }
260 break;
261 case SDDS_CHARACTER:
262 sprintf(buffer, format ? format : "%c", *((char *)data + index));
263 break;
264 default:
265 SDDS_SetError("Unable to print value--unknown data type (SDDS_SprintTypedValue)");
266 return (0);
267 }
268 return (1);
269}
270
271static int32_t n_errors = 0;
272static int32_t n_errors_max = 0;
273static char **error_description = NULL;
274static char *registeredProgramName = NULL;
275
276/**
277 * @brief Registers the executable program name for use in error messages.
278 *
279 * This function stores the name of the executing program, which is included in various error and warning messages generated by the SDDS library routines.
280 *
281 * @param[in] name The name of the program. If `NULL`, the registered program name is cleared.
282 *
283 * @note This function should be called at the beginning of the program to provide context in error messages.
284 *
285 * @see SDDS_Bomb
286 * @see SDDS_Warning
287 */
288void SDDS_RegisterProgramName(const char *name) {
289 if (name)
290 SDDS_CopyString(&registeredProgramName, (char *)name);
291 else
292 registeredProgramName = NULL;
293}
294
295/**
296 * @brief Retrieves the number of errors recorded by SDDS library routines.
297 *
298 * This function returns the total number of errors that have been recorded by the SDDS library since the last invocation of `SDDS_PrintErrors`.
299 *
300 * @return The number of recorded errors.
301 *
302 * @see SDDS_PrintErrors
303 */
305 return (n_errors);
306}
307
308/**
309 * @brief Clears all recorded error messages from the SDDS error stack.
310 *
311 * This function removes all error messages that have been recorded by SDDS library routines, resetting the error count to zero. It should be called after handling or logging the errors to prepare for future error recording.
312 *
313 * @note After calling this function, `SDDS_NumberOfErrors` will return zero until new errors are recorded.
314 *
315 * @see SDDS_SetError
316 * @see SDDS_PrintErrors
317 */
319 int32_t i;
320 for (i=0; i<n_errors; i++) {
321 free(error_description[i]);
322 error_description[i] = NULL;
323 }
324 free(error_description);
325 error_description = NULL;
326 n_errors = 0;
327 n_errors_max = 0;
328}
329
330/**
331 * @brief Terminates the program after printing an error message and recorded errors.
332 *
333 * This function prints a termination message to `stderr`, invokes `SDDS_PrintErrors` to display all recorded errors, and then exits the program with a non-zero status.
334 *
335 * @param[in] message The termination message to be printed. If `NULL`, a default message `"?"` is used.
336 *
337 * @note This function does not return; it exits the program.
338 *
339 * @see SDDS_PrintErrors
340 * @see SDDS_SetError
341 */
342void SDDS_Bomb(char *message) {
343 if (registeredProgramName)
344 fprintf(stderr, "Error (%s): %s\n", registeredProgramName, message ? message : "?");
345 else
346 fprintf(stderr, "Error: %s\n", message ? message : "?");
347 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
348 exit(1);
349}
350
351/**
352 * @brief Prints a warning message to `stderr`.
353 *
354 * This function outputs a warning message to the specified `FILE` stream, typically `stderr`. If a program name has been registered using `SDDS_RegisterProgramName`, it is included in the warning message.
355 *
356 * @param[in] message The warning message to be printed. If `NULL`, a default message `"?"` is used.
357 *
358 * @note This function does not record the warning as an error; it only prints the message.
359 *
360 * @see SDDS_RegisterProgramName
361 */
362void SDDS_Warning(char *message) {
363 if (registeredProgramName)
364 fprintf(stderr, "Warning (%s): %s\n", registeredProgramName, message ? message : "?");
365 else
366 fprintf(stderr, "Warning: %s\n", message ? message : "?");
367}
368
369/**
370 * @brief Records an error message in the SDDS error stack.
371 *
372 * This function appends an error message to the internal error stack. These errors can later be retrieved and displayed using `SDDS_PrintErrors`.
373 *
374 * @param[in] error_text The error message to be recorded. If `NULL`, a warning is printed to `stderr`.
375 *
376 * @see SDDS_PrintErrors
377 * @see SDDS_ClearErrors
378 */
379void SDDS_SetError(char *error_text) {
380 SDDS_SetError0(error_text);
381 SDDS_SetError0("\n");
382}
383
384/**
385 * @brief Internal function to record an error message in the SDDS error stack.
386 *
387 * This function appends an error message to the internal error stack without adding additional formatting or line breaks. It is typically called by `SDDS_SetError`.
388 *
389 * @param[in] error_text The error message to be recorded. If `NULL`, a warning is printed to `stderr`.
390 *
391 * @note This function is intended for internal use within the SDDS library and should not be called directly by user code.
392 *
393 * @see SDDS_SetError
394 */
395void SDDS_SetError0(char *error_text) {
396 if (n_errors >= n_errors_max) {
397 if (!(error_description = SDDS_Realloc(error_description, (n_errors_max += 10) * sizeof(*error_description)))) {
398 fputs("Error trying to allocate additional error description string (SDDS_SetError)\n", stderr);
399 fprintf(stderr, "Most recent error text:\n%s\n", error_text);
400 abort();
401 }
402 }
403 if (!error_text)
404 fprintf(stderr, "warning: error text is NULL (SDDS_SetError)\n");
405 else {
406 if (!SDDS_CopyString(&error_description[n_errors], error_text)) {
407 fputs("Error trying to copy additional error description text (SDDS_SetError)\n", stderr);
408 fprintf(stderr, "Most recent error text: %s\n", error_text);
409 abort();
410 }
411 n_errors++;
412 }
413}
414
415/**
416 * @brief Prints recorded error messages to a specified file stream.
417 *
418 * This function outputs the errors that have been recorded by SDDS library routines to the given file stream. Depending on the `mode` parameter, it can print a single error, all recorded errors, and optionally terminate the program after printing.
419 *
420 * @param[in] fp Pointer to the `FILE` stream where errors will be printed. Typically `stderr`.
421 * @param[in] mode Flags controlling the error printing behavior:
422 * - `0`: Print only the first recorded error.
423 * - `SDDS_VERBOSE_PrintErrors`: Print all recorded errors.
424 * - `SDDS_EXIT_PrintErrors`: After printing errors, terminate the program by calling `exit(1)`.
425 *
426 * @note After printing, the error stack is cleared. If `mode` includes `SDDS_EXIT_PrintErrors`, the program will terminate.
427 *
428 * @see SDDS_SetError
429 * @see SDDS_NumberOfErrors
430 * @see SDDS_ClearErrors
431 */
432void SDDS_PrintErrors(FILE *fp, int32_t mode) {
433 int32_t i, depth;
434
435 if (!n_errors)
436 return;
437 if (!fp) {
438 n_errors = 0;
439 return;
440 }
441 if (mode & SDDS_VERBOSE_PrintErrors)
442 depth = n_errors;
443 else
444 depth = 1;
445 if (registeredProgramName)
446 fprintf(fp, "Error for %s:\n", registeredProgramName);
447 else
448 fputs("Error:\n", fp);
449 if (!error_description)
450 fprintf(stderr, "warning: internal error: error_description pointer is unexpectedly NULL\n");
451 else
452 for (i = 0; i < depth; i++) {
453 if (!error_description[i])
454 fprintf(stderr, "warning: internal error: error_description[%" PRId32 "] is unexpectedly NULL\n", i);
455 fprintf(fp, "%s", error_description[i]);
456 }
457 fflush(fp);
458 n_errors = 0;
459 if (mode & SDDS_EXIT_PrintErrors)
460 exit(1);
461}
462
463/**
464 * @brief Retrieves recorded error messages from the SDDS error stack.
465 *
466 * This function fetches error messages that have been recorded by SDDS library routines. Depending on the `mode` parameter, it can retrieve a single error message or all recorded errors.
467 *
468 * @param[out] number Pointer to an `int32_t` variable where the number of retrieved error messages will be stored. If `NULL`, the function returns `NULL`.
469 * @param[in] mode Flags controlling the retrieval behavior:
470 * - `0`: Retrieve only the most recent error message.
471 * - `SDDS_ALL_GetErrorMessages`: Retrieve all recorded error messages.
472 *
473 * @return A dynamically allocated array of strings containing the error messages. Returns `NULL` if no errors are recorded or if memory allocation fails.
474 *
475 * @note The caller is responsible for freeing the memory allocated for the returned error messages.
476 *
477 * @see SDDS_SetError
478 * @see SDDS_ClearErrors
479 */
480char **SDDS_GetErrorMessages(int32_t *number, int32_t mode) {
481 int32_t i, depth;
482 char **message;
483
484 if (!number)
485 return NULL;
486
487 *number = 0;
488 if (!n_errors)
489 return NULL;
490
491 if (mode & SDDS_ALL_GetErrorMessages)
492 depth = n_errors;
493 else
494 depth = 1;
495 if (!(message = (char **)SDDS_Malloc(sizeof(*message) * depth)))
496 return NULL;
497 if (!error_description) {
498 fprintf(stderr, "warning: internal error: error_description pointer is unexpectedly NULL (SDDS_GetErrorMessages)\n");
499 return NULL;
500 } else {
501 for (i = depth - 1; i >= 0; i--) {
502 if (!error_description[i]) {
503 fprintf(stderr, "internal error: error_description[%" PRId32 "] is unexpectedly NULL (SDDS_GetErrorMessages)\n", i);
504 return NULL;
505 }
506 if (!SDDS_CopyString(message + i, error_description[i])) {
507 fprintf(stderr, "unable to copy error message text (SDDS_GetErrorMessages)\n");
508 return NULL;
509 }
510 }
511 }
512 *number = depth;
513 return message;
514}
515
516/*static uint32_t AutoCheckMode = TABULAR_DATA_CHECKS ;*/
517static uint32_t AutoCheckMode = 0x0000UL;
518
519/**
520 * @brief Sets the automatic check mode for SDDS dataset validation.
521 *
522 * This function updates the auto-check mode, which controls the automatic validation of SDDS datasets during operations. The previous mode is returned.
523 *
524 * @param[in] newMode The new auto-check mode to be set. It should be a bitwise combination of the following constants:
525 * - `TABULAR_DATA_CHECKS`: Enables checks for tabular data consistency.
526 * - (Other mode flags as defined by SDDS)
527 *
528 * @return The previous auto-check mode before the update.
529 *
530 * @see SDDS_CheckDataset
531 * @see SDDS_CheckTabularData
532 */
533uint32_t SDDS_SetAutoCheckMode(uint32_t newMode) {
534 uint32_t oldMode;
535 oldMode = AutoCheckMode;
536 AutoCheckMode = newMode;
537 return oldMode;
538}
539
540/**
541 * @brief Validates the SDDS dataset pointer.
542 *
543 * This function checks whether the provided `SDDS_DATASET` pointer is valid (non-NULL). If the check fails, it records an appropriate error message.
544 *
545 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure to be validated.
546 * @param[in] caller Name of the calling function, used for error reporting.
547 *
548 * @return Returns `1` if the dataset pointer is valid; otherwise, returns `0` and records an error message.
549 *
550 * @see SDDS_SetError
551 */
552int32_t SDDS_CheckDataset(SDDS_DATASET *SDDS_dataset, const char *caller) {
553 char buffer[100];
554 if (!SDDS_dataset) {
555 sprintf(buffer, "NULL SDDS_DATASET pointer passed to %s", caller);
556 SDDS_SetError(buffer);
557 return (0);
558 }
559 return (1);
560}
561
562/**
563 * @brief Validates the consistency of tabular data within an SDDS dataset.
564 *
565 * This function checks the integrity of tabular data in the given `SDDS_DATASET`. It verifies that if columns are defined, corresponding row flags and data arrays exist, and that the number of rows matches the column definitions.
566 *
567 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure to be validated.
568 * @param[in] caller Name of the calling function, used for error reporting.
569 *
570 * @return Returns `1` if the tabular data is consistent and valid; otherwise, returns `0` and records an error message.
571 *
572 * @note This function performs checks only if `AutoCheckMode` includes `TABULAR_DATA_CHECKS`.
573 *
574 * @see SDDS_SetAutoCheckMode
575 * @see SDDS_SetError
576 */
577int32_t SDDS_CheckTabularData(SDDS_DATASET *SDDS_dataset, const char *caller) {
578 int64_t i;
579 char buffer[100];
580 if (!(AutoCheckMode & TABULAR_DATA_CHECKS))
581 return 1;
582 if (SDDS_dataset->layout.n_columns && (!SDDS_dataset->row_flag || !SDDS_dataset->data)) {
583 sprintf(buffer, "tabular data is invalid in %s (columns but no row flags or data array)", caller);
584 SDDS_SetError(buffer);
585 return (0);
586 }
587 if (SDDS_dataset->layout.n_columns == 0 && SDDS_dataset->n_rows) {
588 sprintf(buffer, "tabular data is invalid in %s (no columns present but nonzero row count)", caller);
589 SDDS_SetError(buffer);
590 return (0);
591 }
592 for (i = 0; i < SDDS_dataset->layout.n_columns; i++) {
593 if (!SDDS_dataset->data[i]) {
594 sprintf(buffer, "tabular data is invalid in %s (null data pointer for column %" PRId64 ")", caller, i);
595 SDDS_SetError(buffer);
596 return (0);
597 }
598 }
599 return (1);
600}
601
602/**
603 * @brief Allocates zero-initialized memory for an array of elements.
604 *
605 * This function is a wrapper around the standard `calloc` function, used by SDDS routines to allocate memory. It ensures that even if the requested number of elements or element size is zero or negative, a minimum of 1 element with a size of 4 bytes is allocated.
606 *
607 * @param[in] nelem Number of elements to allocate.
608 * @param[in] elem_size Size in bytes of each element.
609 *
610 * @return Pointer to the allocated memory. If allocation fails, returns `NULL`.
611 *
612 * @note If `nelem` or `elem_size` is less than or equal to zero, the function allocates memory for one element of 4 bytes by default.
613 *
614 * @see SDDS_Malloc
615 * @see SDDS_Free
616 */
617void *SDDS_Calloc(size_t nelem, size_t elem_size) {
618 if (elem_size <= 0)
619 elem_size = 4;
620 if (nelem <= 0)
621 nelem = 1;
622 return calloc(nelem, elem_size);
623}
624
625/**
626 * @brief Allocates memory of a specified size.
627 *
628 * This function is a wrapper around the standard `malloc` function, used by SDDS routines to allocate memory. It ensures that a minimum allocation size is enforced.
629 *
630 * @param[in] size Number of bytes to allocate.
631 *
632 * @return Pointer to the allocated memory. If `size` is less than or equal to zero, it allocates memory for 4 bytes by default. Returns `NULL` if memory allocation fails.
633 *
634 * @note Users should always check the returned pointer for `NULL` before using it.
635 *
636 * @see SDDS_Calloc
637 * @see SDDS_Free
638 */
639void *SDDS_Malloc(size_t size) {
640 if (size <= 0)
641 size = 4;
642 return malloc(size);
643}
644
645/**
646 * @brief Free memory previously allocated by SDDS_Malloc.
647 *
648 * This function frees memory that wsa previously allocated by SDDS_Malloc.
649 *
650 * @param[in] mem Pointer to the memory block.
651 *
652 * @see SDDS_Malloc
653 * @see SDDS_Calloc
654 */
655void SDDS_Free(void *mem) {
656 /* this is required so the free will be consistent with the malloc.
657 On WIN32 the release (optimized) version of malloc is different
658 from the debug (unoptimized) version, so debug programs freeing
659 memory that was allocated by release, library routines encounter
660 problems. */
661 free(mem);
662}
663
664/**
665 * @brief Reallocates memory to a new size.
666 *
667 * This function extends the standard `realloc` functionality by zero-initializing any newly allocated memory beyond the original size. It ensures that memory is consistently reallocated and initialized across different build configurations.
668 *
669 * @param[in] old_ptr Pointer to the original memory block. If `NULL`, the function behaves like `SDDS_Malloc`.
670 * @param[in] new_size New size in bytes for the memory block.
671 *
672 * @return Pointer to the reallocated memory block with the new size. If `new_size` is less than or equal to zero, a minimum of 4 bytes is allocated. Returns `NULL` if memory reallocation fails.
673 *
674 * @see SDDS_Malloc
675 * @see SDDS_Free
676 */
677void *SDDS_Realloc(void *old_ptr, size_t new_size) {
678 /* this is required because some realloc's don't behave properly when asked to return a
679 * pointer to 0 memory. They return NULL.
680 */
681 if (new_size <= 0)
682 new_size = 4;
683 /* this is required because some realloc's don't behave properly when given a NULL pointer */
684 if (!old_ptr)
685 return (SDDS_Malloc(new_size));
686 else
687 return (realloc(old_ptr, new_size));
688}
689
690/**
691 * @brief Reallocates memory to a new size and zero-initializes the additional space.
692 *
693 * This function reallocates a memory block to a new size, similar to the standard `realloc` function. Additionally, it ensures that any newly allocated memory beyond the original size is set to zero. This is particularly useful when extending memory blocks to avoid uninitialized memory usage.
694 *
695 * @param[in] old_ptr Pointer to the original memory block. If `NULL`, the function behaves like `SDDS_Calloc`.
696 * @param[in] old_size Size in bytes of the original memory block.
697 * @param[in] new_size New size in bytes for the memory block.
698 *
699 * @return Pointer to the reallocated memory block with the new size. If `new_size` is less than or equal to zero, a minimum of 4 bytes is allocated. Returns `NULL` if memory reallocation fails.
700 *
701 * @note After reallocation, the memory from `old_size` to `new_size` bytes is set to zero. If `old_ptr` is `NULL`, the function allocates memory initialized to zero.
702 *
703 * @see SDDS_Malloc
704 * @see SDDS_Calloc
705 * @see SDDS_Free
706 */
707void *SDDS_Recalloc(void *old_ptr, size_t old_size, size_t new_size) {
708 /* this is required because some realloc's don't behave properly when asked to return a
709 * pointer to 0 memory. They return NULL.
710 * Also, need to clear the memory (in this version).
711 */
712 void *new_ptr;
713 if (new_size <= 0)
714 new_size = 4;
715 /* this is required because some realloc's don't behave properly when given a NULL pointer */
716 if (!old_ptr)
717 new_ptr = calloc(new_size, 1);
718 else {
719 new_ptr = realloc(old_ptr, new_size);
720 memset((char *)new_ptr + old_size, 0, new_size - old_size);
721 }
722 return new_ptr;
723}
724
725/**
726 * @brief Verifies that a printf format string is compatible with a specified data type.
727 *
728 * This function checks whether the provided printf format string is appropriate for the given SDDS data type. It ensures that the format specifier matches the type, preventing potential formatting errors during data output.
729 *
730 * @param[in] string The printf format string to be verified.
731 * @param[in] type The data type against which the format string is verified. Must be one of the SDDS type constants:
732 * - `SDDS_LONGDOUBLE`
733 * - `SDDS_DOUBLE`
734 * - `SDDS_FLOAT`
735 * - `SDDS_LONG`
736 * - `SDDS_LONG64`
737 * - `SDDS_ULONG`
738 * - `SDDS_ULONG64`
739 * - `SDDS_SHORT`
740 * - `SDDS_USHORT`
741 * - `SDDS_STRING`
742 * - `SDDS_CHARACTER`
743 *
744 * @return Returns `1` if the format string is valid for the specified type; otherwise, returns `0` and records an error message.
745 *
746 * @note This function does not modify the format string; it only validates its compatibility with the given type.
747 *
748 * @see SDDS_SetError
749 */
750int32_t SDDS_VerifyPrintfFormat(const char *string, int32_t type) {
751 char *percent, *s;
752 int32_t len, tmp;
753
754 s = (char *)string;
755 do {
756 if ((percent = strchr(s, '%'))) {
757 if (*(percent + 1) != '%')
758 break;
759 s = percent + 1;
760 }
761 } while (percent);
762 if (!percent || !*++percent)
763 return (0);
764
765 s = percent;
766
767 switch (type) {
768 case SDDS_LONGDOUBLE:
769 case SDDS_DOUBLE:
770 case SDDS_FLOAT:
771 if ((len = strcspn(s, "fegEG")) == strlen(s))
772 return (0);
773 if (len == 0)
774 return (1);
775 if ((tmp = strspn(s, "-+.0123456789 ")) < len)
776 return (0);
777 break;
778 case SDDS_LONG:
779 case SDDS_LONG64:
780 if ((len = strcspn(s, "d")) == strlen(s))
781 return (0);
782 /* if (*(s+len-1)!='l')
783 return(0); */
784 if (--len == 0)
785 return (1);
786 if ((tmp = strspn(s, "-+.0123456789 ")) < len)
787 return (0);
788 break;
789 case SDDS_ULONG:
790 case SDDS_ULONG64:
791 if ((len = strcspn(s, "u")) == strlen(s))
792 return (0);
793 /* if (*(s+len-1)!='l')
794 return(0); */
795 if (--len == 0)
796 return (1);
797 if ((tmp = strspn(s, "-+.0123456789 ")) < len)
798 return (0);
799 break;
800 case SDDS_SHORT:
801 if ((len = strcspn(s, "d")) == strlen(s))
802 return (0);
803 if (*(s + len - 1) != 'h')
804 return (0);
805 if (--len == 0)
806 return (1);
807 if ((tmp = strspn(s, "-+.0123456789 ")) < len)
808 return (0);
809 break;
810 case SDDS_USHORT:
811 if ((len = strcspn(s, "u")) == strlen(s))
812 return (0);
813 if (*(s + len - 1) != 'h')
814 return (0);
815 if (--len == 0)
816 return (1);
817 if ((tmp = strspn(s, "-+.0123456789 ")) < len)
818 return (0);
819 break;
820 case SDDS_STRING:
821 if ((len = strcspn(s, "s")) == strlen(s))
822 return (0);
823 if (len == 0)
824 return (1);
825 if ((tmp = strspn(s, "-0123456789")) < len)
826 return (0);
827 break;
828 case SDDS_CHARACTER:
829 if ((len = strcspn(s, "c")) == strlen(s))
830 return (0);
831 if (len != 0)
832 return (0);
833 break;
834 default:
835 return (0);
836 }
837 /* no errors found--its probably okay */
838 return (1);
839}
840
841/**
842 * @brief Copies a source string to a target string with memory allocation.
843 *
844 * This function allocates memory for the target string and copies the contents of the source string into it. If the source string is `NULL`, the target string is set to `NULL`.
845 *
846 * @param[out] target Pointer to a `char*` variable where the copied string will be stored. Memory is allocated within this function and should be freed by the caller to avoid memory leaks.
847 * @param[in] source The source string to be copied. If `NULL`, the target is set to `NULL`.
848 *
849 * @return Returns `1` on successful copy and memory allocation. Returns `0` on error (e.g., memory allocation failure).
850 *
851 * @note The caller is responsible for freeing the memory allocated for the target string.
852 *
853 * @see SDDS_Free
854 * @see SDDS_Malloc
855 */
856int32_t SDDS_CopyString(char **target, const char *source) {
857 if (!source)
858 *target = NULL;
859 else {
860 if (!(*target = SDDS_Malloc(sizeof(**target) * (strlen(source) + 1))))
861 return (0);
862 strcpy(*target, source);
863 }
864 return (1);
865}
866
867/**
868 * @brief Retrieves the definition of a specified associate from the SDDS dataset.
869 *
870 * This function searches for an associate by its name within the provided SDDS dataset. If found, it creates a copy of the associate's definition and returns a pointer to it. The returned pointer should be freed by the caller using `SDDS_FreeAssociateDefinition` to avoid memory leaks.
871 *
872 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset.
873 * @param[in] name A null-terminated string specifying the name of the associate to retrieve.
874 *
875 * @return On success, returns a pointer to a newly allocated `ASSOCIATE_DEFINITION` structure containing the associate's information. On failure (e.g., if the associate is not found or a copy fails), returns `NULL` and records an error message.
876 *
877 * @note The caller is responsible for freeing the returned `ASSOCIATE_DEFINITION` pointer using `SDDS_FreeAssociateDefinition`.
878 *
879 * @see SDDS_CopyAssociateDefinition
880 * @see SDDS_FreeAssociateDefinition
881 * @see SDDS_SetError
882 */
884 int32_t i;
885 ASSOCIATE_DEFINITION *assdef;
886 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_GetAssociateDefinition"))
887 return (NULL);
888 if (!name) {
889 SDDS_SetError("Unable to get associate definition--name is NULL (SDDS_GetAssociateDefinition)");
890 return (NULL);
891 }
892 for (i = 0; i < SDDS_dataset->layout.n_associates; i++) {
893 if (strcmp(SDDS_dataset->layout.associate_definition[i].name, name) == 0) {
894 if (!SDDS_CopyAssociateDefinition(&assdef, SDDS_dataset->layout.associate_definition + i)) {
895 SDDS_SetError("Unable to get associate definition--copy failure (SDDS_GetAssociateDefinition)");
896 return (NULL);
897 }
898 return (assdef);
899 }
900 }
901 return (NULL);
902}
903
904/**
905 * @brief Creates a copy of an associate definition.
906 *
907 * This function allocates memory for a new `ASSOCIATE_DEFINITION` structure and copies the contents from the source associate definition to the target. All string fields are duplicated to ensure independent memory management.
908 *
909 * @param[out] target Pointer to a `ASSOCIATE_DEFINITION*` where the copied definition will be stored.
910 * @param[in] source Pointer to the `ASSOCIATE_DEFINITION` structure to be copied. If `source` is `NULL`, the target is set to `NULL`.
911 *
912 * @return Returns a pointer to the copied `ASSOCIATE_DEFINITION` structure on success. Returns `NULL` on failure (e.g., memory allocation failure).
913 *
914 * @note The caller is responsible for freeing the copied associate definition using `SDDS_FreeAssociateDefinition`.
915 *
916 * @see SDDS_FreeAssociateDefinition
917 * @see SDDS_Malloc
918 * @see SDDS_CopyString
919 */
921 if (!source)
922 return (*target = NULL);
923 if (!(*target = (ASSOCIATE_DEFINITION *)SDDS_Malloc(sizeof(**target))) ||
924 !SDDS_CopyString(&(*target)->name, source->name) || !SDDS_CopyString(&(*target)->filename, source->filename) || !SDDS_CopyString(&(*target)->path, source->path) || !SDDS_CopyString(&(*target)->description, source->description) || !SDDS_CopyString(&(*target)->contents, source->contents))
925 return (NULL);
926 (*target)->sdds = source->sdds;
927 return (*target);
928}
929
930/**
931 * @brief Frees memory allocated for an associate definition.
932 *
933 * This function deallocates all memory associated with an `ASSOCIATE_DEFINITION` structure, including its string fields. After freeing, the structure is zeroed out to prevent dangling pointers.
934 *
935 * @param[in] source Pointer to the `ASSOCIATE_DEFINITION` structure to be freed.
936 *
937 * @return Returns `1` on successful deallocation. Returns `0` if the `source` is `NULL` or if required fields are missing.
938 *
939 * @note After calling this function, the `source` pointer becomes invalid and should not be used.
940 *
941 * @see SDDS_CopyAssociateDefinition
942 * @see SDDS_Free
943 */
945 if (!source->name)
946 return (0);
947 free(source->name);
948 if (!source->filename)
949 return (0);
950 free(source->filename);
951 if (source->path)
952 free(source->path);
953 if (source->description)
954 free(source->description);
955 if (source->contents)
956 free(source->contents);
957 SDDS_ZeroMemory(source, sizeof(*source));
958 free(source);
959 return (1);
960}
961
962/**
963 * @brief Retrieves the definition of a specified column from the SDDS dataset.
964 *
965 * This function searches for a column by its name within the provided SDDS dataset. If found, it creates a copy of the column's definition and returns a pointer to it. The returned pointer should be freed by the caller using `SDDS_FreeColumnDefinition` to avoid memory leaks.
966 *
967 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset.
968 * @param[in] name A null-terminated string specifying the name of the column to retrieve.
969 *
970 * @return On success, returns a pointer to a newly allocated `COLUMN_DEFINITION` structure containing the column's information. On failure (e.g., if the column is not found or a copy fails), returns `NULL` and records an error message.
971 *
972 * @note The caller is responsible for freeing the returned `COLUMN_DEFINITION` pointer using `SDDS_FreeColumnDefinition`.
973 *
974 * @see SDDS_CopyColumnDefinition
975 * @see SDDS_FreeColumnDefinition
976 * @see SDDS_SetError
977 */
979 int64_t i;
980 COLUMN_DEFINITION *coldef;
981 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_GetColumnDefinition"))
982 return (NULL);
983 if (!name) {
984 SDDS_SetError("Unable to get column definition--name is NULL (SDDS_GetColumnDefinition)");
985 return (NULL);
986 }
987 if ((i = SDDS_GetColumnIndex(SDDS_dataset, name)) < 0)
988 return NULL;
989 if (!SDDS_CopyColumnDefinition(&coldef, SDDS_dataset->layout.column_definition + i)) {
990 SDDS_SetError("Unable to get column definition--copy failure (SDDS_GetColumnDefinition)");
991 return (NULL);
992 }
993 return (coldef);
994}
995
996/**
997 * @brief Creates a copy of a column definition.
998 *
999 * This function allocates memory for a new `COLUMN_DEFINITION` structure and copies the contents from the source column definition to the target. All string fields are duplicated to ensure independent memory management.
1000 *
1001 * @param[out] target Pointer to a `COLUMN_DEFINITION*` where the copied definition will be stored.
1002 * @param[in] source Pointer to the `COLUMN_DEFINITION` structure to be copied. If `source` is `NULL`, the target is set to `NULL`.
1003 *
1004 * @return Returns a pointer to the copied `COLUMN_DEFINITION` structure on success. Returns `NULL` on failure (e.g., memory allocation failure).
1005 *
1006 * @note The caller is responsible for freeing the copied column definition using `SDDS_FreeColumnDefinition`.
1007 *
1008 * @see SDDS_FreeColumnDefinition
1009 * @see SDDS_Malloc
1010 * @see SDDS_CopyString
1011 */
1013 if (!target)
1014 return NULL;
1015 if (!source)
1016 return (*target = NULL);
1017 if (!(*target = (COLUMN_DEFINITION *)SDDS_Malloc(sizeof(**target))) ||
1018 !SDDS_CopyString(&(*target)->name, source->name) ||
1019 !SDDS_CopyString(&(*target)->symbol, source->symbol) || !SDDS_CopyString(&(*target)->units, source->units) || !SDDS_CopyString(&(*target)->description, source->description) || !SDDS_CopyString(&(*target)->format_string, source->format_string))
1020 return (NULL);
1021 (*target)->type = source->type;
1022 (*target)->field_length = source->field_length;
1023 (*target)->definition_mode = source->definition_mode;
1024 (*target)->memory_number = source->memory_number;
1025 return (*target);
1026}
1027
1028/**
1029 * @brief Frees memory allocated for a column definition.
1030 *
1031 * This function deallocates all memory associated with a `COLUMN_DEFINITION` structure, including its string fields. After freeing, the structure is zeroed out to prevent dangling pointers.
1032 *
1033 * @param[in] source Pointer to the `COLUMN_DEFINITION` structure to be freed.
1034 *
1035 * @return Returns `1` on successful deallocation. Returns `0` if the `source` is `NULL` or if required fields are missing.
1036 *
1037 * @note After calling this function, the `source` pointer becomes invalid and should not be used.
1038 *
1039 * @see SDDS_CopyColumnDefinition
1040 * @see SDDS_Free
1041 */
1043 if (!source || !source->name)
1044 return (0);
1045 free(source->name);
1046 if (source->symbol)
1047 free(source->symbol);
1048 if (source->units)
1049 free(source->units);
1050 if (source->description)
1051 free(source->description);
1052 if (source->format_string)
1053 free(source->format_string);
1054 SDDS_ZeroMemory(source, sizeof(*source));
1055 free(source);
1056 return (1);
1057}
1058
1059/**
1060 * @brief Retrieves the definition of a specified parameter from the SDDS dataset.
1061 *
1062 * This function searches for a parameter by its name within the provided SDDS dataset. If found, it creates a copy of the parameter's definition and returns a pointer to it. The returned pointer should be freed by the caller using `SDDS_FreeParameterDefinition` to avoid memory leaks.
1063 *
1064 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset.
1065 * @param[in] name A null-terminated string specifying the name of the parameter to retrieve.
1066 *
1067 * @return On success, returns a pointer to a newly allocated `PARAMETER_DEFINITION` structure containing the parameter's information. On failure (e.g., if the parameter is not found or a copy fails), returns `NULL` and records an error message.
1068 *
1069 * @note The caller is responsible for freeing the returned `PARAMETER_DEFINITION` pointer using `SDDS_FreeParameterDefinition`.
1070 *
1071 * @see SDDS_CopyParameterDefinition
1072 * @see SDDS_FreeParameterDefinition
1073 * @see SDDS_SetError
1074 */
1076 int32_t i;
1077 PARAMETER_DEFINITION *pardef;
1078 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_GetParameterDefinition"))
1079 return (NULL);
1080 if (!name) {
1081 SDDS_SetError("Unable to get parameter definition--name is NULL (SDDS_GetParameterDefinition)");
1082 return (NULL);
1083 }
1084 if ((i = SDDS_GetParameterIndex(SDDS_dataset, name)) < 0)
1085 return NULL;
1086 if (!SDDS_CopyParameterDefinition(&pardef, SDDS_dataset->layout.parameter_definition + i)) {
1087 SDDS_SetError("Unable to get parameter definition--copy failure (SDDS_GetParameterDefinition)");
1088 return (NULL);
1089 }
1090 return (pardef);
1091}
1092
1093/**
1094 * @brief Creates a copy of a parameter definition.
1095 *
1096 * This function allocates memory for a new `PARAMETER_DEFINITION` structure and copies the contents from the source parameter definition to the target. All string fields are duplicated to ensure independent memory management.
1097 *
1098 * @param[out] target Pointer to a `PARAMETER_DEFINITION*` where the copied definition will be stored.
1099 * @param[in] source Pointer to the `PARAMETER_DEFINITION` structure to be copied. If `source` is `NULL`, the target is set to `NULL`.
1100 *
1101 * @return Returns a pointer to the copied `PARAMETER_DEFINITION` structure on success. Returns `NULL` on failure (e.g., memory allocation failure).
1102 *
1103 * @note The caller is responsible for freeing the copied parameter definition using `SDDS_FreeParameterDefinition`.
1104 *
1105 * @see SDDS_FreeParameterDefinition
1106 * @see SDDS_Malloc
1107 * @see SDDS_CopyString
1108 */
1110 if (!target)
1111 return NULL;
1112 if (!source)
1113 return (*target = NULL);
1114 if (!(*target = (PARAMETER_DEFINITION *)SDDS_Malloc(sizeof(**target))) ||
1115 !SDDS_CopyString(&(*target)->name, source->name) ||
1116 !SDDS_CopyString(&(*target)->symbol, source->symbol) ||
1117 !SDDS_CopyString(&(*target)->units, source->units) || !SDDS_CopyString(&(*target)->description, source->description) || !SDDS_CopyString(&(*target)->format_string, source->format_string) || !SDDS_CopyString(&(*target)->fixed_value, source->fixed_value))
1118 return (NULL);
1119 (*target)->type = source->type;
1120 (*target)->definition_mode = source->definition_mode;
1121 (*target)->memory_number = source->memory_number;
1122 return (*target);
1123}
1124
1125/**
1126 * @brief Frees memory allocated for a parameter definition.
1127 *
1128 * This function deallocates all memory associated with a `PARAMETER_DEFINITION` structure, including its string fields. After freeing, the structure is zeroed out to prevent dangling pointers.
1129 *
1130 * @param[in] source Pointer to the `PARAMETER_DEFINITION` structure to be freed.
1131 *
1132 * @return Returns `1` on successful deallocation. Returns `0` if the `source` is `NULL` or if required fields are missing.
1133 *
1134 * @note After calling this function, the `source` pointer becomes invalid and should not be used.
1135 *
1136 * @see SDDS_CopyParameterDefinition
1137 * @see SDDS_Free
1138 */
1140 if (!source || !source->name)
1141 return (0);
1142 free(source->name);
1143 if (source->symbol)
1144 free(source->symbol);
1145 if (source->units)
1146 free(source->units);
1147 if (source->description)
1148 free(source->description);
1149 if (source->format_string)
1150 free(source->format_string);
1151 if (source->fixed_value)
1152 free(source->fixed_value);
1153 SDDS_ZeroMemory(source, sizeof(*source));
1154 free(source);
1155 return (1);
1156}
1157
1158/**
1159 * @brief Retrieves the definition of a specified array from the SDDS dataset.
1160 *
1161 * This function searches for an array by its name within the provided SDDS dataset. If found, it creates a copy of the array's definition and returns a pointer to it. The returned pointer should be freed by the caller using `SDDS_FreeArrayDefinition` to avoid memory leaks.
1162 *
1163 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset.
1164 * @param[in] name A null-terminated string specifying the name of the array to retrieve.
1165 *
1166 * @return On success, returns a pointer to a newly allocated `ARRAY_DEFINITION` structure containing the array's information. On failure (e.g., if the array is not found or a copy fails), returns `NULL` and records an error message.
1167 *
1168 * @note The caller is responsible for freeing the returned `ARRAY_DEFINITION` pointer using `SDDS_FreeArrayDefinition`.
1169 *
1170 * @see SDDS_CopyArrayDefinition
1171 * @see SDDS_FreeArrayDefinition
1172 * @see SDDS_SetError
1173 */
1175 int32_t i;
1176 ARRAY_DEFINITION *arraydef;
1177 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_GetArrayDefinition"))
1178 return (NULL);
1179 if (!name) {
1180 SDDS_SetError("Unable to get array definition--name is NULL (SDDS_GetArrayDefinition)");
1181 return (NULL);
1182 }
1183 if ((i = SDDS_GetArrayIndex(SDDS_dataset, name)) < 0)
1184 return NULL;
1185 if (!SDDS_CopyArrayDefinition(&arraydef, SDDS_dataset->layout.array_definition + i)) {
1186 SDDS_SetError("Unable to get array definition--copy failure (SDDS_GetArrayDefinition)");
1187 return (NULL);
1188 }
1189 return (arraydef);
1190}
1191
1192/**
1193 * @brief Creates a copy of an array definition.
1194 *
1195 * This function allocates memory for a new `ARRAY_DEFINITION` structure and copies the contents from the source array definition to the target. All string fields are duplicated to ensure independent memory management.
1196 *
1197 * @param[out] target Pointer to a `ARRAY_DEFINITION*` where the copied definition will be stored.
1198 * @param[in] source Pointer to the `ARRAY_DEFINITION` structure to be copied. If `source` is `NULL`, the target is set to `NULL`.
1199 *
1200 * @return Returns a pointer to the copied `ARRAY_DEFINITION` structure on success. Returns `NULL` on failure (e.g., memory allocation failure).
1201 *
1202 * @note The caller is responsible for freeing the copied array definition using `SDDS_FreeArrayDefinition`.
1203 *
1204 * @see SDDS_FreeArrayDefinition
1205 * @see SDDS_Malloc
1206 * @see SDDS_CopyString
1207 */
1209 if (!target)
1210 return NULL;
1211 if (!source)
1212 return (*target = NULL);
1213 if (!(*target = (ARRAY_DEFINITION *)SDDS_Malloc(sizeof(**target))) ||
1214 !SDDS_CopyString(&(*target)->name, source->name) ||
1215 !SDDS_CopyString(&(*target)->symbol, source->symbol) ||
1216 !SDDS_CopyString(&(*target)->units, source->units) || !SDDS_CopyString(&(*target)->description, source->description) || !SDDS_CopyString(&(*target)->format_string, source->format_string) || !SDDS_CopyString(&(*target)->group_name, source->group_name))
1217 return (NULL);
1218 (*target)->type = source->type;
1219 (*target)->field_length = source->field_length;
1220 (*target)->dimensions = source->dimensions;
1221 return (*target);
1222}
1223
1224/**
1225 * @brief Frees memory allocated for an array definition.
1226 *
1227 * This function deallocates all memory associated with an `ARRAY_DEFINITION` structure, including its string fields. After freeing, the structure is zeroed out to prevent dangling pointers.
1228 *
1229 * @param[in] source Pointer to the `ARRAY_DEFINITION` structure to be freed.
1230 *
1231 * @return Returns `1` on successful deallocation. Returns `0` if the `source` is `NULL`.
1232 *
1233 * @note After calling this function, the `source` pointer becomes invalid and should not be used.
1234 *
1235 * @see SDDS_CopyArrayDefinition
1236 * @see SDDS_Free
1237 */
1239 if (!source)
1240 return (0);
1241 if (source->name)
1242 free(source->name);
1243 if (source->symbol)
1244 free(source->symbol);
1245 if (source->units)
1246 free(source->units);
1247 if (source->description)
1248 free(source->description);
1249 if (source->format_string)
1250 free(source->format_string);
1251 if (source->group_name)
1252 free(source->group_name);
1253 SDDS_ZeroMemory(source, sizeof(*source));
1254 free(source);
1255 source = NULL;
1256 return (1);
1257}
1258
1259/**
1260 * @brief Compares two `SORTED_INDEX` structures by their name fields.
1261 *
1262 * This function is used as a comparison callback for sorting functions like `qsort`. It compares the `name` fields of two `SORTED_INDEX` structures lexicographically.
1263 *
1264 * @param[in] s1 Pointer to the first `SORTED_INDEX` structure.
1265 * @param[in] s2 Pointer to the second `SORTED_INDEX` structure.
1266 *
1267 * @return An integer less than, equal to, or greater than zero if the `name` of `s1` is found, respectively, to be less than, to match, or be greater than the `name` of `s2`.
1268 *
1269 * @see qsort
1270 * @see SORTED_INDEX
1271 */
1272int SDDS_CompareIndexedNames(const void *s1, const void *s2) {
1273 return strcmp(((SORTED_INDEX *)s1)->name, ((SORTED_INDEX *)s2)->name);
1274}
1275
1276/* This routine is used with qsort. Use const void * to avoid warning
1277 * message from SUN Solaris compiler.
1278 */
1279/**
1280 * @brief Compares two pointers to `SORTED_INDEX` structures by their name fields.
1281 *
1282 * This function is used as a comparison callback for sorting functions like `qsort`. It compares the `name` fields of two `SORTED_INDEX` structure pointers lexicographically.
1283 *
1284 * @param[in] s1 Pointer to the first `SORTED_INDEX*` structure.
1285 * @param[in] s2 Pointer to the second `SORTED_INDEX*` structure.
1286 *
1287 * @return An integer less than, equal to, or greater than zero if the `name` of `*s1` is found, respectively, to be less than, to match, or be greater than the `name` of `*s2`.
1288 *
1289 * @see qsort
1290 * @see SORTED_INDEX
1291 */
1292int SDDS_CompareIndexedNamesPtr(const void *s1, const void *s2) {
1293 return strcmp((*((SORTED_INDEX **)s1))->name, (*((SORTED_INDEX **)s2))->name);
1294}
1295
1296/**
1297 * @brief Retrieves the index of a named column in the SDDS dataset.
1298 *
1299 * This function searches for a column by its name within the provided SDDS dataset and returns its index. The index can then be used with other routines for faster access to the column's data or metadata.
1300 *
1301 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset.
1302 * @param[in] name A null-terminated string specifying the name of the column whose index is desired.
1303 *
1304 * @return On success, returns a non-negative integer representing the index of the column. On failure (e.g., if the column is not found), returns `-1` and records an error message.
1305 *
1306 * @see SDDS_GetColumnDefinition
1307 * @see SDDS_SetError
1308 */
1309int32_t SDDS_GetColumnIndex(SDDS_DATASET *SDDS_dataset, char *name) {
1310 int64_t i;
1311 SORTED_INDEX key;
1312
1313 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_GetColumnIndex"))
1314 return (-1);
1315 if (!name) {
1316 SDDS_SetError("Unable to get column index--name is NULL (SDDS_GetColumnIndex)");
1317 return (-1);
1318 }
1319 key.name = name;
1320 if ((i = binaryIndexSearch((void **)SDDS_dataset->layout.column_index, SDDS_dataset->layout.n_columns, &key, SDDS_CompareIndexedNames, 0)) < 0)
1321 return -1;
1322 return SDDS_dataset->layout.column_index[i]->index;
1323}
1324
1325/**
1326 * @brief Retrieves the index of a named parameter in the SDDS dataset.
1327 *
1328 * This function searches for a parameter by its name within the provided SDDS dataset and returns its index. The index can then be used with other routines for faster access to the parameter's data or metadata.
1329 *
1330 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset.
1331 * @param[in] name A null-terminated string specifying the name of the parameter whose index is desired.
1332 *
1333 * @return On success, returns a non-negative integer representing the index of the parameter. On failure (e.g., if the parameter is not found), returns `-1` and records an error message.
1334 *
1335 * @see SDDS_GetParameterDefinition
1336 * @see SDDS_SetError
1337 */
1338int32_t SDDS_GetParameterIndex(SDDS_DATASET *SDDS_dataset, char *name) {
1339 int32_t i;
1340 SORTED_INDEX key;
1341
1342 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_GetParameterIndex"))
1343 return (-1);
1344 if (!name) {
1345 SDDS_SetError("Unable to get parameter index--name is NULL (SDDS_GetParameterIndex)");
1346 return (-1);
1347 }
1348 key.name = name;
1349 if ((i = binaryIndexSearch((void **)SDDS_dataset->layout.parameter_index, SDDS_dataset->layout.n_parameters, &key, SDDS_CompareIndexedNames, 0)) < 0)
1350 return -1;
1351 return SDDS_dataset->layout.parameter_index[i]->index;
1352}
1353
1354/**
1355 * @brief Retrieves the index of a named array in the SDDS dataset.
1356 *
1357 * This function searches for an array by its name within the provided SDDS dataset and returns its index. The index can then be used with other routines for faster access to the array's data or metadata.
1358 *
1359 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset.
1360 * @param[in] name A null-terminated string specifying the name of the array whose index is desired.
1361 *
1362 * @return On success, returns a non-negative integer representing the index of the array. On failure (e.g., if the array is not found), returns `-1` and records an error message.
1363 *
1364 * @see SDDS_GetArrayDefinition
1365 * @see SDDS_SetError
1366 */
1367int32_t SDDS_GetArrayIndex(SDDS_DATASET *SDDS_dataset, char *name) {
1368 int32_t i;
1369 SORTED_INDEX key;
1370
1371 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_GetArrayIndex"))
1372 return (-1);
1373 if (!name) {
1374 SDDS_SetError("Unable to get array index--name is NULL (SDDS_GetArrayIndex)");
1375 return (-1);
1376 }
1377 key.name = name;
1378 if ((i = binaryIndexSearch((void **)SDDS_dataset->layout.array_index, SDDS_dataset->layout.n_arrays, &key, SDDS_CompareIndexedNames, 0)) < 0)
1379 return -1;
1380 return SDDS_dataset->layout.array_index[i]->index;
1381}
1382
1383/**
1384 * @brief Retrieves the index of a named associate in the SDDS dataset.
1385 *
1386 * This function searches for an associate by its name within the provided SDDS dataset and returns its index. The index can then be used with other routines for faster access to the associate's data or metadata.
1387 *
1388 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset.
1389 * @param[in] name A null-terminated string specifying the name of the associate whose index is desired.
1390 *
1391 * @return On success, returns a non-negative integer representing the index of the associate. On failure (e.g., if the associate is not found), returns `-1` and records an error message.
1392 *
1393 * @see SDDS_GetAssociateDefinition
1394 * @see SDDS_SetError
1395 */
1396int32_t SDDS_GetAssociateIndex(SDDS_DATASET *SDDS_dataset, char *name) {
1397 int32_t i;
1398 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_GetAssociateIndex"))
1399 return (-1);
1400 if (!name) {
1401 SDDS_SetError("Unable to get associate index--name is NULL (SDDS_GetAssociateIndex)");
1402 return (-1);
1403 }
1404 for (i = 0; i < SDDS_dataset->layout.n_associates; i++) {
1405 if (strcmp(SDDS_dataset->layout.associate_definition[i].name, name) == 0)
1406 return (i);
1407 }
1408 return (-1);
1409}
1410
1411/**
1412 * @brief Checks if a string contains any whitespace characters.
1413 *
1414 * This function scans through the provided string to determine if it contains any whitespace characters (e.g., space, tab, newline).
1415 *
1416 * @param[in] string Pointer to the null-terminated string to be checked.
1417 *
1418 * @return Returns `1` if the string contains at least one whitespace character. Returns `0` if no whitespace characters are found or if the input string is `NULL`.
1419 *
1420 * @see isspace
1421 */
1422int32_t SDDS_HasWhitespace(char *string) {
1423 if (!string)
1424 return (0);
1425 while (*string) {
1426 if (isspace(*string))
1427 return (1);
1428 string++;
1429 }
1430 return (0);
1431}
1432
1433/**
1434 * @brief Reads a line from a file while skipping comment lines.
1435 *
1436 * This function reads lines from the specified file stream, ignoring lines that begin with the specified `skip_char`. It also processes special comment lines that start with `!#` by parsing them using `SDDS_ParseSpecialComments`.
1437 *
1438 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure, used for processing comments.
1439 * @param[out] s Pointer to a character array where the read line will be stored.
1440 * @param[in] slen The maximum number of characters to read into `s`.
1441 * @param[in] fp Pointer to the `FILE` stream to read from.
1442 * @param[in] skip_char Character indicating the start of a comment line. Lines beginning with this character will be skipped.
1443 *
1444 * @return On success, returns the pointer `s` containing the read line. If the end of the file is reached or an error occurs, returns `NULL`.
1445 *
1446 * @note The function modifies the buffer `s` by removing comments as determined by `SDDS_CutOutComments`.
1447 *
1448 * @see SDDS_CutOutComments
1449 * @see SDDS_ParseSpecialComments
1450 */
1451char *fgetsSkipComments(SDDS_DATASET *SDDS_dataset, char *s, int32_t slen, FILE *fp, char skip_char /* ignore lines that begin with this character */) {
1452 while (fgets(s, slen, fp)) {
1453 if (s[0] != skip_char) {
1454 SDDS_CutOutComments(SDDS_dataset, s, skip_char);
1455 return (s);
1456 } else if (s[1] == '#') {
1457 SDDS_ParseSpecialComments(SDDS_dataset, s + 2);
1458 }
1459 }
1460 return (NULL);
1461}
1462
1463/**
1464 * @brief Reads a line from a file with dynamic buffer resizing while skipping comment lines.
1465 *
1466 * This function reads lines from the specified file stream, ignoring lines that begin with the specified `skip_char`. If a line exceeds the current buffer size, the buffer is dynamically resized to accommodate the entire line. It also processes special comment lines that start with `!#` by parsing them using `SDDS_ParseSpecialComments`.
1467 *
1468 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure, used for processing comments.
1469 * @param[in,out] s Pointer to a pointer to a character array where the read line will be stored. This buffer may be resized if necessary.
1470 * @param[in,out] slen Pointer to an `int32_t` variable specifying the current size of the buffer `s`. This value may be updated if the buffer is resized.
1471 * @param[in] fp Pointer to the `FILE` stream to read from.
1472 * @param[in] skip_char Character indicating the start of a comment line. Lines beginning with this character will be skipped.
1473 *
1474 * @return On success, returns the pointer `*s` containing the read line. If the end of the file is reached or an error occurs, returns `NULL`.
1475 *
1476 * @note The caller is responsible for managing the memory of the buffer `*s`, including freeing it when no longer needed.
1477 *
1478 * @see SDDS_CutOutComments
1479 * @see SDDS_ParseSpecialComments
1480 * @see SDDS_Realloc
1481 */
1482char *fgetsSkipCommentsResize(SDDS_DATASET *SDDS_dataset, char **s, int32_t *slen, FILE *fp, char skip_char /* ignore lines that begin with this character */) {
1483 int32_t spaceLeft, length, newLine;
1484 char *sInsert, *fgetsReturn;
1485
1486 sInsert = *s;
1487 spaceLeft = *slen;
1488 newLine = 1;
1489 while ((fgetsReturn = fgets(sInsert, spaceLeft, fp))) {
1490 if (newLine && sInsert[0] == '!')
1491 continue;
1492 SDDS_CutOutComments(SDDS_dataset, sInsert, skip_char);
1493 length = strlen(sInsert);
1494 if (sInsert[length - 1] != '\n' && !feof(fp)) {
1495 /* buffer wasn't long enough to get the whole line. Resize and add more data. */
1496 spaceLeft = *slen;
1497 *slen = *slen * 2;
1498 *s = SDDS_Realloc(*s, sizeof(**s) * *slen);
1499 sInsert = *s + strlen(*s);
1500 newLine = 0;
1501 } else
1502 break;
1503 }
1504 if (!fgetsReturn)
1505 return NULL;
1506 return (*s);
1507}
1508
1509/**
1510 * @brief Reads a line from a LZMA-compressed file while skipping comment lines.
1511 *
1512 * This function reads lines from the specified LZMA-compressed file stream, ignoring lines that begin with the specified `skip_char`. It also processes special comment lines that start with `!#` by parsing them using `SDDS_ParseSpecialComments`.
1513 *
1514 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure, used for processing comments.
1515 * @param[out] s Pointer to a character array where the read line will be stored.
1516 * @param[in] slen The maximum number of characters to read into `s`.
1517 * @param[in] lzmafp Pointer to the `lzmafile` structure representing the LZMA-compressed file stream.
1518 * @param[in] skip_char Character indicating the start of a comment line. Lines beginning with this character will be skipped.
1519 *
1520 * @return On success, returns the pointer `s` containing the read line. If the end of the file is reached or an error occurs, returns `NULL`.
1521 *
1522 * @note The function modifies the buffer `s` by removing comments as determined by `SDDS_CutOutComments`.
1523 *
1524 * @see SDDS_CutOutComments
1525 * @see SDDS_ParseSpecialComments
1526 * @see lzma_gets
1527 */
1528char *fgetsLZMASkipComments(SDDS_DATASET *SDDS_dataset, char *s, int32_t slen, struct lzmafile *lzmafp, char skip_char /* ignore lines that begin with this character */) {
1529 while (lzma_gets(s, slen, lzmafp)) {
1530 if (s[0] != skip_char) {
1531 SDDS_CutOutComments(SDDS_dataset, s, skip_char);
1532 return (s);
1533 } else if (s[1] == '#') {
1534 SDDS_ParseSpecialComments(SDDS_dataset, s + 2);
1535 }
1536 }
1537 return (NULL);
1538}
1539
1540/**
1541 * @brief Reads a line from a LZMA-compressed file with dynamic buffer resizing while skipping comment lines.
1542 *
1543 * This function reads lines from the specified LZMA-compressed file stream, ignoring lines that begin with the specified `skip_char`. If a line exceeds the current buffer size, the buffer is dynamically resized to accommodate the entire line. It also processes special comment lines that start with `!#` by parsing them using `SDDS_ParseSpecialComments`.
1544 *
1545 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure, used for processing comments.
1546 * @param[in,out] s Pointer to a pointer to a character array where the read line will be stored. This buffer may be resized if necessary.
1547 * @param[in,out] slen Pointer to an `int32_t` variable specifying the current size of the buffer `*s`. This value may be updated if the buffer is resized.
1548 * @param[in] lzmafp Pointer to the `lzmafile` structure representing the LZMA-compressed file stream.
1549 * @param[in] skip_char Character indicating the start of a comment line. Lines beginning with this character will be skipped.
1550 *
1551 * @return On success, returns the pointer `*s` containing the read line. If the end of the file is reached or an error occurs, returns `NULL`.
1552 *
1553 * @note The caller is responsible for managing the memory of the buffer `*s`, including freeing it when no longer needed.
1554 *
1555 * @see SDDS_CutOutComments
1556 * @see SDDS_ParseSpecialComments
1557 * @see SDDS_Realloc
1558 * @see lzma_gets
1559 */
1560char *fgetsLZMASkipCommentsResize(SDDS_DATASET *SDDS_dataset, char **s, int32_t *slen, struct lzmafile *lzmafp, char skip_char /* ignore lines that begin with this character */) {
1561 int32_t spaceLeft, length, newLine;
1562 char *sInsert, *fgetsReturn;
1563
1564 sInsert = *s;
1565 spaceLeft = *slen;
1566 newLine = 1;
1567 while ((fgetsReturn = lzma_gets(sInsert, spaceLeft, lzmafp))) {
1568 if (newLine && sInsert[0] == '!')
1569 continue;
1570 SDDS_CutOutComments(SDDS_dataset, sInsert, skip_char);
1571 length = strlen(sInsert);
1572 if (sInsert[length - 1] != '\n' && !lzma_eof(lzmafp)) {
1573 /* buffer wasn't long enough to get the whole line. Resize and add more data. */
1574 spaceLeft = *slen;
1575 *slen = *slen * 2;
1576 *s = SDDS_Realloc(*s, sizeof(**s) * *slen);
1577 sInsert = *s + strlen(*s);
1578 newLine = 0;
1579 } else
1580 break;
1581 }
1582 if (!fgetsReturn)
1583 return NULL;
1584 return (*s);
1585}
1586
1587#if defined(zLib)
1588/**
1589 * @brief Reads a line from a GZip-compressed file while skipping comment lines.
1590 *
1591 * This function reads lines from a GZip-compressed file stream (`gzfp`), ignoring lines that begin with the specified `skip_char`. It also processes special comment lines that start with `!#` by parsing them using `SDDS_ParseSpecialComments`. Lines that are not skipped have their comments removed using `SDDS_CutOutComments` before being returned.
1592 *
1593 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure used for processing special comments.
1594 * @param[out] s Pointer to a character array where the read line will be stored.
1595 * @param[in] slen The maximum number of characters to read into `s`, including the null terminator.
1596 * @param[in] gzfp GZip file pointer from which to read the line.
1597 * @param[in] skip_char Character indicating the start of a comment line. Lines beginning with this character will be skipped.
1598 *
1599 * @return On success, returns the pointer `s` containing the read line. If the end of the file is reached or an error occurs, returns `NULL`.
1600 *
1601 * @note This function modifies the buffer `s` by removing comments as determined by `SDDS_CutOutComments`.
1602 *
1603 * @see SDDS_CutOutComments
1604 * @see SDDS_ParseSpecialComments
1605 * @see gzgets
1606 */
1607char *fgetsGZipSkipComments(SDDS_DATASET *SDDS_dataset, char *s, int32_t slen, gzFile gzfp, char skip_char /* ignore lines that begin with this character */) {
1608 while (gzgets(gzfp, s, slen)) {
1609 if (s[0] != skip_char) {
1610 SDDS_CutOutComments(SDDS_dataset, s, skip_char);
1611 return (s);
1612 } else if (s[1] == '#') {
1613 SDDS_ParseSpecialComments(SDDS_dataset, s + 2);
1614 }
1615 }
1616 return (NULL);
1617}
1618
1619/**
1620 * @brief Reads a line from a GZip-compressed file with dynamic buffer resizing while skipping comment lines.
1621 *
1622 * This function reads lines from a GZip-compressed file stream (`gzfp`), ignoring lines that begin with the specified `skip_char`. If a line exceeds the current buffer size (`slen`), the buffer is dynamically resized to accommodate the entire line. It also processes special comment lines that start with `!#` by parsing them using `SDDS_ParseSpecialComments`. Lines that are not skipped have their comments removed using `SDDS_CutOutComments` before being returned.
1623 *
1624 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure used for processing special comments.
1625 * @param[in,out] s Pointer to a pointer to a character array where the read line will be stored. This buffer may be resized if necessary.
1626 * @param[in,out] slen Pointer to an `int32_t` variable specifying the current size of the buffer `*s`. This value may be updated if the buffer is resized.
1627 * @param[in] gzfp GZip file pointer from which to read the line.
1628 * @param[in] skip_char Character indicating the start of a comment line. Lines beginning with this character will be skipped.
1629 *
1630 * @return On success, returns the pointer `*s` containing the read line. If the end of the file is reached or an error occurs, returns `NULL`.
1631 *
1632 * @note The caller is responsible for managing the memory of the buffer `*s`, including freeing it when no longer needed.
1633 *
1634 * @see SDDS_CutOutComments
1635 * @see SDDS_ParseSpecialComments
1636 * @see SDDS_Realloc
1637 * @see gzgets
1638 */
1639char *fgetsGZipSkipCommentsResize(SDDS_DATASET *SDDS_dataset, char **s, int32_t *slen, gzFile gzfp, char skip_char /* ignore lines that begin with this character */) {
1640 int32_t spaceLeft, length, newLine;
1641 char *sInsert, *fgetsReturn;
1642
1643 sInsert = *s;
1644 spaceLeft = *slen;
1645 newLine = 1;
1646 while ((fgetsReturn = gzgets(gzfp, sInsert, spaceLeft))) {
1647 if (newLine && sInsert[0] == '!')
1648 continue;
1649 SDDS_CutOutComments(SDDS_dataset, sInsert, skip_char);
1650 length = strlen(sInsert);
1651 if (sInsert[length - 1] != '\n' && !gzeof(gzfp)) {
1652 /* buffer wasn't int32_t enough to get the whole line. Resize and add more data. */
1653 spaceLeft = *slen;
1654 *slen = *slen * 2;
1655 *s = SDDS_Realloc(*s, sizeof(**s) * *slen);
1656 sInsert = *s + strlen(*s);
1657 newLine = 0;
1658 } else
1659 break;
1660 }
1661 if (!fgetsReturn)
1662 return NULL;
1663 return (*s);
1664}
1665#endif
1666
1667/**
1668 * @brief Removes comments from a string based on a specified comment character.
1669 *
1670 * This function processes a string `s`, removing any content that follows the comment character `cc`. It also handles special comment lines that start with `!#` by parsing them using `SDDS_ParseSpecialComments`. The function ensures that quoted sections within the string are preserved and not mistakenly identified as comments.
1671 *
1672 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure used for processing special comments.
1673 * @param[in,out] s Pointer to the character array containing the string to process. The string will be modified in place.
1674 * @param[in] cc The comment character indicating the start of a comment.
1675 *
1676 * @note If the first character of the string is the comment character, the entire line is treated as a comment. Otherwise, only the portion of the string following the first unescaped comment character is removed.
1677 *
1678 * @see SDDS_ParseSpecialComments
1679 */
1680void SDDS_CutOutComments(SDDS_DATASET *SDDS_dataset, char *s, char cc) {
1681 int32_t length, hasNewline;
1682 char *s0;
1683
1684 if (!cc || !s)
1685 return;
1686
1687 hasNewline = 0;
1688 length = strlen(s);
1689 if (s[length - 1] == '\n')
1690 hasNewline = 1;
1691
1692 if (*s == cc) {
1693 /* check for special information */
1694 if (*(s + 1) == '#')
1695 SDDS_ParseSpecialComments(SDDS_dataset, s + 2);
1696 *s = 0;
1697 return;
1698 }
1699 s0 = s;
1700 while (*s) {
1701 if ((*s == '"') && (s == s0 || *(s - 1) != '\\')) {
1702 while (*++s && (*s != '"' || *(s - 1) == '\\'))
1703 ;
1704 if (!*s)
1705 return;
1706 s++;
1707 continue;
1708 }
1709 if (*s == cc) {
1710 if (s != s0 && *(s - 1) == '\\')
1711 strcpy_ss(s - 1, s);
1712 else {
1713 if (hasNewline) {
1714 *s = '\n';
1715 *(s + 1) = 0;
1716 } else
1717 *s = 0;
1718 return;
1719 }
1720 }
1721 s++;
1722 }
1723}
1724
1725/**
1726 * @brief Extracts the next token from a string, handling quoted substrings and escape characters.
1727 *
1728 * This function parses the input string `s` to extract the next token, considering quoted substrings and escape characters. If the token is enclosed in double quotes (`"`), the function ensures that embedded quotes are handled correctly. After extracting the token, the original string `s` is updated to remove the extracted portion.
1729 *
1730 * @param[in,out] s Pointer to the string from which to extract the token. This string will be modified to remove the extracted token.
1731 * @param[out] buffer Pointer to a character array where the extracted token will be stored.
1732 * @param[in] buflen The maximum number of characters to copy into `buffer`, including the null terminator.
1733 *
1734 * @return On success, returns the length of the extracted token as an `int32_t`. If no token is found or an error occurs (e.g., buffer overflow), returns `-1`.
1735 *
1736 * @note The function assumes that the input string `s` is null-terminated. The caller must ensure that `buffer` has sufficient space to hold the extracted token.
1737 *
1738 * @see SDDS_GetToken2
1739 */
1740int32_t SDDS_GetToken(char *s, char *buffer, int32_t buflen) {
1741 char *ptr0, *ptr1, *escptr, *temp;
1742
1743 /* save the pointer to the head of the string */
1744 ptr0 = s;
1745
1746 /* skip leading white-space */
1747 while (isspace(*s))
1748 s++;
1749 if (*s == 0)
1750 return (-1);
1751 ptr1 = s;
1752
1753 if (*s == '"') {
1754 /* if quoted string, skip to next quotation mark */
1755 ptr1 = s + 1; /* beginning of actual token */
1756 do {
1757 s++;
1758 escptr = NULL;
1759 if (*s == '\\' && *(s + 1) == '\\') {
1760 /* skip and remember literal \ (indicated by \\ in the string) */
1761 escptr = s + 1;
1762 s += 2;
1763 }
1764 } while (*s && (*s != '"' || (*(s - 1) == '\\' && (s - 1) != escptr)));
1765 /* replace trailing quotation mark with a space */
1766 if (*s == '"')
1767 *s = ' ';
1768 } else {
1769 /* skip to first white-space following token */
1770 do {
1771 s++;
1772 /* imbedded quotation marks are handled here */
1773 if (*s == '"' && *(s - 1) != '\\') {
1774 while (*++s && !(*s == '"' && *(s - 1) != '\\'))
1775 ;
1776 }
1777 } while (*s && !isspace(*s));
1778 }
1779
1780 if ((int32_t)(s - ptr1) >= buflen)
1781 return (-1);
1782 strncpy(buffer, ptr1, s - ptr1);
1783 buffer[s - ptr1] = 0;
1784
1785 /* update the original string to delete the token */
1786 temp = malloc(sizeof(char) * (strlen(s) + 1));
1787 strcpy(temp, s);
1788 strcpy(ptr0, temp);
1789 free(temp);
1790
1791 /* return the string length */
1792 return ((int32_t)(s - ptr1));
1793}
1794
1795/**
1796 * @brief Extracts the next token from a string, handling quoted substrings and escape characters, with updated string pointers.
1797 *
1798 * This function parses the input string `s` to extract the next token, considering quoted substrings and escape characters. If the token is enclosed in double quotes (`"`), the function ensures that embedded quotes are handled correctly. After extracting the token, the original string `s` is updated by adjusting the string pointer `st` and the remaining string length `strlength`.
1799 *
1800 * @param[in,out] s Pointer to the string from which to extract the token. This string will be modified to remove the extracted token.
1801 * @param[in,out] st Pointer to the current position in the string `s`. This will be updated to point to the next character after the extracted token.
1802 * @param[in,out] strlength Pointer to an `int32_t` variable representing the remaining length of the string `s`. This will be decremented by the length of the extracted token.
1803 * @param[out] buffer Pointer to a character array where the extracted token will be stored.
1804 * @param[in] buflen The maximum number of characters to copy into `buffer`, including the null terminator.
1805 *
1806 * @return On success, returns the length of the extracted token as an `int32_t`. If no token is found or an error occurs (e.g., buffer overflow), returns `-1`.
1807 *
1808 * @note The caller is responsible for ensuring that `buffer` has sufficient space to hold the extracted token. Additionally, `st` and `strlength` should accurately reflect the current parsing state of the string.
1809 *
1810 * @see SDDS_GetToken
1811 */
1812int32_t SDDS_GetToken2(char *s, char **st, int32_t *strlength, char *buffer, int32_t buflen) {
1813 char *ptr0, *ptr1, *escptr;
1814
1815 /* save the pointer to the head of the string */
1816 ptr0 = s;
1817
1818 /* skip leading white-space */
1819 while (isspace(*s))
1820 s++;
1821 if (*s == 0)
1822 return (-1);
1823 ptr1 = s;
1824
1825 if (*s == '"') {
1826 /* if quoted string, skip to next quotation mark */
1827 ptr1 = s + 1; /* beginning of actual token */
1828 do {
1829 s++;
1830 escptr = NULL;
1831 if (*s == '\\' && *(s + 1) == '\\') {
1832 /* skip and remember literal \ (indicated by \\ in the string) */
1833 escptr = s + 1;
1834 s += 2;
1835 }
1836 } while (*s && (*s != '"' || (*(s - 1) == '\\' && (s - 1) != escptr)));
1837 /* replace trailing quotation mark with a space */
1838 if (*s == '"')
1839 *s = ' ';
1840 } else {
1841 /* skip to first white-space following token */
1842 do {
1843 s++;
1844 /* imbedded quotation marks are handled here */
1845 if (*s == '"' && *(s - 1) != '\\') {
1846 while (*++s && !(*s == '"' && *(s - 1) != '\\'))
1847 ;
1848 }
1849 } while (*s && !isspace(*s));
1850 }
1851
1852 if ((int32_t)(s - ptr1) >= buflen)
1853 return (-1);
1854 strncpy(buffer, ptr1, s - ptr1);
1855 buffer[s - ptr1] = 0;
1856
1857 /* update the original string to delete the token */
1858 *st += s - ptr0;
1859 *strlength -= s - ptr0;
1860
1861 /* return the string length including whitespace */
1862 return ((int32_t)(s - ptr1));
1863}
1864
1865/**
1866 * @brief Pads a string with spaces to reach a specified length.
1867 *
1868 * This function appends space characters to the end of the input string `string` until it reaches the desired `length`. If the original string is longer than the specified `length`, the function returns an error without modifying the string.
1869 *
1870 * @param[in,out] string Pointer to the null-terminated string to be padded.
1871 * @param[in] length The target length for the string after padding.
1872 *
1873 * @return Returns `1` on successful padding. Returns `0` if the input string is `NULL` or if the original string length exceeds the specified `length`.
1874 *
1875 * @note The function ensures that the padded string is null-terminated. The caller must ensure that the buffer `string` has sufficient space to accommodate the additional padding.
1876 *
1877 * @see SDDS_RemovePadding
1878 */
1879int32_t SDDS_PadToLength(char *string, int32_t length) {
1880 int32_t i;
1881 if (!string || (i = strlen(string)) > length)
1882 return (0);
1883 while (i < length)
1884 string[i++] = ' ';
1885 string[i] = 0;
1886 return (1);
1887}
1888
1889/**
1890 * @brief Escapes quote characters within a string by inserting backslashes.
1891 *
1892 * This function scans the input string `s` and inserts a backslash (`\`) before each occurrence of the specified `quote_char`, provided it is not already escaped. This is useful for preparing strings for formats that require escaped quotes.
1893 *
1894 * @param[in,out] s Pointer to the string in which quotes will be escaped. The string will be modified in place.
1895 * @param[in] quote_char The quote character to escape (e.g., `"`).
1896 *
1897 * @note The function dynamically allocates a temporary buffer to perform the escaping process and ensures that the original string `s` is updated correctly. The caller must ensure that `s` has sufficient space to accommodate the additional backslashes.
1898 *
1899 * @see SDDS_UnescapeQuotes
1900 */
1901void SDDS_EscapeQuotes(char *s, char quote_char) {
1902 char *ptr, *bptr;
1903 char *buffer = NULL;
1904
1905 ptr = s;
1906 buffer = trealloc(buffer, sizeof(*buffer) * (4 * (strlen(s) + 1)));
1907 bptr = buffer;
1908
1909 while (*ptr) {
1910 if (*ptr == quote_char && (ptr == s || *(ptr - 1) != '\\'))
1911 *bptr++ = '\\';
1912 *bptr++ = *ptr++;
1913 }
1914 *bptr = 0;
1915 strcpy(s, buffer);
1916 if (buffer)
1917 free(buffer);
1918}
1919
1920/**
1921 * @brief Removes escape characters from quote characters within a string.
1922 *
1923 * This function scans the input string `s` and removes backslashes (`\`) that precede the specified `quote_char`, effectively unescaping the quotes. This is useful for processing strings that have been prepared with escaped quotes.
1924 *
1925 * @param[in,out] s Pointer to the string in which quotes will be unescaped. The string will be modified in place.
1926 * @param[in] quote_char The quote character to unescape (e.g., `"`).
1927 *
1928 * @note The function modifies the string `s` by shifting characters to remove the escape backslashes. It assumes that `s` is properly null-terminated.
1929 *
1930 * @see SDDS_EscapeQuotes
1931 */
1932void SDDS_UnescapeQuotes(char *s, char quote_char) {
1933 char *ptr;
1934 ptr = s;
1935 while (*ptr) {
1936 if (*ptr == quote_char && ptr != s && *(ptr - 1) == '\\')
1937 strcpy(ptr - 1, ptr);
1938 else
1939 ptr++;
1940 }
1941}
1942
1943/**
1944 * @brief Escapes comment characters within a string by inserting backslashes.
1945 *
1946 * This function scans the input string `string` and inserts a backslash (`\`) before each occurrence of the specified comment character `cc`, provided it is not already escaped. This is useful for preparing strings to include comment characters without them being interpreted as actual comments.
1947 *
1948 * @param[in,out] string Pointer to the string in which comment characters will be escaped. The string will be modified in place.
1949 * @param[in] cc The comment character to escape (e.g., `#`).
1950 *
1951 * @note The function dynamically allocates a temporary buffer to perform the escaping process and ensures that the original string `string` is updated correctly. The caller must ensure that `string` has sufficient space to accommodate the additional backslashes.
1952 *
1953 * @see SDDS_CutOutComments
1954 */
1955void SDDS_EscapeCommentCharacters(char *string, char cc) {
1956 char *ptr, *s0;
1957 s0 = string;
1958 while (*string) {
1959 if (*string == cc && (string == s0 || *(string - 1) != '\\')) {
1960 ptr = string + strlen(string) + 1;
1961 while (ptr != string) {
1962 *ptr = *(ptr - 1);
1963 ptr--;
1964 }
1965 *string++ = '\\';
1966 }
1967 string++;
1968 }
1969}
1970
1971/**
1972 * @brief Sets a block of memory to zero.
1973 *
1974 * This function zero-initializes a specified number of bytes in a memory block. It is a wrapper around the standard `memset` function, providing a convenient way to clear memory.
1975 *
1976 * @param[in,out] mem Pointer to the memory block to be zeroed.
1977 * @param[in] n_bytes The number of bytes to set to zero.
1978 *
1979 * @return Returns `1` on successful memory zeroing. Returns `0` if the input memory pointer `mem` is `NULL`.
1980 *
1981 * @note The function does not perform any bounds checking. It is the caller's responsibility to ensure that the memory block is large enough to accommodate `n_bytes`.
1982 *
1983 * @see memset
1984 */
1985int32_t SDDS_ZeroMemory(void *mem, int64_t n_bytes) {
1986 if (mem) {
1987 memset(mem, 0, n_bytes);
1988 return 1;
1989 }
1990 return 0;
1991
1992 /*
1993 char *c;
1994
1995 if (!(c = (char*)mem))
1996 return(0);
1997 while (n_bytes--)
1998 *c++ = 0;
1999 return(1);
2000 */
2001}
2002
2003/**
2004 * @brief Initializes a memory block with a sequence of values based on a specified data type.
2005 *
2006 * This function sets a block of memory to a sequence of values, starting from a specified initial value and incrementing by a defined delta. The sequence is determined by the `data_type` parameter, which specifies the type of each element in the memory block. The function supports various SDDS data types and handles the initialization accordingly.
2007 *
2008 * @param[in,out] mem Pointer to the memory block to be initialized.
2009 * @param[in] n_elements The number of elements to initialize in the memory block.
2010 * @param[in] data_type The SDDS data type of each element. Must be one of the following constants:
2011 * - `SDDS_SHORT`
2012 * - `SDDS_USHORT`
2013 * - `SDDS_LONG`
2014 * - `SDDS_ULONG`
2015 * - `SDDS_LONG64`
2016 * - `SDDS_ULONG64`
2017 * - `SDDS_FLOAT`
2018 * - `SDDS_DOUBLE`
2019 * - `SDDS_LONGDOUBLE`
2020 * - `SDDS_CHARACTER`
2021 * @param[in] ... Variable arguments specifying the starting value and increment value. The types of these arguments depend on the `data_type`:
2022 * - For integer types (`SDDS_SHORT`, `SDDS_USHORT`, `SDDS_LONG`, `SDDS_ULONG`, `SDDS_LONG64`, `SDDS_ULONG64`):
2023 * - First argument: initial value (`int`, `unsigned int`, `int32_t`, `uint32_t`, `int64_t`, `uint64_t`)
2024 * - Second argument: increment value (`int`, `unsigned int`, `int32_t`, `uint32_t`, `int64_t`, `uint64_t`)
2025 * - For floating-point types (`SDDS_FLOAT`, `SDDS_DOUBLE`, `SDDS_LONGDOUBLE`):
2026 * - First argument: initial value (`double` for `float` and `double`, `long double` for `SDDS_LONGDOUBLE`)
2027 * - Second argument: increment value (`double` for `float` and `double`, `long double` for `SDDS_LONGDOUBLE`)
2028 * - For `SDDS_CHARACTER`:
2029 * - First argument: initial value (`char`)
2030 * - Second argument: increment value (`short`)
2031 *
2032 * @return Returns `1` on successful memory initialization. Returns `0` if an unknown or invalid `data_type` is provided.
2033 *
2034 * @note The function uses variable arguments to accept the starting and increment values. The caller must ensure that the correct types are provided based on the `data_type` parameter.
2035 *
2036 * @see SDDS_Malloc
2037 * @see SDDS_Free
2038 */
2039int32_t SDDS_SetMemory(void *mem, int64_t n_elements, int32_t data_type, ...)
2040/* usage is SDDS_SetMemory(ptr, n_elements, type, start_value, increment_value) */
2041{
2042 va_list argptr;
2043 int32_t retval;
2044 int64_t i;
2045 short short_val, short_dval, *short_ptr;
2046 unsigned short ushort_val, ushort_dval, *ushort_ptr;
2047 int32_t long_val, long_dval, *long_ptr;
2048 uint32_t ulong_val, ulong_dval, *ulong_ptr;
2049 int64_t long64_val, long64_dval, *long64_ptr;
2050 uint64_t ulong64_val, ulong64_dval, *ulong64_ptr;
2051 float float_val, float_dval, *float_ptr;
2052 double double_val, double_dval, *double_ptr;
2053 long double longdouble_val, longdouble_dval, *longdouble_ptr;
2054 char char_val, *char_ptr;
2055
2056 retval = 1;
2057 va_start(argptr, data_type);
2058 switch (data_type) {
2059 case SDDS_SHORT:
2060 short_val = (short)va_arg(argptr, int);
2061 short_dval = (short)va_arg(argptr, int);
2062 short_ptr = (short *)mem;
2063 for (i = 0; i < n_elements; i++, short_val += short_dval)
2064 *short_ptr++ = short_val;
2065 break;
2066 case SDDS_USHORT:
2067 ushort_val = (unsigned short)va_arg(argptr, int);
2068 ushort_dval = (unsigned short)va_arg(argptr, int);
2069 ushort_ptr = (unsigned short *)mem;
2070 for (i = 0; i < n_elements; i++, ushort_val += ushort_dval)
2071 *ushort_ptr++ = ushort_val;
2072 break;
2073 case SDDS_LONG:
2074 long_val = (int32_t)va_arg(argptr, int32_t);
2075 long_dval = (int32_t)va_arg(argptr, int32_t);
2076 long_ptr = (int32_t *)mem;
2077 for (i = 0; i < n_elements; i++, long_val += long_dval)
2078 *long_ptr++ = long_val;
2079 break;
2080 case SDDS_ULONG:
2081 ulong_val = (uint32_t)va_arg(argptr, uint32_t);
2082 ulong_dval = (uint32_t)va_arg(argptr, uint32_t);
2083 ulong_ptr = (uint32_t *)mem;
2084 for (i = 0; i < n_elements; i++, ulong_val += ulong_dval)
2085 *ulong_ptr++ = ulong_val;
2086 break;
2087 case SDDS_LONG64:
2088 long64_val = (int64_t)va_arg(argptr, int64_t);
2089 long64_dval = (int64_t)va_arg(argptr, int64_t);
2090 long64_ptr = (int64_t *)mem;
2091 for (i = 0; i < n_elements; i++, long64_val += long64_dval)
2092 *long64_ptr++ = long64_val;
2093 break;
2094 case SDDS_ULONG64:
2095 ulong64_val = (uint64_t)va_arg(argptr, uint32_t);
2096 ulong64_dval = (uint64_t)va_arg(argptr, uint32_t);
2097 ulong64_ptr = (uint64_t *)mem;
2098 for (i = 0; i < n_elements; i++, ulong64_val += ulong64_dval)
2099 *ulong64_ptr++ = ulong64_val;
2100 break;
2101 case SDDS_FLOAT:
2102 float_val = (float)va_arg(argptr, double);
2103 float_dval = (float)va_arg(argptr, double);
2104 float_ptr = (float *)mem;
2105 for (i = 0; i < n_elements; i++, float_val += float_dval)
2106 *float_ptr++ = float_val;
2107 break;
2108 case SDDS_DOUBLE:
2109 double_val = (double)va_arg(argptr, double);
2110 double_dval = (double)va_arg(argptr, double);
2111 double_ptr = (double *)mem;
2112 for (i = 0; i < n_elements; i++, double_val += double_dval)
2113 *double_ptr++ = double_val;
2114 break;
2115 case SDDS_LONGDOUBLE:
2116 longdouble_val = (long double)va_arg(argptr, long double);
2117 longdouble_dval = (long double)va_arg(argptr, long double);
2118 longdouble_ptr = (long double *)mem;
2119 for (i = 0; i < n_elements; i++, longdouble_val += longdouble_dval)
2120 *longdouble_ptr++ = longdouble_val;
2121 break;
2122 case SDDS_CHARACTER:
2123 char_val = (char)va_arg(argptr, int);
2124 short_dval = (short)va_arg(argptr, int);
2125 char_ptr = (char *)mem;
2126 for (i = 0; i < n_elements; i++, char_val += short_dval)
2127 *char_ptr++ = char_val;
2128 break;
2129 default:
2130 SDDS_SetError("Unable to set memory--unknown or invalid data type (SDDS_SetMemory)");
2131 retval = 0;
2132 break;
2133 }
2134 va_end(argptr);
2135 return (retval);
2136}
2137
2138/**
2139 * @brief Retrieves the data type of a column in the SDDS dataset by its index.
2140 *
2141 * This function returns the SDDS data type of the specified column within the dataset. The data type corresponds to one of the predefined SDDS type constants, such as `SDDS_LONGDOUBLE`, `SDDS_DOUBLE`, `SDDS_FLOAT`, etc.
2142 *
2143 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset.
2144 * @param[in] index The zero-based index of the column whose data type is to be retrieved. The index should be obtained from `SDDS_DefineColumn` or `SDDS_GetColumnIndex`.
2145 *
2146 * @return On success, returns the SDDS data type of the column as an `int32_t`. On failure (e.g., if the index is out of range or the dataset is invalid), returns `0` and records an error message.
2147 *
2148 * @note The function does not perform type validation beyond checking the index range. It assumes that the dataset's column definitions are correctly initialized.
2149 *
2150 * @see SDDS_GetColumnIndex
2151 * @see SDDS_SetError
2152 */
2153int32_t SDDS_GetColumnType(SDDS_DATASET *SDDS_dataset, int32_t index) {
2154 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_GetColumnType"))
2155 return (0);
2156 if (index < 0 || index >= SDDS_dataset->layout.n_columns) {
2157 SDDS_SetError("Unable to get column type--column index is out of range (SDDS_GetColumnType)");
2158 return (0);
2159 }
2160 return (SDDS_dataset->layout.column_definition[index].type);
2161}
2162
2163/**
2164 * @brief Retrieves the data type of a column in the SDDS dataset by its name.
2165 *
2166 * This function searches for a column by its name within the dataset and returns its SDDS data type. The data type corresponds to one of the predefined SDDS type constants, such as `SDDS_LONGDOUBLE`, `SDDS_DOUBLE`, `SDDS_FLOAT`, etc.
2167 *
2168 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset.
2169 * @param[in] name A null-terminated string specifying the name of the column whose data type is to be retrieved.
2170 *
2171 * @return On success, returns the SDDS data type of the column as an `int32_t`. On failure (e.g., if the column name is not found or the dataset is invalid), returns `0` and records an error message.
2172 *
2173 * @note The function internally uses `SDDS_GetColumnIndex` to find the column's index before retrieving its type.
2174 *
2175 * @see SDDS_GetColumnIndex
2176 * @see SDDS_SetError
2177 */
2178int32_t SDDS_GetNamedColumnType(SDDS_DATASET *SDDS_dataset, char *name) {
2179 int64_t index;
2180 if ((index = SDDS_GetColumnIndex(SDDS_dataset, name)) < 0 || index >= SDDS_dataset->layout.n_columns) {
2181 SDDS_SetError("Unable to get column type--column index is out of range (SDDS_GetNamedColumnType)");
2182 return (0);
2183 }
2184 return (SDDS_dataset->layout.column_definition[index].type);
2185}
2186
2187/**
2188 * @brief Retrieves the data type of an array in the SDDS dataset by its index.
2189 *
2190 * This function returns the SDDS data type of the specified array within the dataset. The data type corresponds to one of the predefined SDDS type constants, such as `SDDS_LONGDOUBLE`, `SDDS_DOUBLE`, `SDDS_FLOAT`, etc.
2191 *
2192 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset.
2193 * @param[in] index The zero-based index of the array whose data type is to be retrieved. The index should be obtained from `SDDS_DefineArray` or `SDDS_GetArrayIndex`.
2194 *
2195 * @return On success, returns the SDDS data type of the array as an `int32_t`. On failure (e.g., if the index is out of range or the dataset is invalid), returns `0` and records an error message.
2196 *
2197 * @note The function does not perform type validation beyond checking the index range. It assumes that the dataset's array definitions are correctly initialized.
2198 *
2199 * @see SDDS_GetArrayIndex
2200 * @see SDDS_SetError
2201 */
2202int32_t SDDS_GetArrayType(SDDS_DATASET *SDDS_dataset, int32_t index) {
2203 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_GetArrayType"))
2204 return (0);
2205 if (index < 0 || index >= SDDS_dataset->layout.n_arrays) {
2206 SDDS_SetError("Unable to get array type--array index is out of range (SDDS_GetArrayType)");
2207 return (0);
2208 }
2209 return (SDDS_dataset->layout.array_definition[index].type);
2210}
2211
2212/**
2213 * @brief Retrieves the data type of an array in the SDDS dataset by its name.
2214 *
2215 * This function searches for an array by its name within the dataset and returns its SDDS data type. The data type corresponds to one of the predefined SDDS type constants, such as `SDDS_LONGDOUBLE`, `SDDS_DOUBLE`, `SDDS_FLOAT`, etc.
2216 *
2217 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset.
2218 * @param[in] name A null-terminated string specifying the name of the array whose data type is to be retrieved.
2219 *
2220 * @return On success, returns the SDDS data type of the array as an `int32_t`. On failure (e.g., if the array name is not found or the dataset is invalid), returns `0` and records an error message.
2221 *
2222 * @note The function internally uses `SDDS_GetArrayIndex` to find the array's index before retrieving its type.
2223 *
2224 * @see SDDS_GetArrayIndex
2225 * @see SDDS_SetError
2226 */
2227int32_t SDDS_GetNamedArrayType(SDDS_DATASET *SDDS_dataset, char *name) {
2228 int32_t index;
2229 if ((index = SDDS_GetArrayIndex(SDDS_dataset, name)) < 0 || index >= SDDS_dataset->layout.n_arrays) {
2230 SDDS_SetError("Unable to get array type--array index is out of range (SDDS_GetNamedArrayType)");
2231 return (0);
2232 }
2233 return (SDDS_dataset->layout.array_definition[index].type);
2234}
2235
2236/**
2237 * @brief Retrieves the data type of a parameter in the SDDS dataset by its index.
2238 *
2239 * This function returns the SDDS data type of the specified parameter within the dataset. The data type corresponds to one of the predefined SDDS type constants, such as `SDDS_LONGDOUBLE`, `SDDS_DOUBLE`, `SDDS_FLOAT`, etc.
2240 *
2241 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset.
2242 * @param[in] index The zero-based index of the parameter whose data type is to be retrieved. The index should be obtained from `SDDS_DefineParameter` or `SDDS_GetParameterIndex`.
2243 *
2244 * @return On success, returns the SDDS data type of the parameter as an `int32_t`. On failure (e.g., if the index is out of range or the dataset is invalid), returns `0` and records an error message.
2245 *
2246 * @note The function does not perform type validation beyond checking the index range. It assumes that the dataset's parameter definitions are correctly initialized.
2247 *
2248 * @see SDDS_GetParameterIndex
2249 * @see SDDS_SetError
2250 */
2251int32_t SDDS_GetParameterType(SDDS_DATASET *SDDS_dataset, int32_t index) {
2252 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_GetParameterType"))
2253 return (0);
2254 if (index < 0 || index >= SDDS_dataset->layout.n_parameters) {
2255 SDDS_SetError("Unable to get parameter type--parameter index is out of range (SDDS_GetParameterType)");
2256 return (0);
2257 }
2258 return (SDDS_dataset->layout.parameter_definition[index].type);
2259}
2260
2261/**
2262 * @brief Retrieves the data type of a parameter in the SDDS dataset by its name.
2263 *
2264 * This function searches for a parameter by its name within the dataset and returns its SDDS data type. The data type corresponds to one of the predefined SDDS type constants, such as `SDDS_LONGDOUBLE`, `SDDS_DOUBLE`, `SDDS_FLOAT`, etc.
2265 *
2266 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset.
2267 * @param[in] name A null-terminated string specifying the name of the parameter whose data type is to be retrieved.
2268 *
2269 * @return On success, returns the SDDS data type of the parameter as an `int32_t`. On failure (e.g., if the parameter name is not found or the dataset is invalid), returns `0` and records an error message.
2270 *
2271 * @note The function internally uses `SDDS_GetParameterIndex` to find the parameter's index before retrieving its type.
2272 *
2273 * @see SDDS_GetParameterIndex
2274 * @see SDDS_SetError
2275 */
2276int32_t SDDS_GetNamedParameterType(SDDS_DATASET *SDDS_dataset, char *name) {
2277 int32_t index;
2278 if ((index = SDDS_GetParameterIndex(SDDS_dataset, name)) < 0 || index >= SDDS_dataset->layout.n_parameters) {
2279 SDDS_SetError("Unable to get parameter type--parameter index is out of range (SDDS_GetNamedParameterType)");
2280 return (0);
2281 }
2282 return (SDDS_dataset->layout.parameter_definition[index].type);
2283}
2284
2285/**
2286 * @brief Retrieves the size in bytes of a specified SDDS data type.
2287 *
2288 * This function returns the size, in bytes, of the specified SDDS data type. The size corresponds to the memory footprint of the data type when stored in the dataset.
2289 *
2290 * @param[in] type The SDDS data type for which the size is requested. Must be one of the predefined constants:
2291 * - `SDDS_LONGDOUBLE`
2292 * - `SDDS_DOUBLE`
2293 * - `SDDS_FLOAT`
2294 * - `SDDS_LONG`
2295 * - `SDDS_ULONG`
2296 * - `SDDS_SHORT`
2297 * - `SDDS_USHORT`
2298 * - `SDDS_CHARACTER`
2299 * - `SDDS_STRING`
2300 *
2301 * @return On success, returns a positive integer representing the size of the data type in bytes. On failure (e.g., if the type is invalid), returns `-1` and records an error message.
2302 *
2303 * @note The function relies on the `SDDS_type_size` array, which should be properly initialized with the sizes of all supported SDDS data types.
2304 *
2305 * @see SDDS_GetTypeName
2306 * @see SDDS_SetError
2307 */
2308int32_t SDDS_GetTypeSize(int32_t type) {
2309 if (!SDDS_VALID_TYPE(type))
2310 return (-1);
2311 return (SDDS_type_size[type - 1]);
2312}
2313
2314/**
2315 * @brief Retrieves the name of a specified SDDS data type as a string.
2316 *
2317 * This function returns a dynamically allocated string containing the name of the specified SDDS data type. The name corresponds to the textual representation of the data type, such as `"double"`, `"float"`, `"int32"`, etc.
2318 *
2319 * @param[in] type The SDDS data type for which the name is requested. Must be one of the predefined constants:
2320 * - `SDDS_LONGDOUBLE`
2321 * - `SDDS_DOUBLE`
2322 * - `SDDS_FLOAT`
2323 * - `SDDS_LONG`
2324 * - `SDDS_ULONG`
2325 * - `SDDS_SHORT`
2326 * - `SDDS_USHORT`
2327 * - `SDDS_CHARACTER`
2328 * - `SDDS_STRING`
2329 *
2330 * @return On success, returns a pointer to a newly allocated string containing the name of the data type. On failure (e.g., if the type is invalid or memory allocation fails), returns `NULL`.
2331 *
2332 * @note The caller is responsible for freeing the memory allocated for the returned string using `SDDS_Free`.
2333 *
2334 * @see SDDS_GetTypeSize
2335 * @see SDDS_SetError
2336 */
2337char *SDDS_GetTypeName(int32_t type) {
2338 char *name;
2339 if (!SDDS_VALID_TYPE(type))
2340 return NULL;
2341 if (!SDDS_CopyString(&name, SDDS_type_name[type - 1]))
2342 return NULL;
2343 return name;
2344}
2345
2346/**
2347 * @brief Identifies the SDDS data type based on its string name.
2348 *
2349 * This function searches for the SDDS data type that matches the provided string `typeName`. It returns the corresponding SDDS data type constant if a match is found.
2350 *
2351 * @param[in] typeName A null-terminated string representing the name of the SDDS data type to identify.
2352 *
2353 * @return On success, returns the SDDS data type constant (`int32_t`) corresponding to `typeName`. On failure (e.g., if `typeName` does not match any known data type), returns `0`.
2354 *
2355 * @note The function performs a case-sensitive comparison between `typeName` and the names of supported SDDS data types.
2356 *
2357 * @see SDDS_GetTypeName
2358 * @see SDDS_SetError
2359 */
2360int32_t SDDS_IdentifyType(char *typeName) {
2361 int32_t i;
2362 for (i = 0; i < SDDS_NUM_TYPES; i++)
2363 if (strcmp(typeName, SDDS_type_name[i]) == 0)
2364 return i + 1;
2365 return 0;
2366}
2367
2368/**
2369 * @brief Removes leading and trailing whitespace from a string.
2370 *
2371 * This function trims all leading and trailing whitespace characters from the input string `s`. It modifies the string in place, ensuring that any padding spaces are removed while preserving the internal content.
2372 *
2373 * @param[in,out] s Pointer to the null-terminated string to be trimmed. The string will be modified in place.
2374 *
2375 * @note The function handles all standard whitespace characters as defined by the `isspace` function. If the string consists entirely of whitespace, the function will result in an empty string.
2376 *
2377 * @see isspace
2378 */
2379void SDDS_RemovePadding(char *s) {
2380 char *ptr;
2381 ptr = s;
2382 while (isspace(*ptr))
2383 ptr++;
2384 if (ptr != s)
2385 strcpy(s, ptr);
2386 ptr = s + strlen(s) - 1;
2387 while (isspace(*ptr))
2388 *ptr-- = 0;
2389}
2390
2391/**
2392 * @brief Checks if a string is blank (contains only whitespace characters).
2393 *
2394 * This function determines whether the provided NULL-terminated string `s` consists solely of whitespace characters. If the string is `NULL` or contains only whitespace, the function returns `1`. If the string contains any non-whitespace characters, it returns `0`.
2395 *
2396 * @param[in] s Pointer to the NULL-terminated string to be checked.
2397 *
2398 * @return
2399 * - Returns `1` if the string is `NULL` or contains only whitespace characters.
2400 * - Returns `0` if the string contains any non-whitespace characters.
2401 *
2402 * @see isspace
2403 */
2404int32_t SDDS_StringIsBlank(char *s) {
2405 if (!s)
2406 return 1;
2407 while (*s)
2408 if (!isspace(*s++))
2409 return (0);
2410 return (1);
2411}
2412
2413/**
2414 * @brief Determines if a specified column is marked as of interest in the dataset.
2415 *
2416 * This function checks whether the column with the given `name` is flagged as of interest within the provided `SDDS_dataset`. It verifies the dataset's validity and then iterates through the columns to find a match based on the `column_flag` array.
2417 *
2418 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset.
2419 * @param[in] name A NULL-terminated string specifying the name of the column to check.
2420 *
2421 * @return
2422 * - Returns `1` if the column is marked as of interest.
2423 * - Returns `0` if the column is not marked as of interest or if `column_flag` is not set.
2424 * - Returns `-1` if the dataset is invalid.
2425 *
2426 * @see SDDS_CheckDataset
2427 */
2428int32_t SDDS_ColumnIsOfInterest(SDDS_DATASET *SDDS_dataset, char *name) {
2429 int64_t i;
2430 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_ColumnIsOfInterest"))
2431 return -1;
2432 if (!SDDS_dataset->column_flag)
2433 return 0;
2434 for (i = 0; i < SDDS_dataset->layout.n_columns; i++) {
2435 if (SDDS_dataset->column_flag[i] && strcmp(name, SDDS_dataset->layout.column_definition[i].name) == 0)
2436 return 1;
2437 }
2438 return 0;
2439}
2440
2441/**
2442 * @brief Retrieves the names of all columns in the SDDS dataset.
2443 *
2444 * This function allocates and returns an array of NULL-terminated strings containing the names of the columns in the provided `SDDS_dataset`. It only includes columns that are flagged as of interest if `column_flag` is set.
2445 *
2446 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset.
2447 * @param[out] number Pointer to an `int32_t` variable where the number of retrieved column names will be stored.
2448 *
2449 * @return
2450 * - Returns a pointer to an array of NULL-terminated strings containing the column names on success.
2451 * - Returns `NULL` on failure (e.g., if the dataset is invalid or memory allocation fails) and records an error message.
2452 *
2453 * @note The caller is responsible for freeing the memory allocated for the returned array and its strings using `SDDS_FreeStringArray` or similar functions.
2454 *
2455 * @see SDDS_CheckDataset
2456 * @see SDDS_Malloc
2457 * @see SDDS_CopyString
2458 * @see SDDS_SetError
2459 */
2460char **SDDS_GetColumnNames(SDDS_DATASET *SDDS_dataset, int32_t *number) {
2461 int64_t i;
2462 char **name;
2463 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_GetColumnNames"))
2464 return (NULL);
2465 *number = 0;
2466 if (!(name = (char **)SDDS_Malloc(sizeof(*name) * SDDS_dataset->layout.n_columns))) {
2467 SDDS_SetError("Unable to get column names--allocation failure (SDDS_GetColumnNames)");
2468 return (NULL);
2469 }
2470 for (i = 0; i < SDDS_dataset->layout.n_columns; i++) {
2471 if (!SDDS_dataset->column_flag || SDDS_dataset->column_flag[i]) {
2472 if (!SDDS_CopyString(name + *number, SDDS_dataset->layout.column_definition[i].name)) {
2473 free(name);
2474 return (NULL);
2475 }
2476 *number += 1;
2477 }
2478 }
2479 return (name);
2480}
2481
2482/**
2483 * @brief Retrieves the names of all parameters in the SDDS dataset.
2484 *
2485 * This function allocates and returns an array of NULL-terminated strings containing the names of the parameters in the provided `SDDS_dataset`.
2486 *
2487 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset.
2488 * @param[out] number Pointer to an `int32_t` variable where the number of retrieved parameter names will be stored.
2489 *
2490 * @return
2491 * - Returns a pointer to an array of NULL-terminated strings containing the parameter names on success.
2492 * - Returns `NULL` on failure (e.g., if the dataset is invalid or memory allocation fails) and records an error message.
2493 *
2494 * @note The caller is responsible for freeing the memory allocated for the returned array and its strings using `SDDS_FreeStringArray` or similar functions.
2495 *
2496 * @see SDDS_CheckDataset
2497 * @see SDDS_Malloc
2498 * @see SDDS_CopyString
2499 * @see SDDS_SetError
2500 */
2501char **SDDS_GetParameterNames(SDDS_DATASET *SDDS_dataset, int32_t *number) {
2502 int32_t i;
2503 char **name;
2504 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_GetParameterNames"))
2505 return (NULL);
2506 *number = SDDS_dataset->layout.n_parameters;
2507 if (!(name = (char **)SDDS_Malloc(sizeof(*name) * SDDS_dataset->layout.n_parameters))) {
2508 SDDS_SetError("Unable to get parameter names--allocation failure (SDDS_GetParameterNames)");
2509 return (NULL);
2510 }
2511 for (i = 0; i < SDDS_dataset->layout.n_parameters; i++) {
2512 if (!SDDS_CopyString(name + i, SDDS_dataset->layout.parameter_definition[i].name)) {
2513 free(name);
2514 return (NULL);
2515 }
2516 }
2517 return (name);
2518}
2519
2520/**
2521 * @brief Retrieves the names of all arrays in the SDDS dataset.
2522 *
2523 * This function allocates and returns an array of NULL-terminated strings containing the names of the arrays in the provided `SDDS_dataset`.
2524 *
2525 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset.
2526 * @param[out] number Pointer to an `int32_t` variable where the number of retrieved array names will be stored.
2527 *
2528 * @return
2529 * - Returns a pointer to an array of NULL-terminated strings containing the array names on success.
2530 * - Returns `NULL` on failure (e.g., if the dataset is invalid or memory allocation fails) and records an error message.
2531 *
2532 * @note The caller is responsible for freeing the memory allocated for the returned array and its strings using `SDDS_FreeStringArray` or similar functions.
2533 *
2534 * @see SDDS_CheckDataset
2535 * @see SDDS_Malloc
2536 * @see SDDS_CopyString
2537 * @see SDDS_SetError
2538 */
2539char **SDDS_GetArrayNames(SDDS_DATASET *SDDS_dataset, int32_t *number) {
2540 int32_t i;
2541 char **name;
2542 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_GetArrayNames"))
2543 return (NULL);
2544 *number = SDDS_dataset->layout.n_arrays;
2545 if (!(name = (char **)SDDS_Malloc(sizeof(*name) * SDDS_dataset->layout.n_arrays))) {
2546 SDDS_SetError("Unable to get array names--allocation failure (SDDS_GetArrayNames)");
2547 return (NULL);
2548 }
2549 for (i = 0; i < SDDS_dataset->layout.n_arrays; i++) {
2550 if (!SDDS_CopyString(name + i, SDDS_dataset->layout.array_definition[i].name)) {
2551 free(name);
2552 return (NULL);
2553 }
2554 }
2555 return (name);
2556}
2557
2558/**
2559 * @brief Retrieves the names of all associates in the SDDS dataset.
2560 *
2561 * This function allocates and returns an array of NULL-terminated strings containing the names of the associates in the provided `SDDS_dataset`.
2562 *
2563 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset.
2564 * @param[out] number Pointer to an `int32_t` variable where the number of retrieved associate names will be stored.
2565 *
2566 * @return
2567 * - Returns a pointer to an array of NULL-terminated strings containing the associate names on success.
2568 * - Returns `NULL` on failure (e.g., if the dataset is invalid or memory allocation fails) and records an error message.
2569 *
2570 * @note The caller is responsible for freeing the memory allocated for the returned array and its strings using `SDDS_FreeStringArray` or similar functions.
2571 *
2572 * @see SDDS_CheckDataset
2573 * @see SDDS_Malloc
2574 * @see SDDS_CopyString
2575 * @see SDDS_SetError
2576 */
2577char **SDDS_GetAssociateNames(SDDS_DATASET *SDDS_dataset, int32_t *number) {
2578 int32_t i;
2579 char **name;
2580 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_GetAssociateNames"))
2581 return (NULL);
2582 if (!(name = (char **)SDDS_Malloc(sizeof(*name) * SDDS_dataset->layout.n_associates))) {
2583 SDDS_SetError("Unable to get associate names--allocation failure (SDDS_GetAssociateNames)");
2584 return (NULL);
2585 }
2586 *number = SDDS_dataset->layout.n_associates;
2587 for (i = 0; i < SDDS_dataset->layout.n_associates; i++) {
2588 if (!SDDS_CopyString(name + i, SDDS_dataset->layout.associate_definition[i].name)) {
2589 free(name);
2590 return (NULL);
2591 }
2592 }
2593 return (name);
2594}
2595
2596/**
2597 * @brief Casts a value from one SDDS data type to another.
2598 *
2599 * This function converts a value from its original SDDS data type (`data_type`) to a desired SDDS data type (`desired_type`). It retrieves the value at the specified `index` from the `data` array and stores the converted value in the provided `memory` location.
2600 *
2601 * @param[in] data Pointer to the data array containing the original values.
2602 * @param[in] index The zero-based index of the value to be casted within the `data` array.
2603 * @param[in] data_type The original SDDS data type of the value. Must be one of the SDDS type constants:
2604 * - `SDDS_SHORT`
2605 * - `SDDS_USHORT`
2606 * - `SDDS_LONG`
2607 * - `SDDS_ULONG`
2608 * - `SDDS_LONG64`
2609 * - `SDDS_ULONG64`
2610 * - `SDDS_CHARACTER`
2611 * - `SDDS_FLOAT`
2612 * - `SDDS_DOUBLE`
2613 * - `SDDS_LONGDOUBLE`
2614 * @param[in] desired_type The desired SDDS data type to which the value should be casted. Must be one of the SDDS type constants listed above.
2615 * @param[out] memory Pointer to the memory location where the casted value will be stored.
2616 *
2617 * @return
2618 * - Returns a pointer to the `memory` location containing the casted value on success.
2619 * - Returns `NULL` if the casting fails due to invalid data types or other errors.
2620 *
2621 * @note
2622 * - The function does not handle casting for `SDDS_STRING` types.
2623 * - The caller must ensure that the `memory` location has sufficient space to store the casted value.
2624 *
2625 * @see SDDS_CopyString
2626 * @see SDDS_SetError
2627 */
2628void *SDDS_CastValue(void *data, int64_t index, int32_t data_type, int32_t desired_type, void *memory) {
2629 long long integer_value;
2630 long double fp_value;
2631 if (!data || !memory || data_type == SDDS_STRING || desired_type == SDDS_STRING)
2632 return (NULL);
2633 if (data_type == desired_type) {
2634 memcpy(memory, (char *)data + SDDS_type_size[data_type - 1] * index, SDDS_type_size[data_type - 1]);
2635 return (memory);
2636 }
2637 switch (data_type) {
2638 case SDDS_SHORT:
2639 integer_value = *((short *)data + index);
2640 fp_value = integer_value;
2641 break;
2642 case SDDS_USHORT:
2643 integer_value = *((unsigned short *)data + index);
2644 fp_value = integer_value;
2645 break;
2646 case SDDS_LONG:
2647 integer_value = *((int32_t *)data + index);
2648 fp_value = integer_value;
2649 break;
2650 case SDDS_ULONG:
2651 integer_value = *((uint32_t *)data + index);
2652 fp_value = integer_value;
2653 break;
2654 case SDDS_LONG64:
2655 integer_value = *((int64_t *)data + index);
2656 fp_value = integer_value;
2657 break;
2658 case SDDS_ULONG64:
2659 integer_value = *((uint64_t *)data + index);
2660 fp_value = integer_value;
2661 break;
2662 case SDDS_CHARACTER:
2663 integer_value = *((unsigned char *)data + index);
2664 fp_value = integer_value;
2665 break;
2666 case SDDS_FLOAT:
2667 fp_value = *((float *)data + index);
2668 integer_value = fp_value;
2669 break;
2670 case SDDS_DOUBLE:
2671 fp_value = *((double *)data + index);
2672 integer_value = fp_value;
2673 break;
2674 case SDDS_LONGDOUBLE:
2675 fp_value = *((long double *)data + index);
2676 integer_value = fp_value;
2677 break;
2678 default:
2679 return (NULL);
2680 }
2681 switch (desired_type) {
2682 case SDDS_CHARACTER:
2683 *((char *)memory) = integer_value;
2684 break;
2685 case SDDS_SHORT:
2686 *((short *)memory) = integer_value;
2687 break;
2688 case SDDS_USHORT:
2689 *((unsigned short *)memory) = integer_value;
2690 break;
2691 case SDDS_LONG:
2692 *((int32_t *)memory) = integer_value;
2693 break;
2694 case SDDS_ULONG:
2695 *((uint32_t *)memory) = integer_value;
2696 break;
2697 case SDDS_LONG64:
2698 *((int64_t *)memory) = integer_value;
2699 break;
2700 case SDDS_ULONG64:
2701 *((uint64_t *)memory) = integer_value;
2702 break;
2703 case SDDS_FLOAT:
2704 *((float *)memory) = fp_value;
2705 break;
2706 case SDDS_DOUBLE:
2707 *((double *)memory) = fp_value;
2708 break;
2709 case SDDS_LONGDOUBLE:
2710 *((long double *)memory) = fp_value;
2711 break;
2712 default:
2713 SDDS_SetError("The impossible has happened (SDDS_CastValue)");
2714 return (NULL);
2715 }
2716 return (memory);
2717}
2718
2719/**
2720 * @brief Allocates a two-dimensional matrix with zero-initialized elements.
2721 *
2722 * This function allocates memory for a two-dimensional matrix based on the specified dimensions and element size. Each row of the matrix is individually allocated and initialized to zero.
2723 *
2724 * @param[in] size The size in bytes of each element in the matrix.
2725 * @param[in] dim1 The number of rows in the matrix.
2726 * @param[in] dim2 The number of columns in the matrix.
2727 *
2728 * @return
2729 * - Returns a pointer to the allocated two-dimensional matrix on success.
2730 * - Returns `NULL` if memory allocation fails.
2731 *
2732 * @note
2733 * - The function uses `calloc` to ensure that all elements are zero-initialized.
2734 * - The caller is responsible for freeing the allocated memory using `SDDS_FreeMatrix`.
2735 *
2736 * @see SDDS_FreeMatrix
2737 * @see calloc
2738 */
2739void *SDDS_AllocateMatrix(int32_t size, int64_t dim1, int64_t dim2) {
2740 int64_t i;
2741 void **data;
2742
2743 if (!(data = (void **)SDDS_Malloc(sizeof(*data) * dim1)))
2744 return (NULL);
2745 for (i = 0; i < dim1; i++)
2746 if (!(data[i] = (void *)calloc(dim2, size)))
2747 return (NULL);
2748 return (data);
2749}
2750
2751/**
2752 * @brief Frees memory allocated for an SDDS array structure.
2753 *
2754 * This function deallocates all memory associated with an `SDDS_ARRAY` structure, including its data and definition. It handles the freeing of string elements if the array type is `SDDS_STRING` and ensures that all pointers are set to `NULL` after deallocation to prevent dangling references.
2755 *
2756 * @param[in] array Pointer to the `SDDS_ARRAY` structure to be freed.
2757 *
2758 * @note
2759 * - The function assumes that the array's data and definitions were allocated using SDDS memory management functions.
2760 * - After calling this function, the `array` pointer becomes invalid and should not be used.
2761 *
2762 * @see SDDS_FreePointerArray
2763 * @see SDDS_FreeArrayDefinition
2764 * @see SDDS_Free
2765 */
2767 int i;
2768 if (!array)
2769 return;
2770 if (array->definition) {
2771 if ((array->definition->type == SDDS_STRING) && (array->data)) {
2772 char **str = (char **)array->data;
2773 for (i = 0; i < array->elements; i++) {
2774 if (str[i])
2775 free(str[i]);
2776 str[i] = NULL;
2777 }
2778 }
2779 }
2780 if (array->definition && array->pointer)
2781 SDDS_FreePointerArray(array->pointer, array->definition->dimensions, array->dimension);
2782 if (array->data)
2783 free(array->data);
2784 array->pointer = array->data = NULL;
2785 if (array->dimension)
2786 free(array->dimension);
2787 if (array->definition)
2788 SDDS_FreeArrayDefinition(array->definition);
2789 array->definition = NULL;
2790 free(array);
2791 array = NULL;
2792}
2793
2794/**
2795 * @brief Frees memory allocated for a two-dimensional matrix.
2796 *
2797 * This function deallocates a two-dimensional matrix by freeing each row individually followed by the matrix pointer itself.
2798 *
2799 * @param[in] ptr Pointer to the two-dimensional matrix to be freed.
2800 * @param[in] dim1 The number of rows in the matrix.
2801 *
2802 * @note
2803 * - The function assumes that the matrix was allocated using `SDDS_AllocateMatrix` or similar memory allocation functions.
2804 *
2805 * @see SDDS_AllocateMatrix
2806 * @see free
2807 */
2808void SDDS_FreeMatrix(void **ptr, int64_t dim1) {
2809 int64_t i;
2810 if (!ptr)
2811 return;
2812 for (i = 0; i < dim1; i++)
2813 free(ptr[i]);
2814 free(ptr);
2815}
2816
2817/**
2818 * @brief Copies an array of strings from source to target.
2819 *
2820 * This function duplicates each string from the `source` array into the `target` array. It handles memory allocation for each individual string using `SDDS_CopyString`.
2821 *
2822 * @param[in] target Pointer to the destination array of strings where the copied strings will be stored.
2823 * @param[in] source Pointer to the source array of strings to be copied.
2824 * @param[in] n_strings The number of strings to copy from the source to the target.
2825 *
2826 * @return
2827 * - Returns `1` on successful copying of all strings.
2828 * - Returns `0` if either `source` or `target` is `NULL`, or if any string copy operation fails.
2829 *
2830 * @note
2831 * - The caller is responsible for ensuring that the `target` array has sufficient space allocated.
2832 * - In case of failure, partially copied strings may remain in the `target` array.
2833 *
2834 * @see SDDS_CopyString
2835 * @see SDDS_Malloc
2836 */
2837int32_t SDDS_CopyStringArray(char **target, char **source, int64_t n_strings) {
2838 if (!source || !target)
2839 return (0);
2840 while (n_strings--) {
2841 if (!SDDS_CopyString(target + n_strings, source[n_strings]))
2842 return (0);
2843 }
2844 return (1);
2845}
2846
2847/**
2848 * @brief Frees an array of strings by deallocating each individual string.
2849 *
2850 * This function iterates through an array of strings, freeing each non-NULL string and setting its pointer to `NULL` to prevent dangling references.
2851 *
2852 * @param[in,out] string Array of strings to be freed.
2853 * @param[in] strings The number of elements in the `string` array.
2854 *
2855 * @return
2856 * - Returns `1` if the array is successfully freed.
2857 * - Returns `0` if the `string` pointer is `NULL`.
2858 *
2859 * @note
2860 * - After calling this function, all string pointers within the array are set to `NULL`.
2861 *
2862 * @see SDDS_Free
2863 * @see free
2864 */
2865int32_t SDDS_FreeStringArray(char **string, int64_t strings) {
2866 int64_t i;
2867 if (!string)
2868 return 0;
2869 for (i = 0; i < strings; i++)
2870 if (string[i]) {
2871 free(string[i]);
2872 string[i] = NULL;
2873 }
2874 return 1;
2875}
2876
2877/**
2878 * @brief Recursively creates a multi-dimensional pointer array from a contiguous data block.
2879 *
2880 * This internal function is used to build a multi-dimensional pointer array by recursively allocating pointer layers based on the specified dimensions. It maps the contiguous data block to the pointer structure, facilitating easy access to multi-dimensional data.
2881 *
2882 * @param[in] data Pointer to the data block or intermediate pointer array.
2883 * @param[in] size The size in bytes of each element in the current dimension.
2884 * @param[in] dimensions The number of remaining dimensions to process.
2885 * @param[in] dimension An array specifying the size of each remaining dimension.
2886 *
2887 * @return
2888 * - Returns a pointer to the next layer of the pointer array on success.
2889 * - Returns `NULL` if the input data is `NULL`, the `dimension` array is invalid, the `size` is non-positive, or memory allocation fails.
2890 *
2891 * @note
2892 * - This function maintains a static `depth` variable to track recursion depth for error reporting.
2893 * - It is intended for internal use within the SDDS library and should not be called directly by user code.
2894 *
2895 * @see SDDS_MakePointerArray
2896 * @see SDDS_SetError
2897 * @see SDDS_Malloc
2898 * @see SDDS_type_size
2899 */
2900void *SDDS_MakePointerArrayRecursively(void *data, int32_t size, int32_t dimensions, int32_t *dimension) {
2901 void **pointer;
2902 int32_t i, elements;
2903 static int32_t depth = 0;
2904 static char s[200];
2905
2906 depth += 1;
2907 if (!data) {
2908 sprintf(s, "Unable to make pointer array--NULL data array (SDDS_MakePointerArrayRecursively, recursion %" PRId32 ")", depth);
2909 SDDS_SetError(s);
2910 return (NULL);
2911 }
2912 if (!dimension || !dimensions) {
2913 sprintf(s, "Unable to make pointer array--NULL or zero-length dimension array (SDDS_MakePointerArrayRecursively, recursion %" PRId32 ")", depth);
2914 SDDS_SetError(s);
2915 return (NULL);
2916 }
2917 if (size <= 0) {
2918 sprintf(s, "Unable to make pointer array--invalid data size (SDDS_MakePointerArrayRecursively, recursion %" PRId32 ")", depth);
2919 SDDS_SetError(s);
2920 return (NULL);
2921 }
2922 if (dimensions == 1) {
2923 depth -= 1;
2924 return (data);
2925 }
2926 elements = 1;
2927 for (i = 0; i < dimensions - 1; i++)
2928 elements *= dimension[i];
2929 if (!(pointer = (void **)SDDS_Malloc(sizeof(void *) * elements))) {
2930 sprintf(s, "Unable to make pointer array--allocation failure (SDDS_MakePointerArrayRecursively, recursion %" PRId32 ")", depth);
2931 SDDS_SetError(s);
2932 return (NULL);
2933 }
2934 for (i = 0; i < elements; i++)
2935 pointer[i] = (char *)data + i * size * dimension[dimensions - 1];
2936 return (SDDS_MakePointerArrayRecursively(pointer, sizeof(*pointer), dimensions - 1, dimension));
2937}
2938
2939/**
2940 * @brief Creates a multi-dimensional pointer array from a contiguous data block.
2941 *
2942 * This function generates a multi-dimensional pointer array that maps to a contiguous block of data. It supports arrays with multiple dimensions by recursively creating pointer layers. The `dimensions` parameter specifies the number of dimensions, and the `dimension` array provides the size for each dimension.
2943 *
2944 * @param[in] data Pointer to the contiguous data block to be mapped.
2945 * @param[in] type The SDDS data type of the elements in the data block. Must be one of the SDDS type constants:
2946 * - `SDDS_SHORT`
2947 * - `SDDS_USHORT`
2948 * - `SDDS_LONG`
2949 * - `SDDS_ULONG`
2950 * - `SDDS_LONG64`
2951 * - `SDDS_ULONG64`
2952 * - `SDDS_FLOAT`
2953 * - `SDDS_DOUBLE`
2954 * - `SDDS_LONGDOUBLE`
2955 * - `SDDS_CHARACTER`
2956 * @param[in] dimensions The number of dimensions for the pointer array.
2957 * @param[in] dimension An array specifying the size of each dimension.
2958 *
2959 * @return
2960 * - Returns a pointer to the newly created multi-dimensional pointer array on success.
2961 * - Returns `NULL` if the input data is `NULL`, the `dimension` array is invalid, the `type` is unknown, or memory allocation fails.
2962 *
2963 * @note
2964 * - The function uses `SDDS_MakePointerArrayRecursively` to handle multi-dimensional allocations.
2965 * - The caller is responsible for freeing the allocated pointer array using `SDDS_FreePointerArray`.
2966 *
2967 * @see SDDS_MakePointerArrayRecursively
2968 * @see SDDS_FreePointerArray
2969 * @see SDDS_SetError
2970 */
2971void *SDDS_MakePointerArray(void *data, int32_t type, int32_t dimensions, int32_t *dimension) {
2972 int32_t i;
2973
2974 if (!data) {
2975 SDDS_SetError("Unable to make pointer array--NULL data array (SDDS_MakePointerArray)");
2976 return (NULL);
2977 }
2978 if (!dimension || !dimensions) {
2979 SDDS_SetError("Unable to make pointer array--NULL or zero-length dimension array (SDDS_MakePointerArray)");
2980 return (NULL);
2981 }
2982 if (type <= 0 || type > SDDS_NUM_TYPES) {
2983 SDDS_SetError("Unable to make pointer array--unknown data type (SDDS_MakePointerArray)");
2984 return (NULL);
2985 }
2986 for (i = 0; i < dimensions; i++)
2987 if (dimension[i] <= 0) {
2988 SDDS_SetError("Unable to make pointer array--number of elements invalid (SDDS_MakePointerArray)");
2989 return (NULL);
2990 }
2991 if (dimensions == 1)
2992 return (data);
2993 return (SDDS_MakePointerArrayRecursively(data, SDDS_type_size[type - 1], dimensions, dimension));
2994}
2995
2996/**
2997 * @brief Frees a multi-dimensional pointer array created by SDDS_MakePointerArray.
2998 *
2999 * This function recursively deallocates a multi-dimensional pointer array that was previously created using `SDDS_MakePointerArray` or `SDDS_MakePointerArrayRecursively`. It ensures that all pointer layers are properly freed to prevent memory leaks.
3000 *
3001 * @param[in] data Pointer to the multi-dimensional pointer array to be freed.
3002 * @param[in] dimensions The number of dimensions in the pointer array.
3003 * @param[in] dimension An array specifying the size of each dimension.
3004 *
3005 * @note
3006 * - The function assumes that the pointer array was created using SDDS library functions.
3007 * - It does not free the actual data block pointed to by the pointer array.
3008 *
3009 * @see SDDS_MakePointerArrayRecursively
3010 * @see free
3011 */
3012void SDDS_FreePointerArray(void **data, int32_t dimensions, int32_t *dimension)
3013/* This procedure is specifically for freeing the pointer arrays made by SDDS_MakePointerArray
3014 * and *will not* work with general pointer arrays
3015 */
3016{
3017 if (!data || !dimension || !dimensions)
3018 return;
3019 if (dimensions > 1) {
3020 SDDS_FreePointerArray((void **)(data[0]), dimensions - 1, dimension + 1);
3021 free(data);
3022 }
3023}
3024
3025/**
3026 * @brief Applies a scaling factor to a specific parameter in the SDDS dataset.
3027 *
3028 * This function multiplies the value of a specified parameter by the given `factor`. It first retrieves the parameter's index and verifies that it is of a numeric type. The scaling operation is performed in-place on the parameter's data.
3029 *
3030 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset.
3031 * @param[in] name A NULL-terminated string specifying the name of the parameter to scale.
3032 * @param[in] factor The scaling factor to apply to the parameter's value.
3033 *
3034 * @return
3035 * - Returns `1` on successful application of the factor.
3036 * - Returns `0` if the parameter is not found, is non-numeric, or if the dataset lacks the necessary data array.
3037 *
3038 * @note
3039 * - The function modifies the parameter's value directly within the dataset.
3040 * - It supports various numeric SDDS data types.
3041 *
3042 * @see SDDS_GetParameterIndex
3043 * @see SDDS_NUMERIC_TYPE
3044 * @see SDDS_SetError
3045 */
3046int32_t SDDS_ApplyFactorToParameter(SDDS_DATASET *SDDS_dataset, char *name, double factor) {
3047 int32_t type, index;
3048 void *data;
3049
3050 if ((index = SDDS_GetParameterIndex(SDDS_dataset, name)) < 0)
3051 return (0);
3052 type = SDDS_dataset->layout.parameter_definition[index].type;
3053 if (!SDDS_NUMERIC_TYPE(type)) {
3054 SDDS_SetError("Unable to apply factor to non-numeric parameter (SDDS_ApplyFactorToParameter)");
3055 return (0);
3056 }
3057 if (!SDDS_dataset->parameter) {
3058 SDDS_SetError("Unable to apply factor to parameter--no parameter data array (SDDS_ApplyFactorToParameter)");
3059 return (0);
3060 }
3061 if (!(data = SDDS_dataset->parameter[index])) {
3062 SDDS_SetError("Unable to apply factor to parameter--no data array (SDDS_ApplyFactorToParameter)");
3063 return (0);
3064 }
3065 switch (type) {
3066 case SDDS_SHORT:
3067 *((short *)data) *= factor;
3068 break;
3069 case SDDS_USHORT:
3070 *((unsigned short *)data) *= factor;
3071 break;
3072 case SDDS_LONG:
3073 *((int32_t *)data) *= factor;
3074 break;
3075 case SDDS_ULONG:
3076 *((uint32_t *)data) *= factor;
3077 break;
3078 case SDDS_LONG64:
3079 *((int64_t *)data) *= factor;
3080 break;
3081 case SDDS_ULONG64:
3082 *((uint64_t *)data) *= factor;
3083 break;
3084 case SDDS_CHARACTER:
3085 *((char *)data) *= factor;
3086 break;
3087 case SDDS_FLOAT:
3088 *((float *)data) *= factor;
3089 break;
3090 case SDDS_DOUBLE:
3091 *((double *)data) *= factor;
3092 break;
3093 case SDDS_LONGDOUBLE:
3094 *((long double *)data) *= factor;
3095 break;
3096 default:
3097 return (0);
3098 }
3099 return (1);
3100}
3101
3102/**
3103 * @brief Applies a scaling factor to all elements of a specific column in the SDDS dataset.
3104 *
3105 * This function multiplies each value in the specified column by the given `factor`. It first retrieves the column's index and verifies that it is of a numeric type. The scaling operation is performed in-place on each element of the column's data array.
3106 *
3107 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure representing the dataset.
3108 * @param[in] name A NULL-terminated string specifying the name of the column to scale.
3109 * @param[in] factor The scaling factor to apply to each element of the column.
3110 *
3111 * @return
3112 * - Returns `1` on successful application of the factor to all elements.
3113 * - Returns `0` if the column is not found, is non-numeric, or if the dataset lacks the necessary data array.
3114 *
3115 * @note
3116 * - The function modifies each element of the column's data array directly within the dataset.
3117 * - It supports various numeric SDDS data types.
3118 *
3119 * @see SDDS_GetColumnIndex
3120 * @see SDDS_NUMERIC_TYPE
3121 * @see SDDS_SetError
3122 */
3123int32_t SDDS_ApplyFactorToColumn(SDDS_DATASET *SDDS_dataset, char *name, double factor) {
3124 int32_t type, index;
3125 int64_t i;
3126 void *data;
3127
3128 if ((index = SDDS_GetColumnIndex(SDDS_dataset, name)) < 0)
3129 return (0);
3130 type = SDDS_dataset->layout.column_definition[index].type;
3131 if (!SDDS_NUMERIC_TYPE(type)) {
3132 SDDS_SetError("Unable to apply factor to non-numeric column (SDDS_ApplyFactorToColumn)");
3133 return (0);
3134 }
3135 data = SDDS_dataset->data[index];
3136 for (i = 0; i < SDDS_dataset->n_rows; i++) {
3137 switch (type) {
3138 case SDDS_SHORT:
3139 *((short *)data + i) *= factor;
3140 break;
3141 case SDDS_USHORT:
3142 *((unsigned short *)data + i) *= factor;
3143 break;
3144 case SDDS_LONG:
3145 *((int32_t *)data + i) *= factor;
3146 break;
3147 case SDDS_ULONG:
3148 *((uint32_t *)data + i) *= factor;
3149 break;
3150 case SDDS_LONG64:
3151 *((int64_t *)data + i) *= factor;
3152 break;
3153 case SDDS_ULONG64:
3154 *((uint64_t *)data + i) *= factor;
3155 break;
3156 case SDDS_CHARACTER:
3157 *((char *)data + i) *= factor;
3158 break;
3159 case SDDS_FLOAT:
3160 *((float *)data + i) *= factor;
3161 break;
3162 case SDDS_DOUBLE:
3163 *((double *)data + i) *= factor;
3164 break;
3165 case SDDS_LONGDOUBLE:
3166 *((long double *)data + i) *= factor;
3167 break;
3168 default:
3169 return (0);
3170 }
3171 }
3172 return (1);
3173}
3174
3175/**
3176 * @brief Escapes newline characters in a string by replacing them with "\\n".
3177 *
3178 * This function modifies the input string \p s in place by replacing each newline character (`'\n'`) with the two-character sequence `'\\'` and `'n'`. It shifts the subsequent characters in the string to accommodate the additional character introduced by the escape sequence.
3179 *
3180 * @param[in, out] s
3181 * Pointer to the null-terminated string to be modified.
3182 * **Important:** The buffer pointed to by \p s must have sufficient space to accommodate the additional characters resulting from the escape sequences. Failure to ensure adequate space may lead to buffer overflows.
3183 *
3184 * @warning
3185 * This function does not perform bounds checking on the buffer size. Ensure that the buffer is large enough to handle the increased length after escaping newlines.
3186 *
3187 * @sa SDDS_UnescapeNewlines
3188 */
3189void SDDS_EscapeNewlines(char *s) {
3190 char *ptr;
3191 while (*s) {
3192 if (*s == '\n') {
3193 ptr = s + strlen(s);
3194 *(ptr + 1) = 0;
3195 while (ptr != s) {
3196 *ptr = *(ptr - 1);
3197 ptr--;
3198 }
3199 *s++ = '\\';
3200 *s++ = 'n';
3201 } else
3202 s++;
3203 }
3204}
3205
3206/**
3207 * @brief Marks an SDDS dataset as inactive.
3208 *
3209 * This function forces the provided SDDS dataset to become inactive by setting its file pointer to `NULL`. An inactive dataset is typically not associated with any open file operations.
3210 *
3211 * @param[in] SDDS_dataset
3212 * Pointer to the `SDDS_DATASET` structure to be marked as inactive.
3213 *
3214 * @return
3215 * - `1` on successful operation.
3216 * - `-1` if a `NULL` pointer is passed, indicating an error.
3217 *
3218 * @note
3219 * After calling this function, the dataset will be considered inactive, and any subsequent operations that require an active dataset may fail.
3220 *
3221 * @sa SDDS_IsActive, SDDS_SetError
3222 */
3223int32_t SDDS_ForceInactive(SDDS_DATASET *SDDS_dataset) {
3224 if (!SDDS_dataset) {
3225 SDDS_SetError("NULL SDDS_DATASET passed (SDDS_ForceInactive)");
3226 return (-1);
3227 }
3228 SDDS_dataset->layout.fp = NULL;
3229 return (1);
3230}
3231
3232/**
3233 * @brief Checks whether an SDDS dataset is currently active.
3234 *
3235 * This function determines the active status of the provided SDDS dataset by verifying if its file pointer is non-`NULL`.
3236 *
3237 * @param[in] SDDS_dataset
3238 * Pointer to the `SDDS_DATASET` structure to be checked.
3239 *
3240 * @return
3241 * - `1` if the dataset is active (i.e., the file pointer is non-`NULL`).
3242 * - `0` if the dataset is inactive (i.e., the file pointer is `NULL`).
3243 * - `-1` if a `NULL` pointer is passed, indicating an error.
3244 *
3245 * @note
3246 * An inactive dataset does not have an associated open file, and certain operations may not be applicable.
3247 *
3248 * @sa SDDS_ForceInactive, SDDS_SetError
3249 */
3250int32_t SDDS_IsActive(SDDS_DATASET *SDDS_dataset) {
3251 if (!SDDS_dataset) {
3252 SDDS_SetError("NULL SDDS_DATASET passed (SDDS_IsActive)");
3253 return (-1);
3254 }
3255 if (!SDDS_dataset->layout.fp)
3256 return (0);
3257 return (1);
3258}
3259
3260/**
3261 * @brief Determines if a specified file is locked.
3262 *
3263 * This function checks whether the given file is currently locked. If file locking is enabled through the `F_TEST` and `ALLOW_FILE_LOCKING` macros, it attempts to open the file and apply a test lock using `lockf`. The function returns `1` if the file is locked and `0` otherwise.
3264 *
3265 * If file locking is not enabled (i.e., the `F_TEST` and `ALLOW_FILE_LOCKING` macros are not defined), the function always returns `0`, indicating that the file is not locked.
3266 *
3267 * @param[in] filename
3268 * The path to the file to be checked for a lock.
3269 *
3270 * @return
3271 * - `1` if the file is locked.
3272 * - `0` if the file is not locked or if file locking is not enabled.
3273 *
3274 * @note
3275 * The effectiveness of this function depends on the platform and the implementation of file locking mechanisms.
3276 *
3277 * @warning
3278 * Ensure that the `F_TEST` and `ALLOW_FILE_LOCKING` macros are appropriately defined to enable file locking functionality.
3279 *
3280 * @sa SDDS_LockFile
3281 */
3282int32_t SDDS_FileIsLocked(const char *filename) {
3283#if defined(F_TEST) && ALLOW_FILE_LOCKING
3284 FILE *fp;
3285 if (!(fp = fopen(filename, "rb")))
3286 return 0;
3287 if (lockf(fileno(fp), F_TEST, 0) == -1) {
3288 fclose(fp);
3289 return 1;
3290 }
3291 fclose(fp);
3292 return 0;
3293#else
3294 return 0;
3295#endif
3296}
3297
3298/**
3299 * @brief Attempts to lock a specified file.
3300 *
3301 * This function tries to acquire a lock on the provided file using the given file pointer. If file locking is enabled via the `F_TEST` and `ALLOW_FILE_LOCKING` macros, it first tests whether the file can be locked and then attempts to establish an exclusive lock. If locking fails at any step, an error message is set, and the function returns `0`.
3302 *
3303 * If file locking is not enabled, the function assumes that the file is not locked and returns `1`.
3304 *
3305 * @param[in] fp
3306 * Pointer to the open `FILE` stream associated with the file to be locked.
3307 *
3308 * @param[in] filename
3309 * The path to the file to be locked. Used primarily for error messaging.
3310 *
3311 * @param[in] caller
3312 * A string identifying the caller or the context in which the lock is being attempted. This is used in error messages to provide more information about the lock attempt.
3313 *
3314 * @return
3315 * - `1` if the file lock is successfully acquired or if file locking is not enabled.
3316 * - `0` if the file is already locked or if locking fails for another reason.
3317 *
3318 * @note
3319 * The function relies on the `lockf` system call for file locking, which may not be supported on all platforms.
3320 *
3321 * @warning
3322 * Proper error handling should be implemented by the caller to handle cases where file locking fails.
3323 *
3324 * @sa SDDS_FileIsLocked, SDDS_SetError
3325 */
3326int32_t SDDS_LockFile(FILE *fp, const char *filename, const char *caller) {
3327#if defined(F_TEST) && ALLOW_FILE_LOCKING
3328 char s[1024];
3329 if (lockf(fileno(fp), F_TEST, 0) == -1) {
3330 sprintf(s, "Unable to access file %s--file is locked (%s)", filename, caller);
3331 SDDS_SetError(s);
3332 return 0;
3333 }
3334 if (lockf(fileno(fp), F_TLOCK, 0) == -1) {
3335 sprintf(s, "Unable to establish lock on file %s (%s)", filename, caller);
3336 SDDS_SetError(s);
3337 return 0;
3338 }
3339 return 1;
3340#else
3341 return 1;
3342#endif
3343}
3344
3345/**
3346 * @brief Attempts to override a locked file by creating a temporary copy.
3347 *
3348 * This function tries to break into a locked file by creating a temporary backup and replacing the original file with this backup. The process involves:
3349 * - Generating a temporary filename with a `.blXXX` suffix, where `XXX` ranges from `1000` to `1019`.
3350 * - Copying the original file to the temporary file while preserving file attributes.
3351 * - Replacing the original file with the temporary copy.
3352 *
3353 * On Windows systems (`_WIN32` defined), the function currently does not support breaking into locked files and will output an error message.
3354 *
3355 * @param[in] filename
3356 * The path to the locked file that needs to be overridden.
3357 *
3358 * @return
3359 * - `0` on successful override of the locked file.
3360 * - `1` if the operation fails or is not supported on the current platform.
3361 *
3362 * @warning
3363 * - The function limits the filename length to 500 characters to prevent buffer overflows.
3364 * - Ensure that the necessary permissions are available to create and modify files in the target directory.
3365 *
3366 * @note
3367 * - This function relies on the availability of the `cp` and `mv` system commands on Unix-like systems.
3368 * - The function attempts up to 20 different temporary filenames before failing.
3369 *
3370 * @sa SDDS_FileIsLocked, SDDS_LockFile
3371 */
3372int32_t SDDS_BreakIntoLockedFile(char *filename) {
3373#if defined(_WIN32)
3374 fprintf(stderr, "Unable to break into locked file\n");
3375 return (1);
3376#else
3377 char buffer[1024];
3378 int i = 1000, j = 0;
3379 FILE *fp;
3380
3381 /* limit filename length to 500 so we don't overflow the buffer variable */
3382 if (strlen(filename) > 500) {
3383 fprintf(stderr, "Unable to break into locked file\n");
3384 return (1);
3385 }
3386
3387 /* find a temporary file name that is not already in use */
3388 for (i = 1000; i < 1020; i++) {
3389 sprintf(buffer, "%s.bl%d", filename, i);
3390 if ((fp = fopen(buffer, "r"))) {
3391 fclose(fp);
3392 } else {
3393 j = i;
3394 break;
3395 }
3396 }
3397
3398 /* if no temporary file names could be found then return with an error message */
3399 if (j == 0) {
3400 fprintf(stderr, "Unable to break into locked file\n");
3401 return (1);
3402 }
3403
3404 /* copy the original file to the temp file name and preserve the attributes */
3405 /* the temp file name has to be in the same directory to preserve ACL settings */
3406 sprintf(buffer, "cp -p %s %s.bl%d", filename, filename, j);
3407 if (system(buffer) == -1) {
3408 fprintf(stderr, "Unable to break into locked file\n");
3409 return (1);
3410 }
3411
3412 /* move the temp file on top of the original file */
3413 sprintf(buffer, "mv -f %s.bl%d %s", filename, j, filename);
3414 if (system(buffer) == -1) {
3415 fprintf(stderr, "Unable to break into locked file\n");
3416 return (1);
3417 }
3418 return (0);
3419#endif
3420}
3421
3422/**
3423 * @brief Matches and retrieves column names from an SDDS dataset based on specified criteria.
3424 *
3425 * This function selects columns from the provided SDDS dataset according to the specified matching mode and type mode. It supports various calling conventions depending on the matching criteria.
3426 *
3427 * The function supports the following matching modes:
3428 * - **SDDS_NAME_ARRAY**:
3429 * - **Parameters**: `int32_t n_entries`, `char **name`
3430 * - **Description**: Matches columns whose names are present in the provided array.
3431 *
3432 * - **SDDS_NAMES_STRING**:
3433 * - **Parameters**: `char *names`
3434 * - **Description**: Matches columns whose names are specified in a single comma-separated string.
3435 *
3436 * - **SDDS_NAME_STRINGS**:
3437 * - **Parameters**: `char *name1, char *name2, ..., NULL`
3438 * - **Description**: Matches columns whose names are specified as individual string arguments, terminated by a `NULL` pointer.
3439 *
3440 * - **SDDS_MATCH_STRING**:
3441 * - **Parameters**: `char *name`, `int32_t logic_mode`
3442 * - **Description**: Matches columns based on a wildcard pattern provided in `name`, using the specified logical mode.
3443 *
3444 * - **SDDS_MATCH_EXCLUDE_STRING**:
3445 * - **Parameters**: `char *name`, `char *exclude`, `int32_t logic_mode`
3446 * - **Description**: Matches columns based on a wildcard pattern provided in `name`, excluding those that match the `exclude` pattern, using the specified logical mode.
3447 *
3448 * Additionally, the `typeMode` parameter allows filtering based on column types, such as numeric, floating, or integer types.
3449 *
3450 * @param[in] SDDS_dataset
3451 * Pointer to the `SDDS_DATASET` structure containing the dataset.
3452 *
3453 * @param[out] nameReturn
3454 * Pointer to a `char**` that will be allocated and populated with the names of the matched columns. The caller is responsible for freeing the allocated memory.
3455 *
3456 * @param[in] matchMode
3457 * Specifies the matching mode (e.g., `SDDS_NAME_ARRAY`, `SDDS_NAMES_STRING`, etc.).
3458 *
3459 * @param[in] typeMode
3460 * Specifies the type matching mode (e.g., `FIND_SPECIFIED_TYPE`, `FIND_NUMERIC_TYPE`, `FIND_FLOATING_TYPE`, `FIND_INTEGER_TYPE`).
3461 *
3462 * @param[in] ...
3463 * Variable arguments depending on `matchMode`:
3464 * - **SDDS_NAME_ARRAY**: `int32_t n_entries`, `char **name`
3465 * - **SDDS_NAMES_STRING**: `char *names`
3466 * - **SDDS_NAME_STRINGS**: `char *name1, char *name2, ..., NULL`
3467 * - **SDDS_MATCH_STRING**: `char *name`, `int32_t logic_mode`
3468 * - **SDDS_MATCH_EXCLUDE_STRING**: `char *name`, `char *exclude`, `int32_t logic_mode`
3469 *
3470 * @return
3471 * - Returns the number of matched columns on success.
3472 * - Returns `-1` if an error occurs (e.g., invalid parameters, memory allocation failure).
3473 *
3474 * @note
3475 * - The function internally manages memory for the matching process and allocates memory for `nameReturn`, which must be freed by the caller using appropriate memory deallocation functions.
3476 * - The dataset must be properly initialized and contain a valid layout before calling this function.
3477 *
3478 * @warning
3479 * - Ensure that the variable arguments match the expected parameters for the specified `matchMode`.
3480 * - The caller is responsible for freeing the memory allocated for `nameReturn` to avoid memory leaks.
3481 *
3482 * @sa SDDS_MatchParameters, SDDS_SetError
3483 */
3484int32_t SDDS_MatchColumns(SDDS_DATASET *SDDS_dataset, char ***nameReturn, int32_t matchMode, int32_t typeMode, ...)
3485/* This routine has 5 calling modes:
3486 * SDDS_MatchColumns(&SDDS_dataset, &matchName, SDDS_NAME_ARRAY , int32_t typeMode [,int32_t type], int32_t n_entries, char **name)
3487 * SDDS_MatchColumns(&SDDS_dataset, &matchName, SDDS_NAMES_STRING, int32_t typeMode [,int32_t type], char *names)
3488 * SDDS_MatchColumns(&SDDS_dataset, &matchName, SDDS_NAME_STRINGS, int32_t typeMode [,int32_t type], char *name1, char *name2, ..., NULL )
3489 * SDDS_MatchColumns(&SDDS_dataset, &matchName, SDDS_MATCH_STRING, int32_t typeMode [,int32_t type], char *name, int32_t logic_mode)
3490 * SDDS_MatchColumns(&SDDS_dataset, &matchName, SDDS_MATCH_EXCLUDE_STRING, int32_t typeMode [,int32_t type], char *name, char *exclude, int32_t logic_mode)
3491 */
3492{
3493 static int32_t flags = 0;
3494 static int32_t *flag = NULL;
3495 char **name, *string, *match_string, *ptr, *exclude_string;
3496 va_list argptr;
3497 int32_t retval, requiredType;
3498 int32_t i, j, n_names, index, matches;
3499 int32_t local_memory; /* (0,1,2) --> (none, pointer array, pointer array + strings) locally allocated */
3500 char buffer[SDDS_MAXLINE];
3501 int32_t logic;
3502
3503 name = NULL;
3504 match_string = exclude_string = NULL;
3505 n_names = requiredType = local_memory = logic = 0;
3506
3507 matches = -1;
3508 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_MatchColumns"))
3509 return -1;
3510 if (nameReturn)
3511 *nameReturn = NULL;
3512
3513 retval = 1;
3514 va_start(argptr, typeMode);
3515 if (typeMode == FIND_SPECIFIED_TYPE)
3516 requiredType = va_arg(argptr, int32_t);
3517 switch (matchMode) {
3518 case SDDS_NAME_ARRAY:
3519 local_memory = 0;
3520 n_names = va_arg(argptr, int32_t);
3521 name = va_arg(argptr, char **);
3522 break;
3523 case SDDS_NAMES_STRING:
3524 local_memory = 2;
3525 n_names = 0;
3526 name = NULL;
3527 ptr = va_arg(argptr, char *);
3528 SDDS_CopyString(&string, ptr);
3529 while ((ptr = strchr(string, ',')))
3530 *ptr = ' ';
3531 while (SDDS_GetToken(string, buffer, SDDS_MAXLINE) > 0) {
3532 if (!(name = SDDS_Realloc(name, sizeof(*name) * (n_names + 1))) || !SDDS_CopyString(name + n_names, buffer)) {
3533 SDDS_SetError("Unable to process column selection--memory allocation failure (SDDS_MatchColumns)");
3534 retval = 0;
3535 break;
3536 }
3537 n_names++;
3538 }
3539 free(string);
3540 break;
3541 case SDDS_NAME_STRINGS:
3542 local_memory = 1;
3543 n_names = 0;
3544 name = NULL;
3545 while ((string = va_arg(argptr, char *))) {
3546 if (!(name = SDDS_Realloc(name, sizeof(*name) * (n_names + 1)))) {
3547 SDDS_SetError("Unable to process column selection--memory allocation failure (SDDS_MatchColumns)");
3548 retval = 0;
3549 break;
3550 }
3551 name[n_names++] = string;
3552 }
3553 break;
3554 case SDDS_MATCH_STRING:
3555 local_memory = 0;
3556 n_names = 1;
3557 if (!(string = va_arg(argptr, char *))) {
3558 SDDS_SetError("Unable to process column selection--invalid matching string (SDDS_MatchColumns)");
3559 retval = 0;
3560 break;
3561 }
3562 match_string = expand_ranges(string);
3563 logic = va_arg(argptr, int32_t);
3564 break;
3565 case SDDS_MATCH_EXCLUDE_STRING:
3566 local_memory = 0;
3567 n_names = 1;
3568 if (!(string = va_arg(argptr, char *))) {
3569 SDDS_SetError("Unable to process column selection--invalid matching string (SDDS_MatchColumns)");
3570 retval = 0;
3571 break;
3572 }
3573 match_string = expand_ranges(string);
3574 if (!(string = va_arg(argptr, char *))) {
3575 SDDS_SetError("Unable to process column exclusion--invalid matching string (SDDS_MatchColumns)");
3576 retval = 0;
3577 break;
3578 }
3579 exclude_string = expand_ranges(string);
3580 logic = va_arg(argptr, int32_t);
3581 break;
3582 default:
3583 SDDS_SetError("Unable to process column selection--unknown match mode (SDDS_MatchColumns)");
3584 retval = 0;
3585 break;
3586 }
3587 va_end(argptr);
3588 if (retval == 0)
3589 return -1;
3590
3591 if (n_names == 0) {
3592 SDDS_SetError("Unable to process column selection--no names in call (SDDS_MatchColumns)");
3593 return -1;
3594 }
3595
3596 if (SDDS_dataset->layout.n_columns != flags) {
3597 flags = SDDS_dataset->layout.n_columns;
3598 if (flag)
3599 free(flag);
3600 if (!(flag = (int32_t *)calloc(flags, sizeof(*flag)))) {
3601 SDDS_SetError("Memory allocation failure (SDDS_MatchColumns)");
3602 return -1;
3603 }
3604 }
3605
3606 if ((matchMode != SDDS_MATCH_STRING) && (matchMode != SDDS_MATCH_EXCLUDE_STRING)) {
3607 for (i = 0; i < n_names; i++) {
3608 if ((index = SDDS_GetColumnIndex(SDDS_dataset, name[i])) >= 0)
3609 flag[index] = 1;
3610 else
3611 flag[index] = 0;
3612 }
3613 } else {
3614 for (i = 0; i < SDDS_dataset->layout.n_columns; i++) {
3615 if (SDDS_Logic(flag[i], wild_match(SDDS_dataset->layout.column_definition[i].name, match_string), logic)) {
3616 if (exclude_string != NULL) {
3617 if (SDDS_Logic(flag[i], wild_match(SDDS_dataset->layout.column_definition[i].name, exclude_string), logic))
3618 flag[i] = 0;
3619 else
3620 flag[i] = 1;
3621 } else {
3622 flag[i] = 1;
3623 }
3624 } else {
3625#if defined(DEBUG)
3626 fprintf(stderr, "no logic match of %s to %s\n", SDDS_dataset->layout.column_definition[i].name, match_string);
3627#endif
3628 flag[i] = 0;
3629 }
3630 }
3631 }
3632 if (match_string)
3633 free(match_string);
3634 if (exclude_string)
3635 free(exclude_string);
3636#if defined(DEBUG)
3637 for (i = 0; i < SDDS_dataset->layout.n_columns; i++)
3638 fprintf(stderr, "flag[%" PRId32 "] = %" PRId32 " : %s\n", i, flag[i], SDDS_dataset->layout.column_definition[i].name);
3639#endif
3640
3641 if (local_memory == 2) {
3642 for (i = 0; i < n_names; i++)
3643 free(name[i]);
3644 }
3645 if (local_memory >= 1)
3646 free(name);
3647
3648 switch (typeMode) {
3649 case FIND_SPECIFIED_TYPE:
3650 for (i = 0; i < SDDS_dataset->layout.n_columns; i++)
3651 if (SDDS_dataset->layout.column_definition[i].type != requiredType)
3652 flag[i] = 0;
3653 break;
3654 case FIND_NUMERIC_TYPE:
3655 for (i = 0; i < SDDS_dataset->layout.n_columns; i++)
3656 if (!SDDS_NUMERIC_TYPE(SDDS_dataset->layout.column_definition[i].type))
3657 flag[i] = 0;
3658 break;
3659 case FIND_FLOATING_TYPE:
3660 for (i = 0; i < SDDS_dataset->layout.n_columns; i++)
3661 if (!SDDS_FLOATING_TYPE(SDDS_dataset->layout.column_definition[i].type))
3662 flag[i] = 0;
3663 break;
3664 case FIND_INTEGER_TYPE:
3665 for (i = 0; i < SDDS_dataset->layout.n_columns; i++)
3666 if (!SDDS_INTEGER_TYPE(SDDS_dataset->layout.column_definition[i].type))
3667 flag[i] = 0;
3668 break;
3669 default:
3670 break;
3671 }
3672#if defined(DEBUG)
3673 for (i = 0; i < SDDS_dataset->layout.n_columns; i++)
3674 if (flag[i])
3675 fprintf(stderr, "column %s matched\n", SDDS_dataset->layout.column_definition[i].name);
3676#endif
3677
3678 for (i = matches = 0; i < SDDS_dataset->layout.n_columns; i++) {
3679 if (flag[i])
3680 matches++;
3681 }
3682 if (!matches || !nameReturn)
3683 return matches;
3684 if (!((*nameReturn) = (char **)SDDS_Malloc(matches * sizeof(**nameReturn)))) {
3685 SDDS_SetError("Memory allocation failure (SDDS_MatchColumns)");
3686 return -1;
3687 }
3688 for (i = j = 0; i < SDDS_dataset->layout.n_columns; i++) {
3689 if (flag[i]) {
3690 if (!SDDS_CopyString((*nameReturn) + j, SDDS_dataset->layout.column_definition[i].name)) {
3691 SDDS_SetError("String copy failure (SDDS_MatchColumns)");
3692 return -1;
3693 }
3694 j++;
3695 }
3696 }
3697 return matches;
3698}
3699
3700/**
3701 * @brief Matches and retrieves parameter names from an SDDS dataset based on specified criteria.
3702 *
3703 * This function selects parameters from the provided SDDS dataset according to the specified matching mode and type mode. It supports various calling conventions depending on the matching criteria.
3704 *
3705 * The function supports the following matching modes:
3706 * - **SDDS_NAME_ARRAY**:
3707 * - **Parameters**: `int32_t n_entries`, `char **name`
3708 * - **Description**: Matches parameters whose names are present in the provided array.
3709 *
3710 * - **SDDS_NAMES_STRING**:
3711 * - **Parameters**: `char *names`
3712 * - **Description**: Matches parameters whose names are specified in a single comma-separated string.
3713 *
3714 * - **SDDS_NAME_STRINGS**:
3715 * - **Parameters**: `char *name1, char *name2, ..., NULL`
3716 * - **Description**: Matches parameters whose names are specified as individual string arguments, terminated by a `NULL` pointer.
3717 *
3718 * - **SDDS_MATCH_STRING**:
3719 * - **Parameters**: `char *name`, `int32_t logic_mode`
3720 * - **Description**: Matches parameters based on a wildcard pattern provided in `name`, using the specified logical mode.
3721 *
3722 * - **SDDS_MATCH_EXCLUDE_STRING**:
3723 * - **Parameters**: `char *name`, `char *exclude`, `int32_t logic_mode`
3724 * - **Description**: Matches parameters based on a wildcard pattern provided in `name`, excluding those that match the `exclude` pattern, using the specified logical mode.
3725 *
3726 * Additionally, the `typeMode` parameter allows filtering based on parameter types, such as numeric, floating, or integer types.
3727 *
3728 * @param[in] SDDS_dataset
3729 * Pointer to the `SDDS_DATASET` structure containing the dataset.
3730 *
3731 * @param[out] nameReturn
3732 * Pointer to a `char**` that will be allocated and populated with the names of the matched parameters. The caller is responsible for freeing the allocated memory.
3733 *
3734 * @param[in] matchMode
3735 * Specifies the matching mode (e.g., `SDDS_NAME_ARRAY`, `SDDS_NAMES_STRING`, etc.).
3736 *
3737 * @param[in] typeMode
3738 * Specifies the type matching mode (e.g., `FIND_SPECIFIED_TYPE`, `FIND_NUMERIC_TYPE`, `FIND_FLOATING_TYPE`, `FIND_INTEGER_TYPE`).
3739 *
3740 * @param[in] ...
3741 * Variable arguments depending on `matchMode`:
3742 * - **SDDS_NAME_ARRAY**: `int32_t n_entries`, `char **name`
3743 * - **SDDS_NAMES_STRING**: `char *names`
3744 * - **SDDS_NAME_STRINGS**: `char *name1, char *name2, ..., NULL`
3745 * - **SDDS_MATCH_STRING**: `char *name`, `int32_t logic_mode`
3746 * - **SDDS_MATCH_EXCLUDE_STRING**: `char *name`, `char *exclude`, `int32_t logic_mode`
3747 *
3748 * @return
3749 * - Returns the number of matched parameters on success.
3750 * - Returns `-1` if an error occurs (e.g., invalid parameters, memory allocation failure).
3751 *
3752 * @note
3753 * - The function internally manages memory for the matching process and allocates memory for `nameReturn`, which must be freed by the caller using appropriate memory deallocation functions.
3754 * - The dataset must be properly initialized and contain a valid layout before calling this function.
3755 *
3756 * @warning
3757 * - Ensure that the variable arguments match the expected parameters for the specified `matchMode`.
3758 * - The caller is responsible for freeing the memory allocated for `nameReturn` to avoid memory leaks.
3759 *
3760 * @sa SDDS_MatchColumns, SDDS_SetError
3761 */
3762int32_t SDDS_MatchParameters(SDDS_DATASET *SDDS_dataset, char ***nameReturn, int32_t matchMode, int32_t typeMode, ...)
3763/* This routine has 4 calling modes:
3764 * SDDS_MatchParameters(&SDDS_dataset, &matchName, SDDS_NAME_ARRAY , int32_t typeMode [,long type], int32_t n_entries, char **name)
3765 * SDDS_MatchParameters(&SDDS_dataset, &matchName, SDDS_NAMES_STRING, int32_t typeMode [,long type], char *names)
3766 * SDDS_MatchParameters(&SDDS_dataset, &matchName, SDDS_NAME_STRINGS, int32_t typeMode [,long type], char *name1, char *name2, ..., NULL )
3767 * SDDS_MatchParameters(&SDDS_dataset, &matchName, SDDS_MATCH_STRING, int32_t typeMode [,long type], char *name, int32_t logic_mode)
3768 * SDDS_MatchParameters(&SDDS_dataset, &matchName, SDDS_MATCH_EXCLUDE_STRING, int32_t typeMode [,long type], char *name, char *exclude, int32_t logic_mode)
3769 */
3770{
3771 static int32_t flags = 0, *flag = NULL;
3772 char **name, *string, *match_string, *ptr, *exclude_string;
3773 va_list argptr;
3774 int32_t i, j, index, n_names, retval, requiredType, matches;
3775 /* int32_t type; */
3776 int32_t local_memory; /* (0,1,2) --> (none, pointer array, pointer array + strings) locally allocated */
3777 char buffer[SDDS_MAXLINE];
3778 int32_t logic;
3779
3780 name = NULL;
3781 match_string = exclude_string = NULL;
3782 n_names = requiredType = local_memory = logic = 0;
3783
3784 matches = -1;
3785 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_MatchParameters"))
3786 return -1;
3787 if (nameReturn)
3788 *nameReturn = NULL;
3789
3790 retval = 1;
3791 va_start(argptr, typeMode);
3792 if (typeMode == FIND_SPECIFIED_TYPE)
3793 requiredType = va_arg(argptr, int32_t);
3794 switch (matchMode) {
3795 case SDDS_NAME_ARRAY:
3796 local_memory = 0;
3797 n_names = va_arg(argptr, int32_t);
3798 name = va_arg(argptr, char **);
3799 break;
3800 case SDDS_NAMES_STRING:
3801 local_memory = 2;
3802 n_names = 0;
3803 name = NULL;
3804 ptr = va_arg(argptr, char *);
3805 SDDS_CopyString(&string, ptr);
3806 while ((ptr = strchr(string, ',')))
3807 *ptr = ' ';
3808 while (SDDS_GetToken(string, buffer, SDDS_MAXLINE) > 0) {
3809 if (!(name = SDDS_Realloc(name, sizeof(*name) * (n_names + 1))) || !SDDS_CopyString(name + n_names, buffer)) {
3810 SDDS_SetError("Unable to process parameter selection--memory allocation failure (SDDS_MatchParameters)");
3811 retval = 0;
3812 break;
3813 }
3814 n_names++;
3815 }
3816 free(string);
3817 break;
3818 case SDDS_NAME_STRINGS:
3819 local_memory = 1;
3820 n_names = 0;
3821 name = NULL;
3822 while ((string = va_arg(argptr, char *))) {
3823 if (!(name = SDDS_Realloc(name, sizeof(*name) * (n_names + 1)))) {
3824 SDDS_SetError("Unable to process parameter selection--memory allocation failure (SDDS_MatchParameters)");
3825 retval = 0;
3826 break;
3827 }
3828 name[n_names++] = string;
3829 }
3830 break;
3831 case SDDS_MATCH_STRING:
3832 local_memory = 0;
3833 n_names = 1;
3834 if (!(string = va_arg(argptr, char *))) {
3835 SDDS_SetError("Unable to process parameter selection--invalid matching string (SDDS_MatchParameters)");
3836 retval = 0;
3837 break;
3838 }
3839 match_string = expand_ranges(string);
3840 logic = va_arg(argptr, int32_t);
3841 break;
3842 case SDDS_MATCH_EXCLUDE_STRING:
3843 local_memory = 0;
3844 n_names = 1;
3845 if (!(string = va_arg(argptr, char *))) {
3846 SDDS_SetError("Unable to process parameter selection--invalid matching string (SDDS_MatchParameters)");
3847 retval = 0;
3848 break;
3849 }
3850 match_string = expand_ranges(string);
3851 if (!(string = va_arg(argptr, char *))) {
3852 SDDS_SetError("Unable to process parameter exclusion--invalid matching string (SDDS_MatchParameters)");
3853 retval = 0;
3854 break;
3855 }
3856 exclude_string = expand_ranges(string);
3857 logic = va_arg(argptr, int32_t);
3858 break;
3859 default:
3860 SDDS_SetError("Unable to process parameter selection--unknown match mode (SDDS_MatchParameters)");
3861 retval = 0;
3862 break;
3863 }
3864 va_end(argptr);
3865 if (retval == 0)
3866 return -1;
3867
3868 if (n_names == 0) {
3869 SDDS_SetError("Unable to process parameter selection--no names in call (SDDS_MatchParameters)");
3870 return -1;
3871 }
3872
3873 if (SDDS_dataset->layout.n_parameters != flags) {
3874 flags = SDDS_dataset->layout.n_parameters;
3875 if (flag)
3876 free(flag);
3877 if (!(flag = (int32_t *)calloc(flags, sizeof(*flag)))) {
3878 SDDS_SetError("Memory allocation failure (SDDS_MatchParameters)");
3879 return -1;
3880 }
3881 }
3882
3883 if ((matchMode != SDDS_MATCH_STRING) && (matchMode != SDDS_MATCH_EXCLUDE_STRING)) {
3884 for (i = 0; i < n_names; i++) {
3885 if ((index = SDDS_GetParameterIndex(SDDS_dataset, name[i])) >= 0)
3886 flag[index] = 1;
3887 else
3888 flag[index] = 0;
3889 }
3890 } else {
3891 for (i = 0; i < SDDS_dataset->layout.n_parameters; i++) {
3892 if (SDDS_Logic(flag[i], wild_match(SDDS_dataset->layout.parameter_definition[i].name, match_string), logic)) {
3893 if (exclude_string != NULL) {
3894 if (SDDS_Logic(flag[i], wild_match(SDDS_dataset->layout.parameter_definition[i].name, exclude_string), logic))
3895 flag[i] = 0;
3896 else
3897 flag[i] = 1;
3898 } else {
3899 flag[i] = 1;
3900 }
3901 } else {
3902#if defined(DEBUG)
3903 fprintf(stderr, "no logic match of %s to %s\n", SDDS_dataset->layout.parameter_definition[i].name, match_string);
3904#endif
3905 flag[i] = 0;
3906 }
3907 }
3908 }
3909 if (match_string)
3910 free(match_string);
3911 if (exclude_string)
3912 free(exclude_string);
3913#if defined(DEBUG)
3914 for (i = 0; i < SDDS_dataset->layout.n_parameters; i++)
3915 fprintf(stderr, "flag[%" PRId32 "] = %" PRId32 " : %s\n", i, flag[i], SDDS_dataset->layout.parameter_definition[i].name);
3916#endif
3917
3918 if (local_memory == 2) {
3919 for (i = 0; i < n_names; i++)
3920 free(name[i]);
3921 }
3922 if (local_memory >= 1)
3923 free(name);
3924
3925 switch (typeMode) {
3926 case FIND_SPECIFIED_TYPE:
3927 for (i = 0; i < SDDS_dataset->layout.n_parameters; i++)
3928 if (SDDS_dataset->layout.parameter_definition[i].type != requiredType)
3929 flag[i] = 0;
3930 break;
3931 case FIND_NUMERIC_TYPE:
3932 for (i = 0; i < SDDS_dataset->layout.n_parameters; i++)
3933 if (!SDDS_NUMERIC_TYPE(SDDS_dataset->layout.parameter_definition[i].type))
3934 flag[i] = 0;
3935 break;
3936 case FIND_FLOATING_TYPE:
3937 for (i = 0; i < SDDS_dataset->layout.n_parameters; i++)
3938 if (!SDDS_FLOATING_TYPE(SDDS_dataset->layout.parameter_definition[i].type))
3939 flag[i] = 0;
3940 break;
3941 case FIND_INTEGER_TYPE:
3942 for (i = 0; i < SDDS_dataset->layout.n_parameters; i++)
3943 if (!SDDS_INTEGER_TYPE(SDDS_dataset->layout.parameter_definition[i].type))
3944 flag[i] = 0;
3945 break;
3946 default:
3947 break;
3948 }
3949#if defined(DEBUG)
3950 for (i = 0; i < SDDS_dataset->layout.n_parameters; i++)
3951 if (flag[i])
3952 fprintf(stderr, "parameter %s matched\n", SDDS_dataset->layout.parameter_definition[i].name);
3953#endif
3954
3955 for (i = matches = 0; i < SDDS_dataset->layout.n_parameters; i++) {
3956 if (flag[i])
3957 matches++;
3958 }
3959 if (!matches || !nameReturn)
3960 return matches;
3961 if (!((*nameReturn) = (char **)SDDS_Malloc(matches * sizeof(**nameReturn)))) {
3962 SDDS_SetError("Memory allocation failure (SDDS_MatchParameters)");
3963 return -1;
3964 }
3965 for (i = j = 0; i < SDDS_dataset->layout.n_parameters; i++) {
3966 if (flag[i]) {
3967 if (!SDDS_CopyString((*nameReturn) + j, SDDS_dataset->layout.parameter_definition[i].name)) {
3968 SDDS_SetError("String copy failure (SDDS_MatchParameters)");
3969 return -1;
3970 }
3971 j++;
3972 }
3973 }
3974
3975 return matches;
3976}
3977
3978/**
3979 * @brief Matches and retrieves array names from an SDDS dataset based on specified criteria.
3980 *
3981 * This function selects arrays from the provided SDDS dataset according to the specified matching mode and type mode. It supports various calling conventions depending on the matching criteria.
3982 *
3983 * The function supports the following matching modes:
3984 * - **SDDS_NAME_ARRAY**:
3985 * - **Parameters**: `int32_t n_entries`, `char **name`
3986 * - **Description**: Matches arrays whose names are present in the provided array.
3987 *
3988 * - **SDDS_NAMES_STRING**:
3989 * - **Parameters**: `char *names`
3990 * - **Description**: Matches arrays whose names are specified in a single comma-separated string.
3991 *
3992 * - **SDDS_NAME_STRINGS**:
3993 * - **Parameters**: `char *name1, char *name2, ..., NULL`
3994 * - **Description**: Matches arrays whose names are specified as individual string arguments, terminated by a `NULL` pointer.
3995 *
3996 * - **SDDS_MATCH_STRING**:
3997 * - **Parameters**: `char *name`, `int32_t logic_mode`
3998 * - **Description**: Matches arrays based on a wildcard pattern provided in `name`, using the specified logical mode.
3999 *
4000 * - **SDDS_MATCH_EXCLUDE_STRING**:
4001 * - **Parameters**: `char *name`, `char *exclude`, `int32_t logic_mode`
4002 * - **Description**: Matches arrays based on a wildcard pattern provided in `name`, excluding those that match the `exclude` pattern, using the specified logical mode.
4003 *
4004 * Additionally, the `typeMode` parameter allows filtering based on array types, such as numeric, floating, or integer types.
4005 *
4006 * @param[in] SDDS_dataset
4007 * Pointer to the `SDDS_DATASET` structure containing the dataset.
4008 *
4009 * @param[out] nameReturn
4010 * Pointer to a `char**` that will be allocated and populated with the names of the matched arrays. The caller is responsible for freeing the allocated memory.
4011 *
4012 * @param[in] matchMode
4013 * Specifies the matching mode (e.g., `SDDS_NAME_ARRAY`, `SDDS_NAMES_STRING`, etc.).
4014 *
4015 * @param[in] typeMode
4016 * Specifies the type matching mode (e.g., `FIND_SPECIFIED_TYPE`, `FIND_NUMERIC_TYPE`, `FIND_FLOATING_TYPE`, `FIND_INTEGER_TYPE`).
4017 *
4018 * @param[in] ...
4019 * Variable arguments depending on `matchMode`:
4020 * - **SDDS_NAME_ARRAY**: `int32_t n_entries`, `char **name`
4021 * - **SDDS_NAMES_STRING**: `char *names`
4022 * - **SDDS_NAME_STRINGS**: `char *name1, char *name2, ..., NULL`
4023 * - **SDDS_MATCH_STRING**: `char *name`, `int32_t logic_mode`
4024 * - **SDDS_MATCH_EXCLUDE_STRING**: `char *name`, `char *exclude`, `int32_t logic_mode`
4025 *
4026 * @return
4027 * - Returns the number of matched arrays on success.
4028 * - Returns `-1` if an error occurs (e.g., invalid parameters, memory allocation failure).
4029 *
4030 * @note
4031 * - The function internally manages memory for the matching process and allocates memory for `nameReturn`, which must be freed by the caller using appropriate memory deallocation functions.
4032 * - The dataset must be properly initialized and contain a valid layout before calling this function.
4033 *
4034 * @warning
4035 * - Ensure that the variable arguments match the expected parameters for the specified `matchMode`.
4036 * - The caller is responsible for freeing the memory allocated for `nameReturn` to avoid memory leaks.
4037 *
4038 * @sa SDDS_MatchColumns, SDDS_MatchParameters, SDDS_SetError
4039 */
4040int32_t SDDS_MatchArrays(SDDS_DATASET *SDDS_dataset, char ***nameReturn, int32_t matchMode, int32_t typeMode, ...)
4041/* This routine has 4 calling modes:
4042 * SDDS_MatchArrays(&SDDS_dataset, &matchName, SDDS_NAME_ARRAY , int32_t typeMode [,long type], int32_t n_entries, char **name)
4043 * SDDS_MatchArrays(&SDDS_dataset, &matchName, SDDS_NAMES_STRING, int32_t typeMode [,long type], char *names)
4044 * SDDS_MatchArrays(&SDDS_dataset, &matchName, SDDS_NAME_STRINGS, int32_t typeMode [,long type], char *name1, char *name2, ..., NULL )
4045 * SDDS_MatchArrays(&SDDS_dataset, &matchName, SDDS_MATCH_STRING, int32_t typeMode [,long type], char *name, int32_t logic_mode)
4046 * SDDS_MatchArrays(&SDDS_dataset, &matchName, SDDS_MATCH_EXCLUDE_STRING, int32_t typeMode [,long type], char *name, char *exclude, int32_t logic_mode)
4047 */
4048{
4049 static int32_t flags = 0, *flag = NULL;
4050 char **name, *string, *match_string, *ptr, *exclude_string;
4051 va_list argptr;
4052 int32_t i, j, index, n_names, retval, requiredType, matches;
4053 /* int32_t type; */
4054 int32_t local_memory; /* (0,1,2) --> (none, pointer array, pointer array + strings) locally allocated */
4055 char buffer[SDDS_MAXLINE];
4056 int32_t logic;
4057
4058 name = NULL;
4059 match_string = exclude_string = NULL;
4060 n_names = requiredType = local_memory = logic = 0;
4061
4062 matches = -1;
4063 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_MatchArrays"))
4064 return -1;
4065 if (nameReturn)
4066 *nameReturn = NULL;
4067
4068 retval = 1;
4069 va_start(argptr, typeMode);
4070 if (typeMode == FIND_SPECIFIED_TYPE)
4071 requiredType = va_arg(argptr, int32_t);
4072 switch (matchMode) {
4073 case SDDS_NAME_ARRAY:
4074 local_memory = 0;
4075 n_names = va_arg(argptr, int32_t);
4076 name = va_arg(argptr, char **);
4077 break;
4078 case SDDS_NAMES_STRING:
4079 local_memory = 2;
4080 n_names = 0;
4081 name = NULL;
4082 ptr = va_arg(argptr, char *);
4083 SDDS_CopyString(&string, ptr);
4084 while ((ptr = strchr(string, ',')))
4085 *ptr = ' ';
4086 while ((SDDS_GetToken(string, buffer, SDDS_MAXLINE) > 0)) {
4087 if (!(name = SDDS_Realloc(name, sizeof(*name) * (n_names + 1))) || !SDDS_CopyString(name + n_names, buffer)) {
4088 SDDS_SetError("Unable to process array selection--memory allocation failure (SDDS_MatchArrays)");
4089 retval = 0;
4090 break;
4091 }
4092 n_names++;
4093 }
4094 free(string);
4095 break;
4096 case SDDS_NAME_STRINGS:
4097 local_memory = 1;
4098 n_names = 0;
4099 name = NULL;
4100 while ((string = va_arg(argptr, char *))) {
4101 if (!(name = SDDS_Realloc(name, sizeof(*name) * (n_names + 1)))) {
4102 SDDS_SetError("Unable to process array selection--memory allocation failure (SDDS_MatchArrays)");
4103 retval = 0;
4104 break;
4105 }
4106 name[n_names++] = string;
4107 }
4108 break;
4109 case SDDS_MATCH_STRING:
4110 local_memory = 0;
4111 n_names = 1;
4112 if (!(string = va_arg(argptr, char *))) {
4113 SDDS_SetError("Unable to process array selection--invalid matching string (SDDS_MatchArrays)");
4114 retval = 0;
4115 break;
4116 }
4117 match_string = expand_ranges(string);
4118 logic = va_arg(argptr, int32_t);
4119 break;
4120 case SDDS_MATCH_EXCLUDE_STRING:
4121 local_memory = 0;
4122 n_names = 1;
4123 if (!(string = va_arg(argptr, char *))) {
4124 SDDS_SetError("Unable to process array selection--invalid matching string (SDDS_MatchArrays)");
4125 retval = 0;
4126 break;
4127 }
4128 match_string = expand_ranges(string);
4129 if (!(string = va_arg(argptr, char *))) {
4130 SDDS_SetError("Unable to process array exclusion--invalid matching string (SDDS_MatchArrays)");
4131 retval = 0;
4132 break;
4133 }
4134 exclude_string = expand_ranges(string);
4135 logic = va_arg(argptr, int32_t);
4136 break;
4137 default:
4138 SDDS_SetError("Unable to process array selection--unknown match mode (SDDS_MatchArrays)");
4139 retval = 0;
4140 break;
4141 }
4142 va_end(argptr);
4143 if (retval == 0)
4144 return -1;
4145
4146 if (n_names == 0) {
4147 SDDS_SetError("Unable to process array selection--no names in call (SDDS_MatchArrays)");
4148 return -1;
4149 }
4150
4151 if (SDDS_dataset->layout.n_arrays != flags) {
4152 flags = SDDS_dataset->layout.n_arrays;
4153 if (flag)
4154 free(flag);
4155 if (!(flag = (int32_t *)calloc(flags, sizeof(*flag)))) {
4156 SDDS_SetError("Memory allocation failure (SDDS_MatchArrays)");
4157 return -1;
4158 }
4159 }
4160
4161 if ((matchMode != SDDS_MATCH_STRING) && (matchMode != SDDS_MATCH_EXCLUDE_STRING)) {
4162 for (i = 0; i < n_names; i++) {
4163 if ((index = SDDS_GetArrayIndex(SDDS_dataset, name[i])) >= 0)
4164 flag[index] = 1;
4165 else
4166 flag[index] = 0;
4167 }
4168 } else {
4169 for (i = 0; i < SDDS_dataset->layout.n_arrays; i++) {
4170 if (SDDS_Logic(flag[i], wild_match(SDDS_dataset->layout.array_definition[i].name, match_string), logic)) {
4171 if (exclude_string != NULL) {
4172 if (SDDS_Logic(flag[i], wild_match(SDDS_dataset->layout.array_definition[i].name, exclude_string), logic))
4173 flag[i] = 0;
4174 else
4175 flag[i] = 1;
4176 } else {
4177 flag[i] = 1;
4178 }
4179 } else {
4180#if defined(DEBUG)
4181 fprintf(stderr, "no logic match of %s to %s\n", SDDS_dataset->layout.array_definition[i].name, match_string);
4182#endif
4183 flag[i] = 0;
4184 }
4185 }
4186 }
4187 if (match_string)
4188 free(match_string);
4189 if (exclude_string)
4190 free(exclude_string);
4191#if defined(DEBUG)
4192 for (i = 0; i < SDDS_dataset->layout.n_arrays; i++)
4193 fprintf(stderr, "flag[%" PRId32 "] = %" PRId32 " : %s\n", i, flag[i], SDDS_dataset->layout.array_definition[i].name);
4194#endif
4195
4196 if (local_memory == 2) {
4197 for (i = 0; i < n_names; i++)
4198 free(name[i]);
4199 }
4200 if (local_memory >= 1)
4201 free(name);
4202
4203 switch (typeMode) {
4204 case FIND_SPECIFIED_TYPE:
4205 for (i = 0; i < SDDS_dataset->layout.n_arrays; i++)
4206 if (SDDS_dataset->layout.array_definition[i].type != requiredType)
4207 flag[i] = 0;
4208 break;
4209 case FIND_NUMERIC_TYPE:
4210 for (i = 0; i < SDDS_dataset->layout.n_arrays; i++)
4211 if (!SDDS_NUMERIC_TYPE(SDDS_dataset->layout.array_definition[i].type))
4212 flag[i] = 0;
4213 break;
4214 case FIND_FLOATING_TYPE:
4215 for (i = 0; i < SDDS_dataset->layout.n_arrays; i++)
4216 if (!SDDS_FLOATING_TYPE(SDDS_dataset->layout.array_definition[i].type))
4217 flag[i] = 0;
4218 break;
4219 case FIND_INTEGER_TYPE:
4220 for (i = 0; i < SDDS_dataset->layout.n_arrays; i++)
4221 if (!SDDS_INTEGER_TYPE(SDDS_dataset->layout.array_definition[i].type))
4222 flag[i] = 0;
4223 break;
4224 default:
4225 break;
4226 }
4227#if defined(DEBUG)
4228 for (i = 0; i < SDDS_dataset->layout.n_arrays; i++)
4229 if (flag[i])
4230 fprintf(stderr, "array %s matched\n", SDDS_dataset->layout.array_definition[i].name);
4231#endif
4232
4233 for (i = matches = 0; i < SDDS_dataset->layout.n_arrays; i++) {
4234 if (flag[i])
4235 matches++;
4236 }
4237 if (!matches || !nameReturn)
4238 return matches;
4239 if (!((*nameReturn) = (char **)SDDS_Malloc(matches * sizeof(**nameReturn)))) {
4240 SDDS_SetError("Memory allocation failure (SDDS_MatchArrays)");
4241 return -1;
4242 }
4243 for (i = j = 0; i < SDDS_dataset->layout.n_arrays; i++) {
4244 if (flag[i]) {
4245 if (!SDDS_CopyString((*nameReturn) + j, SDDS_dataset->layout.array_definition[i].name)) {
4246 SDDS_SetError("String copy failure (SDDS_MatchArrays)");
4247 return -1;
4248 }
4249 j++;
4250 }
4251 }
4252
4253 return matches;
4254}
4255
4256/**
4257 * @brief Finds the first column in the SDDS dataset that matches the specified criteria.
4258 *
4259 * This function searches through the columns of the provided SDDS dataset and returns the name of the first column that matches the given criteria based on the specified mode.
4260 *
4261 * The function supports the following modes:
4262 * - **FIND_SPECIFIED_TYPE**:
4263 * - **Parameters**: `int32_t type`, `char *name1, char *name2, ..., NULL`
4264 * - **Description**: Finds the first column with a specified type among the provided column names.
4265 *
4266 * - **FIND_ANY_TYPE**:
4267 * - **Parameters**: `char *name1, char *name2, ..., NULL`
4268 * - **Description**: Finds the first column with any type among the provided column names.
4269 *
4270 * - **FIND_NUMERIC_TYPE**:
4271 * - **Parameters**: `char *name1, char *name2, ..., NULL`
4272 * - **Description**: Finds the first column with a numeric type among the provided column names.
4273 *
4274 * - **FIND_FLOATING_TYPE**:
4275 * - **Parameters**: `char *name1, char *name2, ..., NULL`
4276 * - **Description**: Finds the first column with a floating type among the provided column names.
4277 *
4278 * - **FIND_INTEGER_TYPE**:
4279 * - **Parameters**: `char *name1, char *name2, ..., NULL`
4280 * - **Description**: Finds the first column with an integer type among the provided column names.
4281 *
4282 * @param[in] SDDS_dataset
4283 * Pointer to the `SDDS_DATASET` structure containing the dataset.
4284 *
4285 * @param[in] mode
4286 * Specifies the mode for matching columns. Valid modes are:
4287 * - `FIND_SPECIFIED_TYPE`
4288 * - `FIND_ANY_TYPE`
4289 * - `FIND_NUMERIC_TYPE`
4290 * - `FIND_FLOATING_TYPE`
4291 * - `FIND_INTEGER_TYPE`
4292 *
4293 * @param[in] ...
4294 * Variable arguments depending on `mode`:
4295 * - **FIND_SPECIFIED_TYPE**: `int32_t type`, followed by a list of column names (`char *name1, char *name2, ..., NULL`)
4296 * - **Other Modes**: A list of column names (`char *name1, char *name2, ..., NULL`)
4297 *
4298 * @return
4299 * - On success, returns a dynamically allocated string containing the name of the first matched column.
4300 * - Returns `NULL` if no matching column is found or if an error occurs (e.g., memory allocation failure).
4301 *
4302 * @note
4303 * - The caller is responsible for freeing the memory allocated for the returned string using `free()` or an appropriate memory deallocation function.
4304 * - Ensure that the SDDS dataset is properly initialized and contains columns before calling this function.
4305 *
4306 * @warning
4307 * - Ensure that the variable arguments match the expected parameters for the specified `mode`.
4308 * - Failure to free the returned string may lead to memory leaks.
4309 *
4310 * @sa SDDS_FindParameter, SDDS_FindArray, SDDS_MatchColumns, SDDS_SetError
4311 */
4312char *SDDS_FindColumn(SDDS_DATASET *SDDS_dataset, int32_t mode, ...) {
4313 /*
4314 SDDS_DATASET *SDDS_dataset, FIND_SPECIFIED_TYPE, int32_t type, char*, ..., NULL)
4315 SDDS_DATASET *SDDS_dataset, FIND_ANY_TYPE, char*, ..., NULL)
4316 */
4317 int32_t index;
4318 int32_t error, type, thisType;
4319 va_list argptr;
4320 char *name, *buffer;
4321
4322 va_start(argptr, mode);
4323 buffer = NULL;
4324 error = type = 0;
4325
4326 if (mode == FIND_SPECIFIED_TYPE)
4327 type = va_arg(argptr, int32_t);
4328 while ((name = va_arg(argptr, char *))) {
4329 if ((index = SDDS_GetColumnIndex(SDDS_dataset, name)) >= 0) {
4330 thisType = SDDS_GetColumnType(SDDS_dataset, index);
4331 if (mode == FIND_ANY_TYPE || (mode == FIND_SPECIFIED_TYPE && thisType == type) || (mode == FIND_NUMERIC_TYPE && SDDS_NUMERIC_TYPE(thisType)) || (mode == FIND_FLOATING_TYPE && SDDS_FLOATING_TYPE(thisType)) || (mode == FIND_INTEGER_TYPE && SDDS_INTEGER_TYPE(thisType))) {
4332 if (!SDDS_CopyString(&buffer, name)) {
4333 SDDS_SetError("unable to return string from SDDS_FindColumn");
4334 error = 1;
4335 break;
4336 }
4337 error = 0;
4338 break;
4339 }
4340 }
4341 }
4342 va_end(argptr);
4343 if (error)
4344 return NULL;
4345 return buffer;
4346}
4347
4348/**
4349 * @brief Finds the first parameter in the SDDS dataset that matches the specified criteria.
4350 *
4351 * This function searches through the parameters of the provided SDDS dataset and returns the name of the first parameter that matches the given criteria based on the specified mode.
4352 *
4353 * The function supports the following modes:
4354 * - **FIND_SPECIFIED_TYPE**:
4355 * - **Parameters**: `int32_t type`, `char *name1, char *name2, ..., NULL`
4356 * - **Description**: Finds the first parameter with a specified type among the provided parameter names.
4357 *
4358 * - **FIND_ANY_TYPE**:
4359 * - **Parameters**: `char *name1, char *name2, ..., NULL`
4360 * - **Description**: Finds the first parameter with any type among the provided parameter names.
4361 *
4362 * - **FIND_NUMERIC_TYPE**:
4363 * - **Parameters**: `char *name1, char *name2, ..., NULL`
4364 * - **Description**: Finds the first parameter with a numeric type among the provided parameter names.
4365 *
4366 * - **FIND_FLOATING_TYPE**:
4367 * - **Parameters**: `char *name1, char *name2, ..., NULL`
4368 * - **Description**: Finds the first parameter with a floating type among the provided parameter names.
4369 *
4370 * - **FIND_INTEGER_TYPE**:
4371 * - **Parameters**: `char *name1, char *name2, ..., NULL`
4372 * - **Description**: Finds the first parameter with an integer type among the provided parameter names.
4373 *
4374 * @param[in] SDDS_dataset
4375 * Pointer to the `SDDS_DATASET` structure containing the dataset.
4376 *
4377 * @param[in] mode
4378 * Specifies the mode for matching parameters. Valid modes are:
4379 * - `FIND_SPECIFIED_TYPE`
4380 * - `FIND_ANY_TYPE`
4381 * - `FIND_NUMERIC_TYPE`
4382 * - `FIND_FLOATING_TYPE`
4383 * - `FIND_INTEGER_TYPE`
4384 *
4385 * @param[in] ...
4386 * Variable arguments depending on `mode`:
4387 * - **FIND_SPECIFIED_TYPE**: `int32_t type`, followed by a list of parameter names (`char *name1, char *name2, ..., NULL`)
4388 * - **Other Modes**: A list of parameter names (`char *name1, char *name2, ..., NULL`)
4389 *
4390 * @return
4391 * - On success, returns a dynamically allocated string containing the name of the first matched parameter.
4392 * - Returns `NULL` if no matching parameter is found or if an error occurs (e.g., memory allocation failure).
4393 *
4394 * @note
4395 * - The caller is responsible for freeing the memory allocated for the returned string using `free()` or an appropriate memory deallocation function.
4396 * - Ensure that the SDDS dataset is properly initialized and contains parameters before calling this function.
4397 *
4398 * @warning
4399 * - Ensure that the variable arguments match the expected parameters for the specified `mode`.
4400 * - Failure to free the returned string may lead to memory leaks.
4401 *
4402 * @sa SDDS_FindColumn, SDDS_FindArray, SDDS_MatchParameters, SDDS_SetError
4403 */
4404char *SDDS_FindParameter(SDDS_DATASET *SDDS_dataset, int32_t mode, ...) {
4405 int32_t index, error, type, thisType;
4406 va_list argptr;
4407 char *name, *buffer;
4408
4409 va_start(argptr, mode);
4410 buffer = NULL;
4411 error = type = 0;
4412
4413 if (mode == FIND_SPECIFIED_TYPE)
4414 type = va_arg(argptr, int32_t);
4415 while ((name = va_arg(argptr, char *))) {
4416 if ((index = SDDS_GetParameterIndex(SDDS_dataset, name)) >= 0) {
4417 thisType = SDDS_GetParameterType(SDDS_dataset, index);
4418 if (mode == FIND_ANY_TYPE || (mode == FIND_SPECIFIED_TYPE && thisType == type) || (mode == FIND_NUMERIC_TYPE && SDDS_NUMERIC_TYPE(thisType)) || (mode == FIND_FLOATING_TYPE && SDDS_FLOATING_TYPE(thisType)) || (mode == FIND_INTEGER_TYPE && SDDS_INTEGER_TYPE(thisType))) {
4419 if (!SDDS_CopyString(&buffer, name)) {
4420 SDDS_SetError("unable to return string from SDDS_FindParameter");
4421 error = 1;
4422 break;
4423 }
4424 error = 0;
4425 break;
4426 }
4427 }
4428 }
4429 va_end(argptr);
4430 if (error)
4431 return NULL;
4432 return buffer;
4433}
4434
4435/**
4436 * @brief Finds the first array in the SDDS dataset that matches the specified criteria.
4437 *
4438 * This function searches through the arrays of the provided SDDS dataset and returns the name of the first array that matches the given criteria based on the specified mode.
4439 *
4440 * The function supports the following modes:
4441 * - **FIND_SPECIFIED_TYPE**:
4442 * - **Parameters**: `int32_t type`, `char *name1, char *name2, ..., NULL`
4443 * - **Description**: Finds the first array with a specified type among the provided array names.
4444 *
4445 * - **FIND_ANY_TYPE**:
4446 * - **Parameters**: `char *name1, char *name2, ..., NULL`
4447 * - **Description**: Finds the first array with any type among the provided array names.
4448 *
4449 * - **FIND_NUMERIC_TYPE**:
4450 * - **Parameters**: `char *name1, char *name2, ..., NULL`
4451 * - **Description**: Finds the first array with a numeric type among the provided array names.
4452 *
4453 * - **FIND_FLOATING_TYPE**:
4454 * - **Parameters**: `char *name1, char *name2, ..., NULL`
4455 * - **Description**: Finds the first array with a floating type among the provided array names.
4456 *
4457 * - **FIND_INTEGER_TYPE**:
4458 * - **Parameters**: `char *name1, char *name2, ..., NULL`
4459 * - **Description**: Finds the first array with an integer type among the provided array names.
4460 *
4461 * @param[in] SDDS_dataset
4462 * Pointer to the `SDDS_DATASET` structure containing the dataset.
4463 *
4464 * @param[in] mode
4465 * Specifies the mode for matching arrays. Valid modes are:
4466 * - `FIND_SPECIFIED_TYPE`
4467 * - `FIND_ANY_TYPE`
4468 * - `FIND_NUMERIC_TYPE`
4469 * - `FIND_FLOATING_TYPE`
4470 * - `FIND_INTEGER_TYPE`
4471 *
4472 * @param[in] ...
4473 * Variable arguments depending on `mode`:
4474 * - **FIND_SPECIFIED_TYPE**: `int32_t type`, followed by a list of array names (`char *name1, char *name2, ..., NULL`)
4475 * - **Other Modes**: A list of array names (`char *name1, char *name2, ..., NULL`)
4476 *
4477 * @return
4478 * - On success, returns a dynamically allocated string containing the name of the first matched array.
4479 * - Returns `NULL` if no matching array is found or if an error occurs (e.g., memory allocation failure).
4480 *
4481 * @note
4482 * - The caller is responsible for freeing the memory allocated for the returned string using `free()` or an appropriate memory deallocation function.
4483 * - Ensure that the SDDS dataset is properly initialized and contains arrays before calling this function.
4484 *
4485 * @warning
4486 * - Ensure that the variable arguments match the expected parameters for the specified `mode`.
4487 * - Failure to free the returned string may lead to memory leaks.
4488 *
4489 * @sa SDDS_FindColumn, SDDS_FindParameter, SDDS_MatchArrays, SDDS_SetError
4490 */
4491char *SDDS_FindArray(SDDS_DATASET *SDDS_dataset, int32_t mode, ...) {
4492 int32_t index, error, type, thisType;
4493 va_list argptr;
4494 char *name, *buffer;
4495
4496 va_start(argptr, mode);
4497 buffer = NULL;
4498 error = type = 0;
4499
4500 if (mode == FIND_SPECIFIED_TYPE)
4501 type = va_arg(argptr, int32_t);
4502 while ((name = va_arg(argptr, char *))) {
4503 if ((index = SDDS_GetArrayIndex(SDDS_dataset, name)) >= 0) {
4504 thisType = SDDS_GetArrayType(SDDS_dataset, index);
4505 if (mode == FIND_ANY_TYPE || (mode == FIND_SPECIFIED_TYPE && thisType == type) || (mode == FIND_NUMERIC_TYPE && SDDS_NUMERIC_TYPE(thisType)) || (mode == FIND_FLOATING_TYPE && SDDS_FLOATING_TYPE(thisType)) || (mode == FIND_INTEGER_TYPE && SDDS_INTEGER_TYPE(thisType))) {
4506 if (!SDDS_CopyString(&buffer, name)) {
4507 SDDS_SetError("unable to return string from SDDS_FindArray");
4508 error = 1;
4509 break;
4510 }
4511 error = 0;
4512 break;
4513 }
4514 }
4515 }
4516 va_end(argptr);
4517 if (error)
4518 return NULL;
4519 return buffer;
4520}
4521
4522/**
4523 * @brief Checks if a column exists in the SDDS dataset with the specified name, units, and type.
4524 *
4525 * This function verifies whether a column with the given name exists in the SDDS dataset and optionally checks if its units and type match the specified criteria.
4526 *
4527 * @param[in] SDDS_dataset
4528 * Pointer to the `SDDS_DATASET` structure representing the dataset to be checked.
4529 *
4530 * @param[in] name
4531 * The name of the column to check.
4532 *
4533 * @param[in] units
4534 * The units of the column. May be `NULL` if units are not to be checked.
4535 *
4536 * @param[in] type
4537 * Specifies the expected type of the column. Valid values are:
4538 * - `SDDS_ANY_NUMERIC_TYPE`
4539 * - `SDDS_ANY_FLOATING_TYPE`
4540 * - `SDDS_ANY_INTEGER_TYPE`
4541 * - `0` (if type is to be ignored)
4542 *
4543 * @param[in] fp_message
4544 * File pointer where error messages will be sent. Typically, this is `stderr`.
4545 *
4546 * @return
4547 * - `SDDS_CHECK_OKAY` if the column exists and matches the specified criteria.
4548 * - `SDDS_CHECK_NONEXISTENT` if the column does not exist.
4549 * - `SDDS_CHECK_WRONGTYPE` if the column exists but does not match the specified type.
4550 * - `SDDS_CHECK_WRONGUNITS` if the column exists but does not match the specified units.
4551 *
4552 * @note
4553 * - If `units` is `NULL`, the function does not check for units.
4554 * - The function retrieves the column's units and type using `SDDS_GetColumnInformation` and `SDDS_GetColumnType`.
4555 *
4556 * @warning
4557 * - Ensure that the SDDS dataset is properly initialized and contains columns before calling this function.
4558 * - The function may set error messages using `SDDS_SetError` if it encounters issues accessing column information.
4559 *
4560 * @sa SDDS_CheckParameter, SDDS_GetColumnIndex, SDDS_SetError
4561 */
4562int32_t SDDS_CheckColumn(SDDS_DATASET *SDDS_dataset, char *name, char *units, int32_t type, FILE *fp_message) {
4563 char *units1;
4564 int32_t index;
4565 if ((index = SDDS_GetColumnIndex(SDDS_dataset, name)) < 0)
4566 return (SDDS_PrintCheckText(fp_message, name, units, type, "column", SDDS_CHECK_NONEXISTENT));
4567 if (SDDS_VALID_TYPE(type)) {
4568 if (type != SDDS_GetColumnType(SDDS_dataset, index))
4569 return (SDDS_PrintCheckText(fp_message, name, units, type, "column", SDDS_CHECK_WRONGTYPE));
4570 } else {
4571 switch (type) {
4572 case 0:
4573 break;
4575 if (!SDDS_NUMERIC_TYPE(SDDS_GetColumnType(SDDS_dataset, index)))
4576 return (SDDS_PrintCheckText(fp_message, name, units, type, "column", SDDS_CHECK_WRONGTYPE));
4577 break;
4579 if (!SDDS_FLOATING_TYPE(SDDS_GetColumnType(SDDS_dataset, index))) {
4580 return (SDDS_PrintCheckText(fp_message, name, units, type, "column", SDDS_CHECK_WRONGTYPE));
4581 }
4582 break;
4584 if (!SDDS_INTEGER_TYPE(SDDS_GetColumnType(SDDS_dataset, index))) {
4585 return (SDDS_PrintCheckText(fp_message, name, units, type, "column", SDDS_CHECK_WRONGTYPE));
4586 }
4587 break;
4588 default:
4589 return (SDDS_PrintCheckText(fp_message, name, units, type, "column", SDDS_CHECK_WRONGTYPE));
4590 }
4591 }
4592 if (!units) {
4593 /* don't care about units */
4594 return SDDS_CHECK_OKAY;
4595 }
4596 if (SDDS_GetColumnInformation(SDDS_dataset, "units", &units1, SDDS_GET_BY_NAME, name) != SDDS_STRING) {
4597 SDDS_SetError("units field of column has wrong data type!");
4598 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
4599 }
4600 if (!units1) {
4601 if (SDDS_StringIsBlank(units))
4602 return (SDDS_CHECK_OKAY);
4603 return (SDDS_PrintCheckText(fp_message, name, units, type, "column", SDDS_CHECK_WRONGUNITS));
4604 }
4605 if (strcmp(units, units1) == 0) {
4606 free(units1);
4607 return (SDDS_CHECK_OKAY);
4608 }
4609 free(units1);
4610 return (SDDS_PrintCheckText(fp_message, name, units, type, "column", SDDS_CHECK_WRONGUNITS));
4611}
4612
4613/**
4614 * @brief Checks if a parameter exists in the SDDS dataset with the specified name, units, and type.
4615 *
4616 * This function verifies whether a parameter with the given name exists in the SDDS dataset and optionally checks if its units and type match the specified criteria.
4617 *
4618 * @param[in] SDDS_dataset
4619 * Pointer to the `SDDS_DATASET` structure representing the dataset to be checked.
4620 *
4621 * @param[in] name
4622 * The name of the parameter to check.
4623 *
4624 * @param[in] units
4625 * The units of the parameter. May be `NULL` if units are not to be checked.
4626 *
4627 * @param[in] type
4628 * Specifies the expected type of the parameter. Valid values are:
4629 * - `SDDS_ANY_NUMERIC_TYPE`
4630 * - `SDDS_ANY_FLOATING_TYPE`
4631 * - `SDDS_ANY_INTEGER_TYPE`
4632 * - `0` (if type is to be ignored)
4633 *
4634 * @param[in] fp_message
4635 * File pointer where error messages will be sent. Typically, this is `stderr`.
4636 *
4637 * @return
4638 * - `SDDS_CHECK_OKAY` if the parameter exists and matches the specified criteria.
4639 * - `SDDS_CHECK_NONEXISTENT` if the parameter does not exist.
4640 * - `SDDS_CHECK_WRONGTYPE` if the parameter exists but does not match the specified type.
4641 * - `SDDS_CHECK_WRONGUNITS` if the parameter exists but does not match the specified units.
4642 *
4643 * @note
4644 * - If `units` is `NULL`, the function does not check for units.
4645 * - The function retrieves the parameter's units and type using `SDDS_GetParameterInformation` and `SDDS_GetParameterType`.
4646 *
4647 * @warning
4648 * - Ensure that the SDDS dataset is properly initialized and contains parameters before calling this function.
4649 * - The function may set error messages using `SDDS_SetError` if it encounters issues accessing parameter information.
4650 *
4651 * @sa SDDS_CheckColumn, SDDS_GetParameterIndex, SDDS_SetError
4652 */
4653int32_t SDDS_CheckParameter(SDDS_DATASET *SDDS_dataset, char *name, char *units, int32_t type, FILE *fp_message) {
4654 char *units1;
4655 int32_t index;
4656 if ((index = SDDS_GetParameterIndex(SDDS_dataset, name)) < 0)
4657 return (SDDS_PrintCheckText(fp_message, name, units, type, "parameter", SDDS_CHECK_NONEXISTENT));
4658 if (SDDS_VALID_TYPE(type)) {
4659 if (type != SDDS_GetParameterType(SDDS_dataset, index))
4660 return (SDDS_PrintCheckText(fp_message, name, units, type, "parameter", SDDS_CHECK_WRONGTYPE));
4661 } else {
4662 switch (type) {
4663 case 0:
4664 break;
4666 if (!SDDS_NUMERIC_TYPE(SDDS_GetParameterType(SDDS_dataset, index)))
4667 return (SDDS_PrintCheckText(fp_message, name, units, type, "parameter", SDDS_CHECK_WRONGTYPE));
4668 break;
4670 if (!SDDS_FLOATING_TYPE(SDDS_GetParameterType(SDDS_dataset, index)))
4671 return (SDDS_PrintCheckText(fp_message, name, units, type, "parameter", SDDS_CHECK_WRONGTYPE));
4672 break;
4674 if (!SDDS_INTEGER_TYPE(SDDS_GetParameterType(SDDS_dataset, index)))
4675 return (SDDS_PrintCheckText(fp_message, name, units, type, "parameter", SDDS_CHECK_WRONGTYPE));
4676 break;
4677 default:
4678 return (SDDS_PrintCheckText(fp_message, name, units, type, "parameter", SDDS_CHECK_WRONGTYPE));
4679 }
4680 }
4681 if (!units) {
4682 /* don't care about units */
4683 return (SDDS_CHECK_OKAY);
4684 }
4685 if (SDDS_GetParameterInformation(SDDS_dataset, "units", &units1, SDDS_GET_BY_NAME, name) != SDDS_STRING) {
4686 SDDS_SetError("units field of parameter has wrong data type!");
4687 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
4688 }
4689 if (!units1) {
4690 if (SDDS_StringIsBlank(units))
4691 return (SDDS_CHECK_OKAY);
4692 return (SDDS_PrintCheckText(fp_message, name, units, type, "parameter", SDDS_CHECK_WRONGUNITS));
4693 }
4694 if (strcmp(units, units1) == 0) {
4695 free(units1);
4696 return (SDDS_CHECK_OKAY);
4697 }
4698 free(units1);
4699 return (SDDS_PrintCheckText(fp_message, name, units, type, "parameter", SDDS_CHECK_WRONGUNITS));
4700}
4701
4702/**
4703 * @brief Checks if an array exists in the SDDS dataset with the specified name, units, and type.
4704 *
4705 * This function verifies whether an array with the given name exists within the provided SDDS dataset. Additionally, it can check if the array's units and type match the specified criteria.
4706 *
4707 * @param[in] SDDS_dataset
4708 * Pointer to the `SDDS_DATASET` structure representing the dataset to be checked.
4709 *
4710 * @param[in] name
4711 * The name of the array to check.
4712 *
4713 * @param[in] units
4714 * The units of the array. This parameter may be `NULL` if units are not to be validated.
4715 *
4716 * @param[in] type
4717 * Specifies the expected type of the array. Valid values are:
4718 * - `SDDS_ANY_NUMERIC_TYPE`
4719 * - `SDDS_ANY_FLOATING_TYPE`
4720 * - `SDDS_ANY_INTEGER_TYPE`
4721 * - `0` (if type is to be ignored)
4722 *
4723 * @param[in] fp_message
4724 * File pointer where error messages will be sent. Typically, this is `stderr`.
4725 *
4726 * @return
4727 * - `SDDS_CHECK_OKAY` if the array exists and matches the specified criteria.
4728 * - `SDDS_CHECK_NONEXISTENT` if the array does not exist.
4729 * - `SDDS_CHECK_WRONGTYPE` if the array exists but does not match the specified type.
4730 * - `SDDS_CHECK_WRONGUNITS` if the array exists but does not match the specified units.
4731 *
4732 * @note
4733 * - If `units` is `NULL`, the function does not perform units validation.
4734 * - The function retrieves the array's units and type using `SDDS_GetArrayInformation` and `SDDS_GetArrayType`.
4735 *
4736 * @warning
4737 * - Ensure that the SDDS dataset is properly initialized and contains arrays before calling this function.
4738 * - The function may set error messages using `SDDS_SetError` if it encounters issues accessing array information.
4739 *
4740 * @sa SDDS_CheckColumn, SDDS_CheckParameter, SDDS_PrintCheckText, SDDS_SetError
4741 */
4742int32_t SDDS_CheckArray(SDDS_DATASET *SDDS_dataset, char *name, char *units, int32_t type, FILE *fp_message) {
4743 char *units1;
4744 int32_t index;
4745 if ((index = SDDS_GetArrayIndex(SDDS_dataset, name)) < 0)
4746 return (SDDS_PrintCheckText(fp_message, name, units, type, "array", SDDS_CHECK_NONEXISTENT));
4747 if (SDDS_VALID_TYPE(type)) {
4748 if (type != SDDS_GetArrayType(SDDS_dataset, index))
4749 return (SDDS_PrintCheckText(fp_message, name, units, type, "array", SDDS_CHECK_WRONGTYPE));
4750 } else {
4751 switch (type) {
4752 case 0:
4753 break;
4755 if (!SDDS_NUMERIC_TYPE(SDDS_GetArrayType(SDDS_dataset, index)))
4756 return (SDDS_PrintCheckText(fp_message, name, units, type, "array", SDDS_CHECK_WRONGTYPE));
4757 break;
4759 if (!SDDS_FLOATING_TYPE(SDDS_GetArrayType(SDDS_dataset, index)))
4760 return (SDDS_PrintCheckText(fp_message, name, units, type, "array", SDDS_CHECK_WRONGTYPE));
4761 break;
4763 if (!SDDS_INTEGER_TYPE(SDDS_GetArrayType(SDDS_dataset, index)))
4764 return (SDDS_PrintCheckText(fp_message, name, units, type, "array", SDDS_CHECK_WRONGTYPE));
4765 break;
4766 default:
4767 return (SDDS_PrintCheckText(fp_message, name, units, type, "array", SDDS_CHECK_WRONGTYPE));
4768 }
4769 }
4770 if (SDDS_GetArrayInformation(SDDS_dataset, "units", &units1, SDDS_GET_BY_NAME, name) != SDDS_STRING) {
4771 SDDS_SetError("units field of array has wrong data type!");
4772 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
4773 }
4774 if (!units) {
4775 /* don't care about units */
4776 return (SDDS_CHECK_OKAY);
4777 }
4778 if (!units1) {
4779 if (SDDS_StringIsBlank(units))
4780 return (SDDS_CHECK_OKAY);
4781 return (SDDS_CHECK_OKAY);
4782 }
4783 if (strcmp(units, units1) == 0) {
4784 free(units1);
4785 return (SDDS_CHECK_OKAY);
4786 }
4787 free(units1);
4788 return (SDDS_PrintCheckText(fp_message, name, units, type, "array", SDDS_CHECK_WRONGUNITS));
4789}
4790
4791/**
4792 * @brief Prints detailed error messages related to SDDS entity checks.
4793 *
4794 * This function outputs error messages to the specified file pointer based on the provided error code. It is primarily used by functions like `SDDS_CheckColumn`, `SDDS_CheckParameter`, and `SDDS_CheckArray` to report issues during validation checks.
4795 *
4796 * @param[in] fp
4797 * File pointer where the error messages will be printed. Typically, this is `stderr`.
4798 *
4799 * @param[in] name
4800 * The name of the SDDS entity (e.g., column, parameter, array) being checked.
4801 *
4802 * @param[in] units
4803 * The expected units of the SDDS entity. May be `NULL` if units are not relevant.
4804 *
4805 * @param[in] type
4806 * The expected type code of the SDDS entity. This can be a specific type or a general category like `SDDS_ANY_NUMERIC_TYPE`.
4807 *
4808 * @param[in] class_name
4809 * A string representing the class of the SDDS entity (e.g., "column", "parameter", "array").
4810 *
4811 * @param[in] error_code
4812 * The specific error code indicating the type of error encountered. Valid values include:
4813 * - `SDDS_CHECK_OKAY`
4814 * - `SDDS_CHECK_NONEXISTENT`
4815 * - `SDDS_CHECK_WRONGTYPE`
4816 * - `SDDS_CHECK_WRONGUNITS`
4817 *
4818 * @return
4819 * Returns the same `error_code` that was passed as an argument.
4820 *
4821 * @note
4822 * - This function assumes that `registeredProgramName` is a globally accessible string containing the name of the program for contextual error messages.
4823 * - Ensure that `fp`, `name`, and `class_name` are not `NULL` to prevent undefined behavior.
4824 *
4825 * @warning
4826 * - Passing invalid `error_code` values that are not handled in the switch statement will result in a generic error message being printed to `stderr`.
4827 *
4828 * @sa SDDS_CheckColumn, SDDS_CheckParameter, SDDS_CheckArray
4829 */
4830int32_t SDDS_PrintCheckText(FILE *fp, char *name, char *units, int32_t type, char *class_name, int32_t error_code) {
4831 if (!fp || !name || !class_name)
4832 return (error_code);
4833 switch (error_code) {
4834 case SDDS_CHECK_OKAY:
4835 break;
4836 case SDDS_CHECK_NONEXISTENT:
4837 fprintf(fp, "Problem with %s %s: nonexistent (%s)\n", class_name, name, registeredProgramName ? registeredProgramName : "?");
4838 break;
4839 case SDDS_CHECK_WRONGTYPE:
4840 if (SDDS_VALID_TYPE(type))
4841 fprintf(fp, "Problem with %s %s: wrong data type--expected %s (%s)\n", class_name, name, SDDS_type_name[type - 1], registeredProgramName ? registeredProgramName : "?");
4842 else if (type == SDDS_ANY_NUMERIC_TYPE)
4843 fprintf(fp, "Problem with %s %s: wrong data type--expected numeric data (%s)\n", class_name, name, registeredProgramName ? registeredProgramName : "?");
4844 else if (type == SDDS_ANY_FLOATING_TYPE)
4845 fprintf(fp, "Problem with %s %s: wrong data type--expected floating point data (%s)\n", class_name, name, registeredProgramName ? registeredProgramName : "?");
4846 else if (type == SDDS_ANY_INTEGER_TYPE)
4847 fprintf(fp, "Problem with %s %s: wrong data type--expected integer data (%s)\n", class_name, name, registeredProgramName ? registeredProgramName : "?");
4848 else if (type)
4849 fprintf(fp, "Problem with %s %s: invalid data type code seen---may be a programming error (%s)\n", class_name, name, registeredProgramName ? registeredProgramName : "?");
4850 break;
4851 case SDDS_CHECK_WRONGUNITS:
4852 fprintf(fp, "Problem with %s %s: wrong units--expected %s (%s)\n", class_name, name, units ? units : "none", registeredProgramName ? registeredProgramName : "?");
4853 break;
4854 default:
4855 fprintf(stderr, "Problem with call to SDDS_PrintCheckText--invalid error code (%s)\n", registeredProgramName ? registeredProgramName : "?");
4856 return (SDDS_CHECK_OKAY);
4857 }
4858 return (error_code);
4859}
4860
4861/**
4862 * @brief Deletes fixed values from all parameters in the SDDS dataset.
4863 *
4864 * This function iterates through all parameters in the provided SDDS dataset and removes any fixed values associated with them. It ensures that both the current layout and the original layout of the dataset have their fixed values cleared.
4865 *
4866 * @param[in] SDDS_dataset
4867 * Pointer to the `SDDS_DATASET` structure representing the dataset from which fixed values will be deleted.
4868 *
4869 * @return
4870 * - `1` on successful deletion of all fixed values.
4871 * - `0` if the dataset check fails or if saving the layout fails.
4872 *
4873 * @note
4874 * - The function requires that the SDDS dataset is properly initialized and that it contains parameters with fixed values.
4875 * - Both the current layout and the original layout are updated to remove fixed values.
4876 *
4877 * @warning
4878 * - This operation cannot be undone. Ensure that fixed values are no longer needed before calling this function.
4879 * - Improper handling of memory allocations related to fixed values may lead to memory leaks or undefined behavior.
4880 *
4881 * @sa SDDS_CheckDataset, SDDS_SaveLayout
4882 */
4884 int32_t i;
4885 SDDS_LAYOUT *layout, *orig_layout;
4886
4887 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_DeleteFixedValueParameters"))
4888 return 0;
4889 if (!SDDS_SaveLayout(SDDS_dataset))
4890 return 0;
4891 layout = &SDDS_dataset->layout;
4892 orig_layout = &SDDS_dataset->original_layout;
4893 for (i = 0; i < layout->n_parameters; i++) {
4894 if (layout->parameter_definition[i].fixed_value)
4895 free(layout->parameter_definition[i].fixed_value);
4896 if (orig_layout->parameter_definition[i].fixed_value && (!layout->parameter_definition[i].fixed_value || orig_layout->parameter_definition[i].fixed_value != layout->parameter_definition[i].fixed_value))
4897 free(orig_layout->parameter_definition[i].fixed_value);
4898 orig_layout->parameter_definition[i].fixed_value = NULL;
4899 layout->parameter_definition[i].fixed_value = NULL;
4900 }
4901 return 1;
4902}
4903
4904/**
4905 * @brief Sets the data mode (ASCII or Binary) for the SDDS dataset.
4906 *
4907 * This function configures the data mode of the SDDS dataset to either ASCII or Binary. When setting to Binary mode with byte swapping (using `-SDDS_BINARY`), it adjusts the byte order based on the machine's endianness to ensure compatibility.
4908 *
4909 * @param[in] SDDS_dataset
4910 * Pointer to the `SDDS_DATASET` structure representing the dataset whose data mode is to be set.
4911 *
4912 * @param[in] newmode
4913 * The desired data mode. Valid values are:
4914 * - `SDDS_ASCII` for ASCII mode.
4915 * - `SDDS_BINARY` for Binary mode.
4916 * - `-SDDS_BINARY` for Binary mode with byte swapping (for compatibility with systems like the `sddsendian` program).
4917 *
4918 * @return
4919 * - `1` on successful mode change.
4920 * - `0` if the mode is invalid, if the dataset is `NULL`, or if the dataset has already been written to and the mode cannot be changed.
4921 *
4922 * @note
4923 * - Changing the data mode is only permitted if no data has been written to the dataset (i.e., `page_number` is `0` and `n_rows_written` is `0`).
4924 * - When using `-SDDS_BINARY`, the function automatically determines the appropriate byte order based on the machine's endianness.
4925 *
4926 * @warning
4927 * - Attempting to change the data mode after writing data to the dataset will result in an error.
4928 * - Ensure that the `newmode` parameter is correctly specified to prevent unintended behavior.
4929 *
4930 * @sa SDDS_SetError, SDDS_IsBigEndianMachine, SDDS_BINARY, SDDS_ASCII
4931 */
4932int32_t SDDS_SetDataMode(SDDS_DATASET *SDDS_dataset, int32_t newmode) {
4933 if (newmode == -SDDS_BINARY) {
4934 /* will write with bytes swapped.
4935 * provided for compatibility with sddsendian program, which writes the
4936 * data itself
4937 */
4938 SDDS_dataset->layout.byteOrderDeclared = SDDS_IsBigEndianMachine() ? SDDS_LITTLEENDIAN : SDDS_BIGENDIAN;
4939 newmode = SDDS_BINARY;
4940 }
4941 if (newmode != SDDS_ASCII && newmode != SDDS_BINARY) {
4942 SDDS_SetError("Invalid data mode (SDDS_SetDataMode)");
4943 return 0;
4944 }
4945 if (newmode == SDDS_dataset->layout.data_mode.mode)
4946 return 1;
4947 if (!SDDS_dataset) {
4948 SDDS_SetError("NULL page pointer (SDDS_SetDataMode)");
4949 return 0;
4950 }
4951 if (SDDS_dataset->page_number != 0 && (SDDS_dataset->page_number > 1 || SDDS_dataset->n_rows_written != 0)) {
4952 SDDS_SetError("Can't change the mode of a file that's been written to (SDDS_SetDataMode)");
4953 return 0;
4954 }
4955 SDDS_dataset->layout.data_mode.mode = SDDS_dataset->original_layout.data_mode.mode = newmode;
4956 return 1;
4957}
4958
4959/**
4960 * @brief Verifies that the size of the SDDS_DATASET structure matches the expected size.
4961 *
4962 * This function ensures that the size of the `SDDS_DATASET` structure used by the program matches the size expected by the SDDS library. This check is crucial to prevent issues related to structure size mismatches, which can occur due to differences in compiler settings or library versions.
4963 *
4964 * @param[in] size
4965 * The size of the `SDDS_DATASET` structure as determined by the calling program (typically using `sizeof(SDDS_DATASET)`).
4966 *
4967 * @return
4968 * - `1` if the provided size matches the expected size of the `SDDS_DATASET` structure.
4969 * - `0` if there is a size mismatch, indicating potential incompatibility issues.
4970 *
4971 * @note
4972 * - This function should be called during initialization to ensure structural compatibility between the program and the SDDS library.
4973 *
4974 * @warning
4975 * - A size mismatch can lead to undefined behavior, including memory corruption and program crashes. Always ensure that both the program and the SDDS library are compiled with compatible settings.
4976 *
4977 * @sa SDDS_DATASET, SDDS_SetError
4978 */
4979int32_t SDDS_CheckDatasetStructureSize(int32_t size) {
4980 char buffer[100];
4981 if (size != sizeof(SDDS_DATASET)) {
4982 SDDS_SetError("passed size is not equal to expected size for SDDS_DATASET structure");
4983 sprintf(buffer, "Passed size is %" PRId32 ", library size is %" PRId32 "\n", size, (int32_t)sizeof(SDDS_DATASET));
4984 SDDS_SetError(buffer);
4985 return 0;
4986 }
4987 return 1;
4988}
4989
4990/**
4991 * @brief Retrieves the number of columns in the SDDS dataset.
4992 *
4993 * This function returns the total count of columns defined in the layout of the provided SDDS dataset.
4994 *
4995 * @param[in] page
4996 * Pointer to the `SDDS_DATASET` structure representing the dataset.
4997 *
4998 * @return
4999 * - The number of columns (`int32_t`) in the dataset.
5000 * - `0` if the provided dataset pointer is `NULL`.
5001 *
5002 * @note
5003 * - Ensure that the dataset is properly initialized before calling this function.
5004 *
5005 * @sa SDDS_GetColumnIndex, SDDS_CheckColumn
5006 */
5008 if (!page)
5009 return 0;
5010 return page->layout.n_columns;
5011}
5012
5013/**
5014 * @brief Retrieves the number of parameters in the SDDS dataset.
5015 *
5016 * This function returns the total count of parameters defined in the layout of the provided SDDS dataset.
5017 *
5018 * @param[in] page
5019 * Pointer to the `SDDS_DATASET` structure representing the dataset.
5020 *
5021 * @return
5022 * - The number of parameters (`int32_t`) in the dataset.
5023 * - `0` if the provided dataset pointer is `NULL`.
5024 *
5025 * @note
5026 * - Ensure that the dataset is properly initialized before calling this function.
5027 *
5028 * @sa SDDS_GetParameterIndex, SDDS_CheckParameter
5029 */
5031 if (!page)
5032 return 0;
5033 return page->layout.n_parameters;
5034}
5035
5036/**
5037 * @brief Retrieves the number of arrays in the SDDS dataset.
5038 *
5039 * This function returns the total count of arrays defined in the layout of the provided SDDS dataset.
5040 *
5041 * @param[in] page
5042 * Pointer to the `SDDS_DATASET` structure representing the dataset.
5043 *
5044 * @return
5045 * - The number of arrays (`int32_t`) in the dataset.
5046 * - `0` if the provided dataset pointer is `NULL`.
5047 *
5048 * @note
5049 * - Ensure that the dataset is properly initialized before calling this function.
5050 *
5051 * @sa SDDS_GetArrayIndex, SDDS_CheckArray
5052 */
5054 if (!page)
5055 return 0;
5056 return page->layout.n_arrays;
5057}
5058
5059/* `\\`, `\\ '`, `\\\"`, `\\a`, `\?` */
5060/**
5061 * @brief Interprets and converts escape sequences in a string.
5062 *
5063 * This function processes a string containing escape sequences and converts them into their corresponding character representations. Supported escape sequences include:
5064 * - Standard ANSI escape codes: `\n`, `\t`, `\b`, `\r`, `\f`, `\v`, `\\`, \\', `\"`, `\a`, `\?`
5065 * - Octal values: `\ddd`
5066 * - SDDS-specific escape codes: `\!`, `\‍)`
5067 *
5068 * The function modifies the input string `s` in place, replacing escape sequences with their actual character values.
5069 *
5070 * @param[in, out] s
5071 * Pointer to the null-terminated string to be processed. The string will be modified in place.
5072 *
5073 * @note
5074 * - Ensure that the input string `s` has sufficient buffer space to accommodate the modified characters, especially when dealing with octal escape sequences that may reduce the overall string length.
5075 *
5076 * @warning
5077 * - The function does not perform bounds checking. Ensure that the input string is properly null-terminated to prevent undefined behavior.
5078 * - Unrecognized escape sequences (other than the ones specified) will result in the backslash being retained in the string.
5079 *
5080 * @sa SDDS_EscapeNewlines, SDDS_UnescapeNewlines
5081 */
5083/* \ddd = octal value
5084 * ANSI escape codes (n t b r f v \ ' " a ?
5085 * SDDS escape codes (! )
5086 */
5087{
5088 char *ptr;
5089 int32_t count;
5090
5091 ptr = s;
5092 while (*s) {
5093 if (*s != '\\')
5094 *ptr++ = *s++;
5095 else {
5096 s++;
5097 if (!*s) {
5098 *ptr++ = '\\';
5099 *ptr++ = 0;
5100 return;
5101 }
5102 switch (*s) {
5103 case 'n':
5104 *ptr++ = '\n';
5105 s++;
5106 break;
5107 case 't':
5108 *ptr++ = '\t';
5109 s++;
5110 break;
5111 case 'b':
5112 *ptr++ = '\b';
5113 s++;
5114 break;
5115 case 'r':
5116 *ptr++ = '\r';
5117 s++;
5118 break;
5119 case 'f':
5120 *ptr++ = '\f';
5121 s++;
5122 break;
5123 case 'v':
5124 *ptr++ = '\v';
5125 s++;
5126 break;
5127 case '\\':
5128 *ptr++ = '\\';
5129 s++;
5130 break;
5131 case '\'':
5132 *ptr++ = '\'';
5133 s++;
5134 break;
5135 case '"':
5136 *ptr++ = '\"';
5137 s++;
5138 break;
5139 case 'a':
5140 *ptr++ = '\a';
5141 s++;
5142 break;
5143 case '?':
5144 *ptr++ = '\?';
5145 s++;
5146 break;
5147 case '!':
5148 *ptr++ = '!';
5149 s++;
5150 break;
5151 default:
5152 if (*s >= '0' && *s <= '9') {
5153 *ptr = 0;
5154 count = 0;
5155 while (++count <= 3 && *s >= '0' && *s <= '9')
5156 *ptr = 8 * (*ptr) + *s++ - '0';
5157 ptr++;
5158 } else {
5159 *ptr++ = '\\';
5160 }
5161 break;
5162 }
5163 }
5164 }
5165 *ptr = 0;
5166}
5167
5168#define COMMENT_COMMANDS 3
5169static char *commentCommandName[COMMENT_COMMANDS] = {
5170 "big-endian",
5171 "little-endian",
5172 "fixed-rowcount",
5173};
5174
5175static uint32_t commentCommandFlag[COMMENT_COMMANDS] = {
5176 SDDS_BIGENDIAN_SEEN,
5177 SDDS_LITTLEENDIAN_SEEN,
5178 SDDS_FIXED_ROWCOUNT_SEEN,
5179};
5180
5181/**
5182 * @brief Retrieves the current special comments modes set in the SDDS dataset.
5183 *
5184 * This function returns the current set of special comment flags that have been parsed and set within the dataset. These flags indicate the presence of specific configurations such as endianness and fixed row counts.
5185 *
5186 * @param[in] SDDS_dataset
5187 * Pointer to the `SDDS_DATASET` structure representing the dataset.
5188 *
5189 * @return
5190 * - A `uint32_t` value representing the combined set of special comment flags.
5191 * - `0` if no special comments have been set.
5192 *
5193 * @note
5194 * - Special comment flags are typically set by parsing comment strings using functions like `SDDS_ParseSpecialComments`.
5195 *
5196 * @warning
5197 * - Ensure that the dataset is properly initialized before calling this function.
5198 *
5199 * @sa SDDS_ParseSpecialComments, SDDS_ResetSpecialCommentsModes
5200 */
5202 return SDDS_dataset->layout.commentFlags;
5203}
5204
5205/**
5206 * @brief Resets the special comments modes in the SDDS dataset.
5207 *
5208 * This function clears all special comment flags that have been set within the dataset. After calling this function, the dataset will no longer have any special configurations related to comments.
5209 *
5210 * @param[in,out] SDDS_dataset
5211 * Pointer to the `SDDS_DATASET` structure representing the dataset. The `commentFlags` field will be reset to `0`.
5212 *
5213 * @note
5214 * - Use this function to clear all special configurations before setting new ones or when resetting the dataset's state.
5215 *
5216 * @warning
5217 * - This operation cannot be undone. Ensure that you no longer require the existing special comment configurations before resetting.
5218 *
5219 * @sa SDDS_GetSpecialCommentsModes, SDDS_ParseSpecialComments
5220 */
5222 SDDS_dataset->layout.commentFlags = 0;
5223}
5224
5225/**
5226 * @brief Parses and processes special comment commands within the SDDS dataset.
5227 *
5228 * This function interprets special commands embedded within comment strings of the SDDS dataset. Supported special commands include:
5229 * - `big-endian`
5230 * - `little-endian`
5231 * - `fixed-rowcount`
5232 *
5233 * Each recognized command updates the `commentFlags` field within the dataset's layout to reflect the presence of these special configurations.
5234 *
5235 * @param[in,out] SDDS_dataset
5236 * Pointer to the `SDDS_DATASET` structure representing the dataset. The `commentFlags` field will be updated based on the parsed commands.
5237 *
5238 * @param[in] s
5239 * Pointer to the null-terminated string containing special comment commands to be parsed.
5240 *
5241 * @note
5242 * - This function is intended to be used internally by the SDDS library to handle special configurations specified in comments.
5243 * - Only the predefined special commands are recognized and processed.
5244 *
5245 * @warning
5246 * - Unrecognized commands within the comment string are ignored.
5247 * - Ensure that the input string `s` is properly formatted and null-terminated to prevent undefined behavior.
5248 *
5249 * @sa SDDS_GetSpecialCommentsModes, SDDS_ResetSpecialCommentsModes
5250 */
5251void SDDS_ParseSpecialComments(SDDS_DATASET *SDDS_dataset, char *s) {
5252 char buffer[SDDS_MAXLINE];
5253 int32_t i;
5254 if (SDDS_dataset == NULL)
5255 return;
5256 while (SDDS_GetToken(s, buffer, SDDS_MAXLINE) > 0) {
5257 for (i = 0; i < COMMENT_COMMANDS; i++) {
5258 if (strcmp(buffer, commentCommandName[i]) == 0) {
5259 SDDS_dataset->layout.commentFlags |= commentCommandFlag[i];
5260 break;
5261 }
5262 }
5263 }
5264}
5265
5266/**
5267 * @brief Determines whether the current machine uses big-endian byte ordering.
5268 *
5269 * This function checks the byte order of the machine on which the program is running. It returns `1` if the machine is big-endian and `0` if it is little-endian.
5270 *
5271 * @return
5272 * - `1` if the machine is big-endian.
5273 * - `0` if the machine is little-endian.
5274 *
5275 * @note
5276 * - Endianness detection is based on inspecting the byte order of an integer value.
5277 *
5278 * @warning
5279 * - This function assumes that `int32_t` is 4 bytes in size. If compiled on a system where `int32_t` differs in size, the behavior may be incorrect.
5280 *
5281 * @sa SDDS_SetDataMode
5282 */
5284 int32_t x = 1;
5285 if (*((char *)&x))
5286 return 0;
5287 return 1;
5288}
5289
5290/**
5291 * @brief Verifies the existence of an array in the SDDS dataset based on specified criteria.
5292 *
5293 * This function searches for an array within the SDDS dataset that matches the given criteria defined by the `mode`. It returns the index of the first matching array or `-1` if no match is found.
5294 *
5295 * The function supports the following modes:
5296 * - **FIND_SPECIFIED_TYPE**:
5297 * - **Parameters**: `int32_t type`, `char *name`
5298 * - **Description**: Finds the first array with the specified type.
5299 *
5300 * - **FIND_ANY_TYPE**:
5301 * - **Parameters**: `char *name`
5302 * - **Description**: Finds the first array with any type.
5303 *
5304 * - **FIND_NUMERIC_TYPE**:
5305 * - **Parameters**: `char *name`
5306 * - **Description**: Finds the first array with a numeric type.
5307 *
5308 * - **FIND_FLOATING_TYPE**:
5309 * - **Parameters**: `char *name`
5310 * - **Description**: Finds the first array with a floating type.
5311 *
5312 * - **FIND_INTEGER_TYPE**:
5313 * - **Parameters**: `char *name`
5314 * - **Description**: Finds the first array with an integer type.
5315 *
5316 * @param[in] SDDS_dataset
5317 * Pointer to the `SDDS_DATASET` structure representing the dataset to be searched.
5318 *
5319 * @param[in] mode
5320 * Specifies the mode for matching arrays. Valid modes are:
5321 * - `FIND_SPECIFIED_TYPE`
5322 * - `FIND_ANY_TYPE`
5323 * - `FIND_NUMERIC_TYPE`
5324 * - `FIND_FLOATING_TYPE`
5325 * - `FIND_INTEGER_TYPE`
5326 *
5327 * @param[in] ...
5328 * Variable arguments depending on `mode`:
5329 * - **FIND_SPECIFIED_TYPE**: `int32_t type`, followed by `char *name`
5330 * - **Other Modes**: `char *name`
5331 *
5332 * @return
5333 * - Returns the index (`int32_t`) of the first matched array.
5334 * - Returns `-1` if no matching array is found.
5335 *
5336 * @note
5337 * - The caller must ensure that the variable arguments match the expected parameters for the specified `mode`.
5338 *
5339 * @warning
5340 * - Passing incorrect types or mismatched arguments may lead to undefined behavior.
5341 *
5342 * @sa SDDS_GetArrayIndex, SDDS_CheckArray, SDDS_MatchArrays
5343 */
5344int32_t SDDS_VerifyArrayExists(SDDS_DATASET *SDDS_dataset, int32_t mode, ...) {
5345 int32_t index, type, thisType;
5346 va_list argptr;
5347 char *name;
5348
5349 va_start(argptr, mode);
5350 type = 0;
5351
5352 if (mode == FIND_SPECIFIED_TYPE)
5353 type = va_arg(argptr, int32_t);
5354 name = va_arg(argptr, char *);
5355 if ((index = SDDS_GetArrayIndex(SDDS_dataset, name)) >= 0) {
5356 thisType = SDDS_GetArrayType(SDDS_dataset, index);
5357 if (mode == FIND_ANY_TYPE || (mode == FIND_SPECIFIED_TYPE && thisType == type) || (mode == FIND_NUMERIC_TYPE && SDDS_NUMERIC_TYPE(thisType)) || (mode == FIND_FLOATING_TYPE && SDDS_FLOATING_TYPE(thisType)) || (mode == FIND_INTEGER_TYPE && SDDS_INTEGER_TYPE(thisType))) {
5358 va_end(argptr);
5359 return (index);
5360 }
5361 }
5362 va_end(argptr);
5363 return (-1);
5364}
5365
5366/**
5367 * @brief Verifies the existence of a column in the SDDS dataset based on specified criteria.
5368 *
5369 * This function searches for a column within the SDDS dataset that matches the given criteria defined by the `mode`. It returns the index of the first matching column or `-1` if no match is found.
5370 *
5371 * The function supports the following modes:
5372 * - **FIND_SPECIFIED_TYPE**:
5373 * - **Parameters**: `int32_t type`, `char *name`
5374 * - **Description**: Finds the first column with the specified type.
5375 *
5376 * - **FIND_ANY_TYPE**:
5377 * - **Parameters**: `char *name`
5378 * - **Description**: Finds the first column with any type.
5379 *
5380 * - **FIND_NUMERIC_TYPE**:
5381 * - **Parameters**: `char *name`
5382 * - **Description**: Finds the first column with a numeric type.
5383 *
5384 * - **FIND_FLOATING_TYPE**:
5385 * - **Parameters**: `char *name`
5386 * - **Description**: Finds the first column with a floating type.
5387 *
5388 * - **FIND_INTEGER_TYPE**:
5389 * - **Parameters**: `char *name`
5390 * - **Description**: Finds the first column with an integer type.
5391 *
5392 * @param[in] SDDS_dataset
5393 * Pointer to the `SDDS_DATASET` structure representing the dataset to be searched.
5394 *
5395 * @param[in] mode
5396 * Specifies the mode for matching columns. Valid modes are:
5397 * - `FIND_SPECIFIED_TYPE`
5398 * - `FIND_ANY_TYPE`
5399 * - `FIND_NUMERIC_TYPE`
5400 * - `FIND_FLOATING_TYPE`
5401 * - `FIND_INTEGER_TYPE`
5402 *
5403 * @param[in] ...
5404 * Variable arguments depending on `mode`:
5405 * - **FIND_SPECIFIED_TYPE**: `int32_t type`, followed by `char *name`
5406 * - **Other Modes**: `char *name`
5407 *
5408 * @return
5409 * - Returns the index (`int32_t`) of the first matched column.
5410 * - Returns `-1` if no matching column is found.
5411 *
5412 * @note
5413 * - The caller must ensure that the variable arguments match the expected parameters for the specified `mode`.
5414 *
5415 * @warning
5416 * - Passing incorrect types or mismatched arguments may lead to undefined behavior.
5417 *
5418 * @sa SDDS_GetColumnIndex, SDDS_CheckColumn, SDDS_MatchColumns
5419 */
5420int32_t SDDS_VerifyColumnExists(SDDS_DATASET *SDDS_dataset, int32_t mode, ...) {
5421 int32_t index;
5422 int32_t type, thisType;
5423 va_list argptr;
5424 char *name;
5425
5426 va_start(argptr, mode);
5427 type = 0;
5428
5429 if (mode == FIND_SPECIFIED_TYPE)
5430 type = va_arg(argptr, int32_t);
5431 name = va_arg(argptr, char *);
5432 if ((index = SDDS_GetColumnIndex(SDDS_dataset, name)) >= 0) {
5433 thisType = SDDS_GetColumnType(SDDS_dataset, index);
5434 if (mode == FIND_ANY_TYPE || (mode == FIND_SPECIFIED_TYPE && thisType == type) || (mode == FIND_NUMERIC_TYPE && SDDS_NUMERIC_TYPE(thisType)) || (mode == FIND_FLOATING_TYPE && SDDS_FLOATING_TYPE(thisType)) || (mode == FIND_INTEGER_TYPE && SDDS_INTEGER_TYPE(thisType))) {
5435 va_end(argptr);
5436 return (index);
5437 }
5438 }
5439 va_end(argptr);
5440 return (-1);
5441}
5442
5443/**
5444 * @brief Verifies the existence of a parameter in the SDDS dataset based on specified criteria.
5445 *
5446 * This function searches for a parameter within the SDDS dataset that matches the given criteria defined by the `mode`. It returns the index of the first matching parameter or `-1` if no match is found.
5447 *
5448 * The function supports the following modes:
5449 * - **FIND_SPECIFIED_TYPE**:
5450 * - **Parameters**: `int32_t type`, `char *name`
5451 * - **Description**: Finds the first parameter with the specified type.
5452 *
5453 * - **FIND_ANY_TYPE**:
5454 * - **Parameters**: `char *name`
5455 * - **Description**: Finds the first parameter with any type.
5456 *
5457 * - **FIND_NUMERIC_TYPE**:
5458 * - **Parameters**: `char *name`
5459 * - **Description**: Finds the first parameter with a numeric type.
5460 *
5461 * - **FIND_FLOATING_TYPE**:
5462 * - **Parameters**: `char *name`
5463 * - **Description**: Finds the first parameter with a floating type.
5464 *
5465 * - **FIND_INTEGER_TYPE**:
5466 * - **Parameters**: `char *name`
5467 * - **Description**: Finds the first parameter with an integer type.
5468 *
5469 * @param[in] SDDS_dataset
5470 * Pointer to the `SDDS_DATASET` structure representing the dataset to be searched.
5471 *
5472 * @param[in] mode
5473 * Specifies the mode for matching parameters. Valid modes are:
5474 * - `FIND_SPECIFIED_TYPE`
5475 * - `FIND_ANY_TYPE`
5476 * - `FIND_NUMERIC_TYPE`
5477 * - `FIND_FLOATING_TYPE`
5478 * - `FIND_INTEGER_TYPE`
5479 *
5480 * @param[in] ...
5481 * Variable arguments depending on `mode`:
5482 * - **FIND_SPECIFIED_TYPE**: `int32_t type`, followed by `char *name`
5483 * - **Other Modes**: `char *name`
5484 *
5485 * @return
5486 * - Returns the index (`int32_t`) of the first matched parameter.
5487 * - Returns `-1` if no matching parameter is found.
5488 *
5489 * @note
5490 * - The caller must ensure that the variable arguments match the expected parameters for the specified `mode`.
5491 *
5492 * @warning
5493 * - Passing incorrect types or mismatched arguments may lead to undefined behavior.
5494 *
5495 * @sa SDDS_GetParameterIndex, SDDS_CheckParameter, SDDS_MatchParameters
5496 */
5497int32_t SDDS_VerifyParameterExists(SDDS_DATASET *SDDS_dataset, int32_t mode, ...) {
5498 int32_t index, type, thisType;
5499 va_list argptr;
5500 char *name;
5501
5502 va_start(argptr, mode);
5503 type = 0;
5504
5505 if (mode == FIND_SPECIFIED_TYPE)
5506 type = va_arg(argptr, int32_t);
5507 name = va_arg(argptr, char *);
5508 if ((index = SDDS_GetParameterIndex(SDDS_dataset, name)) >= 0) {
5509 thisType = SDDS_GetParameterType(SDDS_dataset, index);
5510 if (mode == FIND_ANY_TYPE || (mode == FIND_SPECIFIED_TYPE && thisType == type) || (mode == FIND_NUMERIC_TYPE && SDDS_NUMERIC_TYPE(thisType)) || (mode == FIND_FLOATING_TYPE && SDDS_FLOATING_TYPE(thisType)) || (mode == FIND_INTEGER_TYPE && SDDS_INTEGER_TYPE(thisType))) {
5511 va_end(argptr);
5512 return (index);
5513 }
5514 }
5515 va_end(argptr);
5516 return (-1);
5517}
5518
5519/**
5520 * @brief Retrieves an array of matching SDDS entity names based on specified criteria.
5521 *
5522 * This function processes a list of SDDS entity names (columns, parameters, or arrays) and selects those that match the provided criteria. It supports wildcard matching and exact matching based on the presence of wildcards in the names.
5523 *
5524 * @param[in] dataset
5525 * Pointer to the `SDDS_DATASET` structure representing the dataset to be searched.
5526 *
5527 * @param[in] matchName
5528 * Array of strings containing the names or patterns to match against the dataset's entities.
5529 *
5530 * @param[in] matches
5531 * The number of names/patterns provided in `matchName`.
5532 *
5533 * @param[out] names
5534 * Pointer to an `int32_t` that will be set to the number of matched names.
5535 *
5536 * @param[in] type
5537 * Specifies the type of SDDS entity to match. Valid values are:
5538 * - `SDDS_MATCH_COLUMN`
5539 * - `SDDS_MATCH_PARAMETER`
5540 * - `SDDS_MATCH_ARRAY`
5541 *
5542 * @return
5543 * - Returns an array of strings (`char **`) containing the names of the matched SDDS entities.
5544 * - If no matches are found, returns `NULL`.
5545 *
5546 * @note
5547 * - The caller is responsible for freeing the memory allocated for the returned array and the individual strings within it.
5548 * - The function uses `wild_match` for pattern matching when wildcards are present in the `matchName` entries.
5549 *
5550 * @warning
5551 * - Ensure that the `type` parameter is correctly specified to match the intended SDDS entity class.
5552 * - Passing an invalid `type` value will cause the function to terminate the program with an error message.
5553 *
5554 * @sa SDDS_MatchColumns, SDDS_MatchParameters, SDDS_MatchArrays, SDDS_Realloc, SDDS_CopyString
5555 */
5556char **getMatchingSDDSNames(SDDS_DATASET *dataset, char **matchName, int32_t matches, int32_t *names, short type) {
5557 char **name, **selectedName, *ptr = NULL;
5558 int32_t names0 = 0, selected = 0, i, j;
5559 int32_t names32 = 0;
5560
5561 name = selectedName = NULL;
5562 switch (type) {
5563 case SDDS_MATCH_COLUMN:
5564 if (!(name = SDDS_GetColumnNames(dataset, &names0)))
5565 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
5566 break;
5567 case SDDS_MATCH_PARAMETER:
5568 if (!(name = SDDS_GetParameterNames(dataset, &names32)))
5569 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
5570 names0 = names32;
5571 break;
5572 case SDDS_MATCH_ARRAY:
5573 if (!(name = SDDS_GetArrayNames(dataset, &names32)))
5574 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
5575 names0 = names32;
5576 break;
5577 default:
5578 SDDS_Bomb("Invalid match type provided.");
5579 break;
5580 }
5581 for (i = 0; i < matches; i++) {
5582 if (has_wildcards(matchName[i])) {
5583 ptr = expand_ranges(matchName[i]);
5584 for (j = 0; j < names0; j++) {
5585 if (wild_match(name[j], ptr)) {
5586 selectedName = SDDS_Realloc(selectedName, sizeof(*selectedName) * (selected + 1));
5587 SDDS_CopyString(&selectedName[selected], name[j]);
5588 selected++;
5589 }
5590 }
5591 free(ptr);
5592 } else {
5593 if (match_string(matchName[i], name, names0, EXACT_MATCH) < 0) {
5594 fprintf(stderr, "%s not found in input file.\n", matchName[i]);
5595 exit(1);
5596 } else {
5597 selectedName = SDDS_Realloc(selectedName, sizeof(*selectedName) * (selected + 1));
5598 SDDS_CopyString(&selectedName[selected], matchName[i]);
5599 selected++;
5600 }
5601 }
5602 }
5603 SDDS_FreeStringArray(name, names0);
5604 free(name);
5605 *names = selected;
5606 return selectedName;
5607}
5608
5609/**
5610 * @brief Creates an empty SDDS dataset.
5611 *
5612 * This function allocates and initializes an empty `SDDS_DATASET` structure. The returned dataset can then be configured and populated with columns, parameters, and arrays as needed.
5613 *
5614 * @return
5615 * - Pointer to the newly created `SDDS_DATASET` structure.
5616 * - `NULL` if memory allocation fails.
5617 *
5618 * @note
5619 * - The caller is responsible for initializing the dataset's layout and other necessary fields before use.
5620 * - Ensure that the returned dataset is properly freed using appropriate memory deallocation functions to prevent memory leaks.
5621 *
5622 * @warning
5623 * - Failing to initialize the dataset after creation may lead to undefined behavior when performing operations on it.
5624 * - Always check if the returned pointer is not `NULL` before using it.
5625 *
5626 * @sa SDDS_FreeDataset, SDDS_InitLayout
5627 */
5629 SDDS_DATASET *dataset;
5630 dataset = malloc(sizeof(SDDS_DATASET));
5631 return dataset;
5632}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
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_type_name[SDDS_NUM_TYPES]
Array of supported data type names.
Definition SDDS_data.c:43
int32_t SDDS_Logic(int32_t previous, int32_t match, uint32_t logic)
Applies logical operations to determine the new state of a row flag based on previous and current mat...
int32_t SDDS_GetArrayInformation(SDDS_DATASET *SDDS_dataset, char *field_name, void *memory, int32_t mode,...)
Retrieves information about a specified array in the SDDS dataset.
Definition SDDS_info.c:192
int32_t SDDS_GetParameterInformation(SDDS_DATASET *SDDS_dataset, char *field_name, void *memory, int32_t mode,...)
Retrieves information about a specified parameter in the SDDS dataset.
Definition SDDS_info.c:117
int32_t SDDS_GetColumnInformation(SDDS_DATASET *SDDS_dataset, char *field_name, void *memory, int32_t mode,...)
Retrieves information about a specified column in the SDDS dataset.
Definition SDDS_info.c:41
Internal definitions and function declarations for SDDS with LZMA support.
int32_t SDDS_VerifyParameterExists(SDDS_DATASET *SDDS_dataset, int32_t mode,...)
Verifies the existence of a parameter in the SDDS dataset based on specified criteria.
void SDDS_FreeArray(SDDS_ARRAY *array)
Frees memory allocated for an SDDS array structure.
int32_t SDDS_CheckArray(SDDS_DATASET *SDDS_dataset, char *name, char *units, int32_t type, FILE *fp_message)
Checks if an array exists in the SDDS dataset with the specified name, units, and type.
int32_t SDDS_FileIsLocked(const char *filename)
Determines if a specified file is locked.
int32_t SDDS_GetNamedArrayType(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the data type of an array in the SDDS dataset by its name.
int32_t SDDS_FreeStringArray(char **string, int64_t strings)
Frees an array of strings by deallocating each individual string.
void SDDS_SetError0(char *error_text)
Internal function to record an error message in the SDDS error stack.
Definition SDDS_utils.c:395
uint32_t SDDS_SetAutoCheckMode(uint32_t newMode)
Sets the automatic check mode for SDDS dataset validation.
Definition SDDS_utils.c:533
void SDDS_InterpretEscapes(char *s)
Interprets and converts escape sequences in a string.
int32_t SDDS_GetNamedColumnType(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the data type of a column in the SDDS dataset by its name.
void SDDS_SetError(char *error_text)
Records an error message in the SDDS error stack.
Definition SDDS_utils.c:379
void SDDS_FreeMatrix(void **ptr, int64_t dim1)
Frees memory allocated for a two-dimensional matrix.
int32_t SDDS_VerifyArrayExists(SDDS_DATASET *SDDS_dataset, int32_t mode,...)
Verifies the existence of an array in the SDDS dataset based on specified criteria.
int32_t SDDS_GetParameterType(SDDS_DATASET *SDDS_dataset, int32_t index)
Retrieves the data type of a parameter in the SDDS dataset by its index.
int32_t SDDS_GetNamedParameterType(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the data type of a parameter in the SDDS dataset by its name.
int32_t SDDS_IsActive(SDDS_DATASET *SDDS_dataset)
Checks whether an SDDS dataset is currently active.
ASSOCIATE_DEFINITION * SDDS_GetAssociateDefinition(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the definition of a specified associate from the SDDS dataset.
Definition SDDS_utils.c:883
int32_t SDDS_ZeroMemory(void *mem, int64_t n_bytes)
Sets a block of memory to zero.
int32_t SDDS_SetDataMode(SDDS_DATASET *SDDS_dataset, int32_t newmode)
Sets the data mode (ASCII or Binary) for the SDDS dataset.
int SDDS_CompareIndexedNames(const void *s1, const void *s2)
Compares two SORTED_INDEX structures by their name fields.
ARRAY_DEFINITION * SDDS_GetArrayDefinition(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the definition of a specified array from the SDDS dataset.
int32_t SDDS_VerifyPrintfFormat(const char *string, int32_t type)
Verifies that a printf format string is compatible with a specified data type.
Definition SDDS_utils.c:750
int32_t SDDS_FreeArrayDefinition(ARRAY_DEFINITION *source)
Frees memory allocated for an array definition.
char * SDDS_FindArray(SDDS_DATASET *SDDS_dataset, int32_t mode,...)
Finds the first array in the SDDS dataset that matches the specified criteria.
int32_t SDDS_GetArrayIndex(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the index of a named array in the SDDS dataset.
char ** getMatchingSDDSNames(SDDS_DATASET *dataset, char **matchName, int32_t matches, int32_t *names, short type)
Retrieves an array of matching SDDS entity names based on specified criteria.
PARAMETER_DEFINITION * SDDS_GetParameterDefinition(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the definition of a specified parameter from the SDDS dataset.
int32_t SDDS_BreakIntoLockedFile(char *filename)
Attempts to override a locked file by creating a temporary copy.
int32_t SDDS_ParameterCount(SDDS_DATASET *page)
Retrieves the number of parameters in the SDDS dataset.
int32_t SDDS_FreeParameterDefinition(PARAMETER_DEFINITION *source)
Frees memory allocated for a parameter definition.
void * SDDS_Recalloc(void *old_ptr, size_t old_size, size_t new_size)
Reallocates memory to a new size and zero-initializes the additional space.
Definition SDDS_utils.c:707
char ** SDDS_GetParameterNames(SDDS_DATASET *SDDS_dataset, int32_t *number)
Retrieves the names of all parameters in the SDDS dataset.
int32_t SDDS_GetParameterIndex(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the index of a named parameter in the SDDS dataset.
int32_t SDDS_SprintTypedValue(void *data, int64_t index, int32_t type, const char *format, char *buffer, uint32_t mode)
Formats a data value of a specified type into a string buffer using an optional printf format string.
Definition SDDS_utils.c:151
int32_t SDDS_GetColumnIndex(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the index of a named column in the SDDS dataset.
int32_t SDDS_MatchParameters(SDDS_DATASET *SDDS_dataset, char ***nameReturn, int32_t matchMode, int32_t typeMode,...)
Matches and retrieves parameter names from an SDDS dataset based on specified criteria.
char * fgetsSkipComments(SDDS_DATASET *SDDS_dataset, char *s, int32_t slen, FILE *fp, char skip_char)
Reads a line from a file while skipping comment lines.
int SDDS_CompareIndexedNamesPtr(const void *s1, const void *s2)
Compares two pointers to SORTED_INDEX structures by their name fields.
void * SDDS_CastValue(void *data, int64_t index, int32_t data_type, int32_t desired_type, void *memory)
Casts a value from one SDDS data type to another.
void * SDDS_MakePointerArrayRecursively(void *data, int32_t size, int32_t dimensions, int32_t *dimension)
Recursively creates a multi-dimensional pointer array from a contiguous data block.
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_ColumnCount(SDDS_DATASET *page)
Retrieves the number of columns in the SDDS dataset.
char ** SDDS_GetAssociateNames(SDDS_DATASET *SDDS_dataset, int32_t *number)
Retrieves the names of all associates in the SDDS dataset.
int32_t SDDS_SprintTypedValueFactor(void *data, int64_t index, int32_t type, const char *format, char *buffer, uint32_t mode, double factor)
Reallocates memory to a new size and zero-initializes the additional space.
Definition SDDS_utils.c:186
char * SDDS_GetTypeName(int32_t type)
Retrieves the name of a specified SDDS data type as a string.
int32_t SDDS_CheckColumn(SDDS_DATASET *SDDS_dataset, char *name, char *units, int32_t type, FILE *fp_message)
Checks if a column exists in the SDDS dataset with the specified name, units, and type.
char * fgetsLZMASkipCommentsResize(SDDS_DATASET *SDDS_dataset, char **s, int32_t *slen, struct lzmafile *lzmafp, char skip_char)
Reads a line from a LZMA-compressed file with dynamic buffer resizing while skipping comment lines.
void * SDDS_AllocateMatrix(int32_t size, int64_t dim1, int64_t dim2)
Allocates a two-dimensional matrix with zero-initialized elements.
void SDDS_EscapeQuotes(char *s, char quote_char)
Escapes quote characters within a string by inserting backslashes.
char * fgetsLZMASkipComments(SDDS_DATASET *SDDS_dataset, char *s, int32_t slen, struct lzmafile *lzmafp, char skip_char)
Reads a line from a LZMA-compressed file while skipping comment lines.
ASSOCIATE_DEFINITION * SDDS_CopyAssociateDefinition(ASSOCIATE_DEFINITION **target, ASSOCIATE_DEFINITION *source)
Creates a copy of an associate definition.
Definition SDDS_utils.c:920
char ** SDDS_GetColumnNames(SDDS_DATASET *SDDS_dataset, int32_t *number)
Retrieves the names of all columns in the SDDS dataset.
int32_t SDDS_ColumnIsOfInterest(SDDS_DATASET *SDDS_dataset, char *name)
Determines if a specified column is marked as of interest in the dataset.
int32_t SDDS_GetArrayType(SDDS_DATASET *SDDS_dataset, int32_t index)
Retrieves the data type of an array in the SDDS dataset by its index.
void SDDS_CutOutComments(SDDS_DATASET *SDDS_dataset, char *s, char cc)
Removes comments from a string based on a specified comment character.
int32_t SDDS_CheckDataset(SDDS_DATASET *SDDS_dataset, const char *caller)
Validates the SDDS dataset pointer.
Definition SDDS_utils.c:552
char * SDDS_FindParameter(SDDS_DATASET *SDDS_dataset, int32_t mode,...)
Finds the first parameter in the SDDS dataset that matches the specified criteria.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
Definition SDDS_utils.c:432
char ** SDDS_GetErrorMessages(int32_t *number, int32_t mode)
Retrieves recorded error messages from the SDDS error stack.
Definition SDDS_utils.c:480
int32_t SDDS_CopyStringArray(char **target, char **source, int64_t n_strings)
Copies an array of strings from source to target.
void * SDDS_Malloc(size_t size)
Allocates memory of a specified size.
Definition SDDS_utils.c:639
void SDDS_EscapeCommentCharacters(char *string, char cc)
Escapes comment characters within a string by inserting backslashes.
int32_t SDDS_DeleteParameterFixedValues(SDDS_DATASET *SDDS_dataset)
Deletes fixed values from all parameters in the SDDS dataset.
void SDDS_ClearErrors()
Clears all recorded error messages from the SDDS error stack.
Definition SDDS_utils.c:318
int32_t SDDS_ApplyFactorToColumn(SDDS_DATASET *SDDS_dataset, char *name, double factor)
Applies a scaling factor to all elements of a specific column in the SDDS dataset.
void SDDS_FreePointerArray(void **data, int32_t dimensions, int32_t *dimension)
Frees a multi-dimensional pointer array created by SDDS_MakePointerArray.
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
Definition SDDS_utils.c:288
int32_t SDDS_NumberOfErrors()
Retrieves the number of errors recorded by SDDS library routines.
Definition SDDS_utils.c:304
int32_t SDDS_IdentifyType(char *typeName)
Identifies the SDDS data type based on its string name.
int32_t SDDS_ArrayCount(SDDS_DATASET *page)
Retrieves the number of arrays in the SDDS dataset.
int32_t SDDS_GetTypeSize(int32_t type)
Retrieves the size in bytes of a specified SDDS data type.
int32_t SDDS_StringIsBlank(char *s)
Checks if a string is blank (contains only whitespace characters).
int32_t SDDS_LockFile(FILE *fp, const char *filename, const char *caller)
Attempts to lock a specified file.
int32_t SDDS_ApplyFactorToParameter(SDDS_DATASET *SDDS_dataset, char *name, double factor)
Applies a scaling factor to a specific parameter in the SDDS dataset.
int32_t SDDS_GetToken(char *s, char *buffer, int32_t buflen)
Extracts the next token from a string, handling quoted substrings and escape characters.
char * SDDS_FindColumn(SDDS_DATASET *SDDS_dataset, int32_t mode,...)
Finds the first column in the SDDS dataset that matches the specified criteria.
int32_t SDDS_CheckDatasetStructureSize(int32_t size)
Verifies that the size of the SDDS_DATASET structure matches the expected size.
int32_t SDDS_MatchColumns(SDDS_DATASET *SDDS_dataset, char ***nameReturn, int32_t matchMode, int32_t typeMode,...)
Matches and retrieves column names from an SDDS dataset based on specified criteria.
ARRAY_DEFINITION * SDDS_CopyArrayDefinition(ARRAY_DEFINITION **target, ARRAY_DEFINITION *source)
Creates a copy of an array definition.
int32_t SDDS_GetColumnType(SDDS_DATASET *SDDS_dataset, int32_t index)
Retrieves the data type of a column in the SDDS dataset by its index.
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
Definition SDDS_utils.c:342
int32_t SDDS_CheckParameter(SDDS_DATASET *SDDS_dataset, char *name, char *units, int32_t type, FILE *fp_message)
Checks if a parameter exists in the SDDS dataset with the specified name, units, and type.
int32_t SDDS_PrintCheckText(FILE *fp, char *name, char *units, int32_t type, char *class_name, int32_t error_code)
Prints detailed error messages related to SDDS entity checks.
int32_t SDDS_ForceInactive(SDDS_DATASET *SDDS_dataset)
Marks an SDDS dataset as inactive.
int32_t SDDS_GetAssociateIndex(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the index of a named associate in the SDDS dataset.
int32_t SDDS_VerifyColumnExists(SDDS_DATASET *SDDS_dataset, int32_t mode,...)
Verifies the existence of a column in the SDDS dataset based on specified criteria.
char ** SDDS_GetArrayNames(SDDS_DATASET *SDDS_dataset, int32_t *number)
Retrieves the names of all arrays in the SDDS dataset.
int32_t SDDS_CopyString(char **target, const char *source)
Copies a source string to a target string with memory allocation.
Definition SDDS_utils.c:856
int32_t SDDS_CheckTabularData(SDDS_DATASET *SDDS_dataset, const char *caller)
Validates the consistency of tabular data within an SDDS dataset.
Definition SDDS_utils.c:577
int32_t SDDS_IsBigEndianMachine()
Determines whether the current machine uses big-endian byte ordering.
void * SDDS_Realloc(void *old_ptr, size_t new_size)
Reallocates memory to a new size.
Definition SDDS_utils.c:677
int32_t SDDS_GetToken2(char *s, char **st, int32_t *strlength, char *buffer, int32_t buflen)
Extracts the next token from a string, handling quoted substrings and escape characters,...
uint32_t SDDS_GetSpecialCommentsModes(SDDS_DATASET *SDDS_dataset)
Retrieves the current special comments modes set in the SDDS dataset.
void SDDS_EscapeNewlines(char *s)
Escapes newline characters in a string by replacing them with "\\n".
int32_t SDDS_FreeAssociateDefinition(ASSOCIATE_DEFINITION *source)
Frees memory allocated for an associate definition.
Definition SDDS_utils.c:944
void SDDS_UnescapeQuotes(char *s, char quote_char)
Removes escape characters from quote characters within a string.
int32_t SDDS_PrintTypedValue(void *data, int64_t index, int32_t type, char *format, FILE *fp, uint32_t mode)
Prints a data value of a specified type using an optional printf format string.
Definition SDDS_utils.c:59
void SDDS_ResetSpecialCommentsModes(SDDS_DATASET *SDDS_dataset)
Resets the special comments modes in the SDDS dataset.
COLUMN_DEFINITION * SDDS_CopyColumnDefinition(COLUMN_DEFINITION **target, COLUMN_DEFINITION *source)
Creates a copy of a column definition.
char * fgetsSkipCommentsResize(SDDS_DATASET *SDDS_dataset, char **s, int32_t *slen, FILE *fp, char skip_char)
Reads a line from a file with dynamic buffer resizing while skipping comment lines.
void SDDS_ParseSpecialComments(SDDS_DATASET *SDDS_dataset, char *s)
Parses and processes special comment commands within the SDDS dataset.
void SDDS_Free(void *mem)
Free memory previously allocated by SDDS_Malloc.
Definition SDDS_utils.c:655
void SDDS_RemovePadding(char *s)
Removes leading and trailing whitespace from a string.
int32_t SDDS_PadToLength(char *string, int32_t length)
Pads a string with spaces to reach a specified length.
int32_t SDDS_HasWhitespace(char *string)
Checks if a string contains any whitespace characters.
void SDDS_Warning(char *message)
Prints a warning message to stderr.
Definition SDDS_utils.c:362
void * SDDS_MakePointerArray(void *data, int32_t type, int32_t dimensions, int32_t *dimension)
Creates a multi-dimensional pointer array from a contiguous data block.
int32_t SDDS_FreeColumnDefinition(COLUMN_DEFINITION *source)
Frees memory allocated for a column definition.
PARAMETER_DEFINITION * SDDS_CopyParameterDefinition(PARAMETER_DEFINITION **target, PARAMETER_DEFINITION *source)
Creates a copy of a parameter definition.
COLUMN_DEFINITION * SDDS_GetColumnDefinition(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the definition of a specified column from the SDDS dataset.
Definition SDDS_utils.c:978
void * SDDS_Calloc(size_t nelem, size_t elem_size)
Allocates zero-initialized memory for an array of elements.
Definition SDDS_utils.c:617
SDDS_DATASET * SDDS_CreateEmptyDataset(void)
Creates an empty SDDS dataset.
int32_t SDDS_MatchArrays(SDDS_DATASET *SDDS_dataset, char ***nameReturn, int32_t matchMode, int32_t typeMode,...)
Matches and retrieves array names from an SDDS dataset based on specified criteria.
#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_INTEGER_TYPE(type)
Checks if the given type identifier corresponds to an integer type.
Definition SDDStypes.h:109
#define SDDS_VALID_TYPE(type)
Validates whether the given type identifier is within the defined range of SDDS types.
Definition SDDStypes.h:149
#define SDDS_FLOAT
Identifier for the float data type.
Definition SDDStypes.h:43
#define SDDS_STRING
Identifier for the string data type.
Definition SDDStypes.h:85
#define SDDS_ULONG64
Identifier for the unsigned 64-bit integer data type.
Definition SDDStypes.h:55
#define SDDS_FLOATING_TYPE(type)
Checks if the given type identifier corresponds to a floating-point type.
Definition SDDStypes.h:124
#define SDDS_LONG
Identifier for the signed 32-bit integer data type.
Definition SDDStypes.h:61
#define SDDS_SHORT
Identifier for the signed short integer data type.
Definition SDDStypes.h:73
#define SDDS_ANY_FLOATING_TYPE
Special identifier used by SDDS_Check*() routines to accept any floating-point type.
Definition SDDStypes.h:165
#define SDDS_CHARACTER
Identifier for the character data type.
Definition SDDStypes.h:91
#define SDDS_USHORT
Identifier for the unsigned short integer data type.
Definition SDDStypes.h:79
#define SDDS_ANY_NUMERIC_TYPE
Special identifier used by SDDS_Check*() routines to accept any numeric type.
Definition SDDStypes.h:157
#define SDDS_DOUBLE
Identifier for the double data type.
Definition SDDStypes.h:37
#define SDDS_NUMERIC_TYPE(type)
Checks if the given type identifier corresponds to any numeric type.
Definition SDDStypes.h:138
#define SDDS_ANY_INTEGER_TYPE
Special identifier used by SDDS_Check*() routines to accept any integer type.
Definition SDDStypes.h:173
#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