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