SDDS ToolKit Programs and Libraries for C and Python
All Classes Files Functions Variables Macros Pages
SDDSutils.c
Go to the documentation of this file.
1/**
2 * @file SDDSutils.c
3 * @brief Utility routines for SDDS applications.
4 *
5 * This file contains a collection of utility functions used in SDDS (Self Describing Data Sets)
6 * applications. These utilities include functions for string manipulation, unit operations,
7 * parameter comparisons, and prime number calculations to support various data processing tasks
8 * within SDDS datasets.
9 *
10 * @copyright
11 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
12 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
13 *
14 * @license
15 * This file is distributed under the terms of the Software License Agreement
16 * found in the file LICENSE included with this distribution.
17 *
18 * @author M. Borland, C. Saunders, R. Soliday, H. Shang
19 */
20
21#include "mdb.h"
22#include "SDDS.h"
23#include "SDDSutils.h"
24
25long appendToStringArray(char ***item, long items, char *newItem) {
26 if (!(*item = SDDS_Realloc(*item, sizeof(**item) * (items + 1))))
27 SDDS_Bomb("allocation failure in appendToStringArray");
28 if (!SDDS_CopyString((*item) + items, newItem)) {
29 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
30 exit(1);
31 }
32 return items + 1;
33}
34
35long expandColumnPairNames(SDDS_DATASET *SDDSin, char ***name, char ***errorName, long names, char **excludeName,
36 long excludeNames, long typeMode, long typeValue) {
37 long i, j, names1, errorNames1, names2;
38 char **name1, **errorName1, **name2, **errorName2;
39
40 if (!names || !*name)
41 return 0;
42 name2 = errorName1 = errorName2 = NULL;
43 names2 = errorNames1 = 0;
44 for (i = 0; i < names; i++) {
45 switch (typeMode) {
46 case FIND_ANY_TYPE:
47 case FIND_NUMERIC_TYPE:
48 case FIND_INTEGER_TYPE:
49 case FIND_FLOATING_TYPE:
50 names1 = SDDS_MatchColumns(SDDSin, excludeNames ? NULL : &name1, SDDS_MATCH_STRING, typeMode,
51 (*name)[i], SDDS_0_PREVIOUS | SDDS_OR);
52 break;
53 case FIND_SPECIFIED_TYPE:
54 if (!SDDS_VALID_TYPE(typeValue))
55 SDDS_Bomb("invalid type value in expandColumnPairNames");
56 names1 = SDDS_MatchColumns(SDDSin, excludeNames ? NULL : &name1, SDDS_MATCH_STRING, typeMode, typeValue,
57 (*name)[i], SDDS_0_PREVIOUS | SDDS_OR);
58 break;
59 default:
60 SDDS_Bomb("invalid typeMode in expandColumnPairNames");
61 exit(1);
62 break;
63 }
64 if (names1 == 0)
65 continue;
66 if (names1 == -1) {
67 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
68 SDDS_Bomb("unable to perform column name match in expandColumnPairNames");
69 }
70
71 if (excludeNames) {
72 for (j = 0; j < excludeNames; j++)
73 if (!(names1 = SDDS_MatchColumns(SDDSin, (j == excludeNames - 1 ? &name1 : 0),
74 SDDS_MATCH_STRING, FIND_ANY_TYPE,
75 excludeName[j], SDDS_NEGATE_MATCH | SDDS_AND)))
76 break;
77 }
78 if (!names1)
79 continue;
80 moveToStringArray(&name2, &names2, name1, names1);
81 if (errorName && *errorName && (*errorName)[i]) {
82 if (strstr((*errorName)[i], "%s")) {
83 if (!(errorName1 = (char **)malloc(sizeof(*errorName1) * names1)))
84 SDDS_Bomb("allocation failure in expandColumnPairNames");
85 errorNames1 = names1;
86 for (j = 0; j < names1; j++) {
87 if (!(errorName1[j] = (char *)malloc(sizeof(**errorName1) *
88 strlen(name1[j]) +
89 strlen((*errorName)[i]) + 1)))
90 SDDS_Bomb("allocation failure in expandColumnPairNames");
91 replace_stringn(errorName1[j], (*errorName)[i], "%s", name1[j], 1);
92 if (SDDS_CheckColumn(SDDSin, errorName1[j], NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OKAY)
93 exit(1);
94 }
95 } else if (names1 == 1) {
96 errorNames1 = 1;
97 if (!(errorName1 = (char **)malloc(sizeof(*errorName1))))
98 SDDS_Bomb("allocation failure in expandColumnPairNames");
99 if (!SDDS_CopyString(errorName1, (*errorName)[i]))
100 return 0;
101 } else
102 SDDS_Bomb("%s template must be employed with error names when primary name has wildcards");
103 names2 -= names1;
104 moveToStringArray(&errorName2, &names2, errorName1, errorNames1);
105 free(errorName1);
106 free(name1);
107 }
108 }
109 if (names2 == 0)
110 return 0;
111 SDDS_FreeStringArray(*name, names);
112 *name = name2;
113 if (errorName) {
114 if (*errorName)
115 SDDS_FreeStringArray(*errorName, names);
116 *errorName = errorName2;
117 }
118 return names2;
119}
120
121void moveToStringArray(char ***target, long *targets, char **source, long sources) {
122 long i, j;
123 if (!sources)
124 return;
125 *target = SDDS_Realloc(*target, sizeof(**target) * (*targets + sources));
126 for (i = 0; i < sources; i++) {
127 for (j = 0; j < *targets; j++)
128 if (strcmp(source[i], (*target)[j]) == 0)
129 break;
130 if (j == *targets) {
131 (*target)[j] = source[i];
132 *targets += 1;
133 }
134 }
135}
136
137char *multiplyColumnUnits(SDDS_DATASET *SDDSin, char *name1, char *name2) {
138 char buffer[SDDS_MAXLINE];
139 char *units1, *units2;
140
141 if (SDDS_GetColumnInformation(SDDSin, "units", &units1, SDDS_GET_BY_NAME, name1) != SDDS_STRING ||
142 SDDS_GetColumnInformation(SDDSin, "units", &units2, SDDS_GET_BY_NAME, name2) != SDDS_STRING)
143 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
144 if (units1 && !SDDS_StringIsBlank(units1)) {
145 strcpy(buffer, units1);
146 free(units1);
147 units1 = NULL;
148 if (units2 && !SDDS_StringIsBlank(units2)) {
149 strcat(buffer, " ");
150 strcat(buffer, units2);
151 free(units2);
152 units2 = NULL;
153 }
154 } else if (units2 && !SDDS_StringIsBlank(units2)) {
155 strcpy(buffer, units2);
156 free(units2);
157 units2 = NULL;
158 } else
159 buffer[0] = 0;
160 if (units1)
161 free(units1);
162 if (units2)
163 free(units2);
164 SDDS_CopyString(&units1, buffer);
165 return units1;
166}
167
168char *divideColumnUnits(SDDS_DATASET *SDDSin, char *name1, char *name2) {
169 char buffer[SDDS_MAXLINE];
170 char *units1, *units2;
171
172 if (SDDS_GetColumnInformation(SDDSin, "units", &units1, SDDS_GET_BY_NAME, name1) != SDDS_STRING ||
173 SDDS_GetColumnInformation(SDDSin, "units", &units2, SDDS_GET_BY_NAME, name2) != SDDS_STRING)
174 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
175 if (units1 && !SDDS_StringIsBlank(units1)) {
176 strcpy(buffer, units1);
177 free(units1);
178 units1 = NULL;
179 if (units2 && !SDDS_StringIsBlank(units2)) {
180 strcat(buffer, "/(");
181 strcat(buffer, units2);
182 strcat(buffer, ")");
183 free(units2);
184 units2 = NULL;
185 }
186 } else if (units2 && !SDDS_StringIsBlank(units2)) {
187 strcpy(buffer, "1/(");
188 strcat(buffer, units2);
189 strcat(buffer, ")");
190 free(units2);
191 units2 = NULL;
192 } else
193 buffer[0] = 0;
194 if (units1)
195 free(units1);
196 if (units2)
197 free(units2);
198 SDDS_CopyString(&units1, buffer);
199 return units1;
200}
201
202long SDDS_CompareParameterValues(void *param1, void *param2, long type) {
203 double ddiff;
204 int64_t ldiff;
205 char cdiff;
206
207 switch (type) {
208 case SDDS_FLOAT:
209 ddiff = *((float *)param1) - *((float *)param2);
210 return ddiff < 0 ? -1 : ddiff > 0 ? 1 : 0;
211 case SDDS_DOUBLE:
212 ddiff = *((double *)param1) - *((double *)param2);
213 return ddiff < 0 ? -1 : ddiff > 0 ? 1 : 0;
214 case SDDS_LONG64:
215 ldiff = *((int64_t *)param1) - *((int64_t *)param2);
216 return ldiff < 0 ? -1 : ldiff > 0 ? 1 : 0;
217 case SDDS_LONG:
218 ldiff = *((int32_t *)param1) - *((int32_t *)param2);
219 return ldiff < 0 ? -1 : ldiff > 0 ? 1 : 0;
220 case SDDS_SHORT:
221 ldiff = *((short *)param1) - *((short *)param2);
222 return ldiff < 0 ? -1 : ldiff > 0 ? 1 : 0;
223 case SDDS_CHARACTER:
224 cdiff = (short)*((char *)param1) - (short)*((char *)param2);
225 return cdiff < 0 ? -1 : cdiff > 0 ? 1 : 0;
226 case SDDS_STRING:
227 return strcmp(*(char **)param1, *(char **)param2);
228 default:
229 SDDS_SetError("Problem doing data comparison--invalid data type (SDDS_CompareParameterValues)");
230 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
231 exit(1);
232 }
233}
234
235char *makeFrequencyUnits(SDDS_DATASET *SDDSin, char *indepName) {
236 char *timeUnits;
237 char *units;
238 long reciprocal = 0, end;
239
240 if (SDDS_GetColumnInformation(SDDSin, "units", &timeUnits, SDDS_GET_BY_NAME, indepName) != SDDS_STRING)
241 return 0;
242 if (timeUnits) {
243 while (1) {
244 end = strlen(timeUnits) - 1;
245 if (timeUnits[0] == '(' && timeUnits[end] == ')') {
246 timeUnits[end] = 0;
247 strslide(timeUnits, 1);
248 } else if (timeUnits[0] == '1' && timeUnits[1] == '/' && timeUnits[2] == '(' && timeUnits[end] == ')') {
249 timeUnits[end] = 0;
250 strslide(timeUnits, 3);
251 reciprocal = !reciprocal;
252 } else
253 break;
254 }
255 }
256 if (!timeUnits || SDDS_StringIsBlank(timeUnits)) {
257 units = tmalloc(sizeof(*units) * 1);
258 units[0] = 0;
259 return units;
260 }
261
262 if (reciprocal) {
263 if (!SDDS_CopyString(&units, timeUnits))
264 return NULL;
265 return units;
266 }
267
268 units = tmalloc(sizeof(*units) * (strlen(timeUnits) + 5));
269 if (strchr(timeUnits, ' '))
270 sprintf(units, "1/(%s)", timeUnits);
271 else
272 sprintf(units, "1/%s", timeUnits);
273 return units;
274}
275
276#define MAXPRIMES 25
277int64_t greatestProductOfSmallPrimes(int64_t rows)
278/* doesn't really find the greatest product, but simply a large one */
279{
280 int64_t bestResult = 0, result, nPrimes;
281 static int64_t prime[MAXPRIMES] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67,
282 71, 73, 79, 83, 89, 97};
283
284 for (nPrimes = 1; nPrimes <= MAXPRIMES; nPrimes++) {
285 if ((result = greatestProductOfSmallPrimes1(rows, prime, nPrimes)) > bestResult &&
286 result <= rows)
287 bestResult = result;
288 }
289 if (bestResult == 0)
290 SDDS_Bomb("couldn't find acceptable number of rows for truncation/padding");
291 return bestResult;
292}
293
294int64_t greatestProductOfSmallPrimes1(int64_t rows, int64_t *primeList, int64_t nPrimes) {
295 int64_t iprime, product, remains, bestFactor = 0;
296 double remainder, smallestRemainder;
297
298 remains = rows;
299 product = 1;
300 while (remains > 2) {
301 smallestRemainder = LONG_MAX;
302 for (iprime = 0; iprime < nPrimes; iprime++) {
303 remainder = remains - primeList[iprime] * ((long)(remains / primeList[iprime]));
304 if (remainder < smallestRemainder) {
305 smallestRemainder = remainder;
306 bestFactor = primeList[iprime];
307 }
308 if (remainder == 0)
309 break;
310 }
311 remains /= bestFactor;
312 product *= bestFactor;
313 }
314 return product * remains;
315}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
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
int32_t SDDS_FreeStringArray(char **string, int64_t strings)
Frees an array of strings by deallocating each individual string.
void SDDS_SetError(char *error_text)
Records an error message in the SDDS error stack.
Definition SDDS_utils.c:379
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.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
Definition SDDS_utils.c:432
int32_t SDDS_StringIsBlank(char *s)
Checks if a string is blank (contains only whitespace characters).
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.
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
Definition SDDS_utils.c:342
int32_t SDDS_CopyString(char **target, const char *source)
Copies a source string to a target string with memory allocation.
Definition SDDS_utils.c:856
void * SDDS_Realloc(void *old_ptr, size_t new_size)
Reallocates memory to a new size.
Definition SDDS_utils.c:677
#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_LONG
Identifier for the signed 32-bit integer data type.
Definition SDDStypes.h:61
#define SDDS_SHORT
Identifier for the signed short integer data type.
Definition SDDStypes.h:73
#define SDDS_CHARACTER
Identifier for the character data type.
Definition SDDStypes.h:91
#define SDDS_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_LONG64
Identifier for the signed 64-bit integer data type.
Definition SDDStypes.h:49
Utility functions for SDDS dataset manipulation and string array operations.
void * tmalloc(uint64_t size_of_block)
Allocates a memory block of the specified size with zero initialization.
Definition array.c:59
int replace_stringn(char *t, char *s, char *orig, char *repl, long count_limit)
Replace a limited number of occurrences of one string with another string.
char * strslide(char *s, long distance)
Slides character data within a string by a specified distance.
Definition strslide.c:32