SDDSlib
Loading...
Searching...
No Matches
data_scan.c
Go to the documentation of this file.
1/**
2 * @file data_scan.c
3 * @brief Provides functions for scanning and parsing free-format data.
4 *
5 * This file contains functions such as get_double(), get_float(), get_long(),
6 * get_token(), and get_token_buf() to facilitate easy scanning and parsing of
7 * numerical and token-based data from strings.
8 *
9 * @copyright
10 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
11 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
12 *
13 * @license
14 * This file is distributed under the terms of the Software License Agreement
15 * found in the file LICENSE included with this distribution.
16 *
17 * @author M. Borland, C. Saunders, R. Soliday, H. Shang
18 */
19
20#include "mdb.h"
21#include <ctype.h>
22
23#define float_start(m_c) (isdigit(*(m_c)) || *(m_c) == '.' || ((*(m_c) == '-' || *(m_c) == '+') && (isdigit(*((m_c) + 1)) || *((m_c) + 1) == '.')))
24#define int_start(m_c) (isdigit(*(m_c)) || ((*(m_c) == '-' || *(m_c) == '+') && isdigit(*((m_c) + 1))))
25
26#define skip_it(m_c) (isspace(m_c) || (m_c) == ',' || (m_c) == ';')
27#define nskip_it(m_c) (!isspace(m_c) && (m_c) != ',' && (m_c) != ';')
28
29/**
30 * @brief Parses a double value from the given string.
31 *
32 * This function scans the input string for a valid double-precision floating-point
33 * number, stores the result in the provided pointer, and updates the string pointer
34 * to the position following the parsed number.
35 *
36 * @param[out] dptr Pointer to store the parsed double value.
37 * @param[in,out] s Input string to scan. It will be modified to point after the parsed number.
38 * @return Returns 1 if a double was successfully parsed, 0 otherwise.
39 */
40int get_double(double *dptr, char *s) {
41 register char *ptr0;
42 register int was_point = 0;
43
44 /* skip leading non-number characters */
45 ptr0 = s;
46 while (!float_start(s) && *s)
47 s++;
48 if (*s == 0)
49 return (0);
50
51 /* scan the number */
52 sscanf(s, "%lf", dptr);
53
54 /* skip to first white-space following number */
55
56 /* skip sign, if any */
57 if (*s == '-' || *s == '+')
58 s++;
59
60 /* skip mantissa */
61 while (isdigit(*s) || (*s == '.' && !was_point))
62 if (*s++ == '.')
63 was_point = 1;
64
65 if (*s == 'e' || *s == 'E') { /* skip exponent, if any */
66 s++;
67 if (*s == '+' || *s == '-')
68 s++;
69 while (isdigit(*s))
70 s++;
71 }
72
73 strcpy_ss(ptr0, s);
74 return (1);
75}
76
77/**
78 * @brief Parses a long double value from the given string.
79 *
80 * This function scans the input string for a valid long double floating-point number,
81 * stores the result in the provided pointer, and updates the string pointer to the
82 * position following the parsed number.
83 *
84 * @param[out] dptr Pointer to store the parsed long double value.
85 * @param[in,out] s Input string to scan. It will be modified to point after the parsed number.
86 * @return Returns 1 if a long double was successfully parsed, 0 otherwise.
87 */
88int get_longdouble(long double *dptr, char *s) {
89 register char *ptr0;
90 register int was_point = 0;
91
92 /* skip leading non-number characters */
93 ptr0 = s;
94 while (!float_start(s) && *s)
95 s++;
96 if (*s == 0)
97 return (0);
98 /* scan the number */
99 sscanf(s, "%Lf", dptr);
100 /* skip to first white-space following number */
101
102 /* skip sign, if any */
103 if (*s == '-' || *s == '+')
104 s++;
105
106 /* skip mantissa */
107 while (isdigit(*s) || (*s == '.' && !was_point))
108 if (*s++ == '.')
109 was_point = 1;
110
111 if (*s == 'e' || *s == 'E') { /* skip exponent, if any */
112 s++;
113 if (*s == '+' || *s == '-')
114 s++;
115 while (isdigit(*s))
116 s++;
117 }
118 strcpy_ss(ptr0, s);
119 return (1);
120}
121
122/**
123 * @brief Parses a double value from the given string without modifying the string.
124 *
125 * This function scans the input string for a valid double-precision floating-point
126 * number, stores the result in the provided pointer, and ensures that the string remains
127 * unchanged after parsing.
128 *
129 * @param[out] dptr Pointer to store the parsed double value.
130 * @param[in] s Input string to scan. It remains unchanged after parsing.
131 * @return Returns 1 if a double was successfully parsed, 0 otherwise.
132 */
133int get_double1(double *dptr, char *s) {
134 char *endptr;
135 double val;
136
137 if (s == NULL || *s == '\0')
138 return 0;
139
140 // Remove trailing whitespace
141 char *p = s + strlen(s) - 1;
142 while (p >= s && isspace((unsigned char)*p))
143 p--;
144 *(p + 1) = '\0';
145
146 // Start from the beginning and try to find a number that ends at the end of the string
147 char *start = s;
148 while (*start) {
149 val = strtod(start, &endptr);
150
151 if (endptr != start) {
152 // Check if we've reached the end of the string
153 if (*endptr == '\0') {
154 *dptr = val;
155 return 1;
156 }
157 }
158 start++;
159 }
160 return 0;
161}
162
163int get_double1_old(double *dptr, char *s) {
164 register int was_point = 0;
165
166 /* skip leading non-number characters */
167 while (!float_start(s) && *s)
168 s++;
169 if (*s == 0)
170 return (0);
171
172 /* scan the number */
173 sscanf(s, "%lf", dptr);
174
175 /* skip to first white-space following number */
176
177 /* skip sign, if any */
178 if (*s == '-' || *s == '+')
179 s++;
180
181 /* skip mantissa */
182 while (isdigit(*s) || (*s == '.' && !was_point))
183 if (*s++ == '.')
184 was_point = 1;
185
186 if (*s == 'e' || *s == 'E') { /* skip exponent, if any */
187 s++;
188 if (*s == '+' || *s == '-')
189 s++;
190 while (isdigit(*s))
191 s++;
192 }
193
194 return (1);
195}
196
197/**
198 * @brief Parses a float value from the given string.
199 *
200 * This function scans the input string for a valid single-precision floating-point
201 * number, stores the result in the provided pointer, and updates the string pointer to the
202 * position following the parsed number.
203 *
204 * @param[out] fptr Pointer to store the parsed float value.
205 * @param[in,out] s Input string to scan. It will be modified to point after the parsed number.
206 * @return Returns 1 if a float was successfully parsed, 0 otherwise.
207 */
208int get_float(float *fptr, char *s) {
209 register char *ptr0;
210 register int was_point = 0;
211
212 /* skip leading non-number characters */
213 ptr0 = s;
214 while (!float_start(s) && *s)
215 s++;
216 if (*s == 0)
217 return (0);
218
219 /* scan the number */
220 sscanf(s, "%f", fptr);
221
222 /* skip to first white-space following number */
223
224 /* skip sign, if any */
225 if (*s == '-' || *s == '+')
226 s++;
227
228 /* skip mantissa */
229 while (isdigit(*s) || (*s == '.' && !was_point))
230 if (*s++ == '.')
231 was_point = 1;
232
233 if (*s == 'e' || *s == 'E') { /* skip exponent, if any */
234 s++;
235 if (*s == '+' || *s == '-')
236 s++;
237 while (isdigit(*s))
238 s++;
239 }
240
241 strcpy_ss(ptr0, s);
242 return (1);
243}
244
245/**
246 * @brief Parses a long integer value from the given string.
247 *
248 * This function scans the input string for a valid long integer, stores the result in the
249 * provided pointer, and updates the string pointer to the position following the parsed number.
250 *
251 * @param[out] iptr Pointer to store the parsed long integer value.
252 * @param[in,out] s Input string to scan. It will be modified to point after the parsed number.
253 * @return Returns 1 if a long integer was successfully parsed, 0 otherwise.
254 */
255int get_long(long *iptr, char *s) {
256 char *ptr0;
257
258 /* skip leading white-space and commas */
259 ptr0 = s;
260 while (!int_start(s) && *s)
261 s++;
262 if (*s == 0)
263 return (0);
264
265 /* scan the number */
266 sscanf(s, "%ld", iptr);
267
268 /* skip to first white-space following number */
269 if (*s == '-' || *s == '+')
270 s++;
271 while (isdigit(*s))
272 s++;
273
274 strcpy_ss(ptr0, s);
275 return (1);
276}
277
278/**
279 * @brief Parses a long integer value from the given string without modifying the string.
280 *
281 * This function scans the input string for a valid long integer, stores the result in the
282 * provided pointer, and ensures that the string remains unchanged after parsing.
283 *
284 * @param[out] lptr Pointer to store the parsed long integer value.
285 * @param[in] s Input string to scan. It remains unchanged after parsing.
286 * @return Returns 1 if a long integer was successfully parsed, 0 otherwise.
287 */
288int get_long1(long *lptr, char *s) {
289 char *endptr;
290 long val;
291
292 if (s == NULL || *s == '\0')
293 return 0;
294
295 // Remove trailing whitespace
296 char *p = s + strlen(s) - 1;
297 while (p >= s && isspace((unsigned char)*p))
298 p--;
299 *(p + 1) = '\0';
300
301 // Start from the beginning and try to find a number that ends at the end of the string
302 char *start = s;
303 while (*start) {
304 val = strtol(start, &endptr, 10); // Base 10
305
306 if (endptr != start) {
307 // Check if we've reached the end of the string
308 if (*endptr == '\0') {
309 *lptr = val;
310 return 1;
311 }
312 }
313 start++;
314 }
315 return 0;
316}
317
318int get_long1_old(long *iptr, char *s) {
319
320 /* skip leading white-space and commas */
321 while (!int_start(s) && *s)
322 s++;
323 if (*s == 0)
324 return (0);
325
326 /* scan the number */
327 sscanf(s, "%ld", iptr);
328
329 /* skip to first white-space following number */
330 if (*s == '-' || *s == '+')
331 s++;
332 while (isdigit(*s))
333 s++;
334 return (1);
335}
336
337/**
338 * @brief Parses a short integer value from the given string.
339 *
340 * This function scans the input string for a valid short integer, stores the result in the
341 * provided pointer, and updates the string pointer to the position following the parsed number.
342 *
343 * @param[out] iptr Pointer to store the parsed short integer value.
344 * @param[in,out] s Input string to scan. It will be modified to point after the parsed number.
345 * @return Returns 1 if a short integer was successfully parsed, 0 otherwise.
346 */
347int get_short(short *iptr, char *s) {
348 char *ptr0;
349
350 /* skip leading white-space and commas */
351 ptr0 = s;
352 while (!int_start(s) && *s)
353 s++;
354 if (*s == 0)
355 return (0);
356
357 /* scan the number */
358 sscanf(s, "%hd", iptr);
359
360 /* skip to first white-space following number */
361 if (*s == '-' || *s == '+')
362 s++;
363 while (isdigit(*s))
364 s++;
365
366 strcpy_ss(ptr0, s);
367 return (1);
368}
369
370/**
371 * @brief Parses an integer value from the given string.
372 *
373 * This function scans the input string for a valid integer, stores the result in the
374 * provided pointer, and updates the string pointer to the position following the parsed number.
375 *
376 * @param[out] iptr Pointer to store the parsed integer value.
377 * @param[in,out] s Input string to scan. It will be modified to point after the parsed number.
378 * @return Returns 1 if an integer was successfully parsed, 0 otherwise.
379 */
380int get_int(int *iptr, char *s) {
381 char *ptr0;
382
383 /* skip leading white-space and commas */
384 ptr0 = s;
385 while (!int_start(s) && *s)
386 s++;
387 if (*s == 0)
388 return (0);
389
390 /* scan the number */
391 sscanf(s, "%d", iptr);
392
393 /* skip to first white-space following number */
394 if (*s == '-' || *s == '+')
395 s++;
396 while (isdigit(*s))
397 s++;
398
399 strcpy_ss(ptr0, s);
400 return (1);
401}
402
403/**
404 * @brief Extracts the next token from the input string.
405 *
406 * This function scans the input string for the next token, which can be a quoted string
407 * or a sequence of non-separator characters. It allocates memory for the token, copies it
408 * to the allocated space, and updates the input string pointer to the position following the token.
409 *
410 * @param[in,out] s Input string to scan. It will be modified to point after the extracted token.
411 * @return Returns a pointer to the newly allocated token string, or NULL if no token is found.
412 */
413char *get_token(char *s) {
414 char *ptr0, *ptr1, *ptr;
415
416 /* skip leading white-space and commas */
417 ptr0 = s;
418 while (skip_it(*s))
419 s++;
420 if (*s == 0)
421 return (NULL);
422 ptr1 = s;
423
424 if (*s == '"' && (ptr0 == s || *(s - 1) != '\\')) {
425 ptr1 = s + 1;
426 /* quoted string, so skip to next quotation mark */
427 do {
428 s++;
429 } while (*s && (*s != '"' || *(s - 1) == '\\'));
430 if (*s == '"' && *(s - 1) != '\\')
431 *s = ' ';
432 } else {
433 /* skip to first white-space following token */
434 do {
435 s++;
436 if (*s == '"' && *(s - 1) != '\\') {
437 while (*++s && (*s != '"' || *(s - 1) == '\\'))
438 ;
439 }
440 } while (*s && nskip_it(*s));
441 }
442
443 ptr = tmalloc((unsigned)sizeof(*ptr) * (s - ptr1 + 1));
444 strncpy(ptr, ptr1, s - ptr1);
445 ptr[s - ptr1] = 0;
446
447 strcpy_ss(ptr0, s);
448 return (ptr);
449}
450
451/**
452 * @brief Extracts the next token from the input string into a provided buffer.
453 *
454 * This function scans the input string for the next token, which can be a quoted string
455 * or a sequence of non-separator characters. It copies the token into the provided buffer
456 * if it fits, and updates the input string pointer to the position following the token.
457 *
458 * @param[in,out] s Input string to scan. It will be modified to point after the extracted token.
459 * @param[out] buf Buffer to store the extracted token.
460 * @param[in] lbuf Length of the buffer to prevent overflow.
461 * @return Returns a pointer to the buffer containing the token, or NULL if no token is found.
462 */
463char *get_token_buf(char *s, char *buf, long lbuf) {
464 char *ptr0, *ptr1;
465
466 /* skip leading white-space and commas */
467 ptr0 = s;
468 while (skip_it(*s))
469 s++;
470 if (*s == 0)
471 return (NULL);
472 ptr1 = s;
473
474 if (*s == '"') {
475 ptr1 = s + 1;
476 /* if quoted string, skip to next quotation mark */
477 do {
478 s++;
479 } while (*s != '"' && *s);
480 if (*s == '"')
481 *s = ' ';
482 } else {
483 /* skip to first white-space following token */
484 do {
485 s++;
486 } while (*s && nskip_it(*s));
487 }
488
489 if ((s - ptr1 + 1) > lbuf) {
490 printf("buffer overflow in get_token_buf()\nstring was %s\n", ptr0);
491 exit(1);
492 }
493 strncpy(buf, ptr1, s - ptr1);
494 buf[s - ptr1] = 0;
495
496 strcpy_ss(ptr0, s);
497 return (buf);
498}
499
500/**
501 * @brief Checks if the given token represents a valid integer.
502 *
503 * This function verifies whether the input token string is a valid integer, which may
504 * include an optional leading '+' or '-' sign followed by digits.
505 *
506 * @param[in] token The token string to check.
507 * @return Returns a non-zero value if the token is a valid integer, 0 otherwise.
508 */
509long tokenIsInteger(char *token) {
510 if (!isdigit(*token) && *token != '-' && *token != '+')
511 return 0;
512 if (!isdigit(*token) && !isdigit(*(token + 1)))
513 return 0;
514 token++;
515 while (*token)
516 if (!isdigit(*token++))
517 return 0;
518 return 1;
519}
520
521/**
522 * @brief Checks if the given token represents a valid number.
523 *
524 * This function verifies whether the input token string is a valid numerical value,
525 * which may include integers, floating-point numbers, and numbers in exponential notation.
526 *
527 * @param[in] token The token string to check.
528 * @return Returns a non-zero value if the token is a valid number, 0 otherwise.
529 */
530long tokenIsNumber(char *token) {
531 long pointSeen, digitSeen;
532
533 if (!(digitSeen = isdigit(*token)) && *token != '-' && *token != '+' && *token != '.')
534 return 0;
535 pointSeen = *token == '.';
536 token++;
537
538 while (*token) {
539 if (isdigit(*token)) {
540 digitSeen = 1;
541 token++;
542 } else if (*token == '.') {
543 if (pointSeen)
544 return 0;
545 pointSeen = 1;
546 token++;
547 } else if (*token == 'e' || *token == 'E') {
548 if (!digitSeen)
549 return 0;
550 return tokenIsInteger(token + 1);
551 } else
552 return 0;
553 }
554 return digitSeen;
555}
void * tmalloc(uint64_t size_of_block)
Allocates a memory block of the specified size with zero initialization.
Definition array.c:59
int get_short(short *iptr, char *s)
Parses a short integer value from the given string.
Definition data_scan.c:347
int get_longdouble(long double *dptr, char *s)
Parses a long double value from the given string.
Definition data_scan.c:88
int get_long(long *iptr, char *s)
Parses a long integer value from the given string.
Definition data_scan.c:255
int get_long1(long *lptr, char *s)
Parses a long integer value from the given string without modifying the string.
Definition data_scan.c:288
int get_double(double *dptr, char *s)
Parses a double value from the given string.
Definition data_scan.c:40
long tokenIsNumber(char *token)
Checks if the given token represents a valid number.
Definition data_scan.c:530
int get_double1(double *dptr, char *s)
Parses a double value from the given string without modifying the string.
Definition data_scan.c:133
int get_float(float *fptr, char *s)
Parses a float value from the given string.
Definition data_scan.c:208
int get_int(int *iptr, char *s)
Parses an integer value from the given string.
Definition data_scan.c:380
char * get_token_buf(char *s, char *buf, long lbuf)
Extracts the next token from the input string into a provided buffer.
Definition data_scan.c:463
char * get_token(char *s)
Extracts the next token from the input string.
Definition data_scan.c:413
long tokenIsInteger(char *token)
Checks if the given token represents a valid integer.
Definition data_scan.c:509
char * strcpy_ss(char *dest, const char *src)
Safely copies a string, handling memory overlap.
Definition str_copy.c:34