SDDSlib
Loading...
Searching...
No Matches
scanitemlist.c
Go to the documentation of this file.
1/**
2 * @file scanitemlist.c
3 * @brief This file contains functions for scanning and parsing item lists with various data types.
4 *
5 * @copyright
6 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
7 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
8 *
9 * @license
10 * This file is distributed under the terms of the Software License Agreement
11 * found in the file LICENSE included with this distribution.
12 *
13 * @author M. Borland, C. Saunders, R. Soliday, H. Shang
14 */
15
16#include "mdb.h"
17#include "scan.h"
18#include "match_string.h"
19#include <stdarg.h>
20#if defined(vxWorks)
21# include "epicsStdlib.h"
22#endif
23
24/**
25 * @brief Scans a list of items and assigns values based on provided keywords and types.
26 *
27 * This function processes a list of item strings, each potentially in the format "keyword=value",
28 * and assigns the corresponding values to provided data pointers based on specified SDDS types.
29 * It supports setting flags and handles various data types as specified in the variable arguments.
30 *
31 * @param flags Pointer to an unsigned long variable where flags will be set based on matched items.
32 * @param item Array of strings containing items to be scanned, each in the format "keyword=value" or "keyword".
33 * @param items Pointer to a long variable indicating the number of items in the `item` array.
34 * It will be updated based on the scanning process.
35 * @param mode Unsigned long value specifying the scanning mode, used for future expansion and controlling behavior.
36 * @param ... Variable arguments specifying pairs of <keyword>, <SDDS-type>, <pointer>, <number-required>, <set-flag>, etc.,
37 * ending with NULL.
38 *
39 * @return Returns 1 on successful scanning and parsing of items, or 0 on failure.
40 */
41long scanItemList(unsigned long *flags, char **item, long *items, unsigned long mode, ...)
42{
43 va_list argptr;
44 long i, j, type, flag, retval, length, number, match;
45 char *keyword;
46 void *data;
47 static char **valueptr = NULL;
48 static long *keylength = NULL;
49 static short *item_matched = NULL, *has_equals = NULL;
50 static long maxitems = 0;
51
52 if (!flags)
53 return bombre("null flags pointer seen (scanItemList)", NULL, 0);
54 if (!item)
55 return bombre("null item pointer seen (scanItemList)", NULL, 0);
56 if (!items)
57 return bombre("null items pointer seen (scanItemList)", NULL, 0);
58 if (*items <= 0) {
59 *flags = 0;
60 return 1;
61 }
62 if (*items > maxitems) {
63 valueptr = trealloc(valueptr, sizeof(*valueptr) * (maxitems = *items));
64 keylength = trealloc(keylength, sizeof(*keylength) * maxitems);
65 item_matched = trealloc(item_matched, sizeof(*item_matched) * maxitems);
66 has_equals = trealloc(has_equals, sizeof(*has_equals) * maxitems);
67 }
68 *flags = 0;
69 for (i = 0; i < *items; i++) {
70 item_matched[i] = 0;
71#if DEBUG
72 fprintf(stderr, "item %ld: %s\n", i, item[i]);
73#endif
74 if ((valueptr[i] = strchr(item[i], '='))) {
75 if ((keylength[i] = valueptr[i] - item[i]) <= 0)
76 return bombre("zero-length keyword seen (scanItemList)", NULL, 0);
77 *valueptr[i]++ = 0;
78 has_equals[i] = 1;
79 } else {
80 keylength[i] = strlen(item[i]);
81 has_equals[i] = 0;
82 }
83
84#if DEBUG
85 fprintf(stderr, " keyword: %s valueptr: %s\n", item[i], valueptr[i]);
86#endif
87 }
88
89 va_start(argptr, mode);
90 retval = 1;
91 do {
92 if (!(keyword = va_arg(argptr, char *)))
93 break;
94 type = va_arg(argptr, int32_t);
95 data = va_arg(argptr, void *);
96 number = va_arg(argptr, int32_t);
97 flag = va_arg(argptr, uint32_t);
98 length = strlen(keyword);
99 match = -1;
100 for (i = 0; i < *items; i++)
101 if (strncmp_case_insensitive(item[i], keyword, MIN(length, keylength[i])) == 0) {
102 if (match != -1) {
103 fprintf(stderr, "ambiguous item %s seen\n", keyword);
104 retval = 0;
105 }
106 match = i;
107 }
108#if defined(DEBUG)
109 if (match != -1)
110 fprintf(stderr, "keyword %s and item %ld (%s) match\n", keyword, match, item[match]);
111 else
112 fprintf(stderr, "no match for keyword %s\n", keyword);
113#endif
114 if (!retval)
115 break;
116 if (match == -1)
117 continue;
118 if (!has_equals[match] && number && mode & SCANITEMLIST_IGNORE_VALUELESS)
119 continue;
120 if (item_matched[match]) {
121 fprintf(stderr, "error: ambiguous qualifier %s seen\n", item[match]);
122 retval = 0;
123 break;
124 }
125 item_matched[match] = 1;
126 *flags |= flag;
127 if (!valueptr[match]) {
128 if (type == -1)
129 continue;
130 fprintf(stderr, "error: value not given for %s\n", keyword);
131 retval = 0;
132 break;
133 }
134 switch (type) {
135 case SDDS_LONGDOUBLE:
136#if defined(vxWorks)
137 fprintf(stderr, "error: SDDS_LONGDOUBLE is not supported on vxWorks yet\n");
138 return 0;
139#else
140 *((long double *)data) = (long double)strtold(valueptr[match], NULL);
141#endif
142 break;
143 case SDDS_DOUBLE:
144 *((double *)data) = atof(valueptr[match]);
145 break;
146 case SDDS_FLOAT:
147 *((float *)data) = (float)atof(valueptr[match]);
148 break;
149 case SDDS_LONG64:
150#if defined(vxWorks)
151 epicsParseInt64(valueptr[match], (int64_t *)data, 10, NULL);
152#else
153 *((int64_t *)data) = (uint64_t)atoll(valueptr[match]);
154#endif
155 break;
156 case SDDS_ULONG64:
157 *((uint64_t *)data) = (uint64_t)strtoull(valueptr[match], NULL, 10);
158 break;
159 case SDDS_LONG:
160 *((int32_t *)data) = (int32_t)atol(valueptr[match]);
161 break;
162 case SDDS_ULONG:
163 *((uint32_t *)data) = (uint32_t)strtoul(valueptr[match], NULL, 10);
164 break;
165 case SDDS_SHORT:
166 *((short *)data) = (short)atol(valueptr[match]);
167 break;
168 case SDDS_USHORT:
169 *((unsigned short *)data) = (unsigned short)atol(valueptr[match]);
170 break;
171 case SDDS_STRING:
172 cp_str((char **)data, valueptr[match]);
173 break;
174 case SDDS_CHARACTER:
175 *((char *)data) = valueptr[match][0];
176 break;
177 default:
178 fprintf(stderr, "Error: value not accepted for qualifier %s\n",
179 item[match]);
180 break;
181 }
182 } while (retval == 1);
183 va_end(argptr);
184 for (i = 0; i < *items; i++) {
185 if (!item_matched[i]) {
186 if (!has_equals[i] && mode & SCANITEMLIST_UNKNOWN_VALUE_OK)
187 continue;
188 if (has_equals[i] && mode & SCANITEMLIST_UNKNOWN_KEYVALUE_OK)
189 continue;
190 fprintf(stderr, "unknown keyword/value given: %s\n", item[i]);
191 return 0;
192 }
193 }
194 if (mode & SCANITEMLIST_REMOVE_USED_ITEMS) {
195 for (i = j = 0; i < *items; i++) {
196 if (!item_matched[i]) {
197 if (i != j) {
198 item_matched[j] = 1;
199 item[j] = item[i];
200 }
201 j++;
202 }
203 }
204 *items = j;
205 }
206 return retval;
207}
208
209/**
210 * @brief Scans a list of items with extended flag support and assigns values based on provided keywords and types.
211 *
212 * This function is similar to `scanItemList` but uses an `unsigned long long` for flags,
213 * allowing for a larger set of flags. It processes a list of item strings, assigns values based on SDDS types,
214 * and supports various scanning modes.
215 *
216 * @param flags Pointer to an unsigned long long variable where flags will be set based on matched items.
217 * @param item Array of strings containing items to be scanned, each in the format "keyword=value" or "keyword".
218 * @param items Pointer to a long variable indicating the number of items in the `item` array.
219 * It will be updated based on the scanning process.
220 * @param mode Unsigned long value specifying the scanning mode, used for future expansion and controlling behavior.
221 * @param ... Variable arguments specifying pairs of <keyword>, <SDDS-type>, <pointer>, <number-required>, <set-flag>, etc.,
222 * ending with NULL.
223 *
224 * @return Returns 1 on successful scanning and parsing of items, or 0 on failure.
225 */
226long scanItemListLong(unsigned long long *flags, char **item, long *items, unsigned long mode, ...)
227{
228 va_list argptr;
229 long i, j, type, retval, length, number, match;
230 long long flag;
231 char *keyword;
232 void *data;
233 static char **valueptr = NULL;
234 static long *keylength = NULL;
235 static short *item_matched = NULL, *has_equals = NULL;
236 static long maxitems = 0;
237
238 if (!flags)
239 return bombre("null flags pointer seen (scanItemList)", NULL, 0);
240 if (!item)
241 return bombre("null item pointer seen (scanItemList)", NULL, 0);
242 if (!items)
243 return bombre("null items pointer seen (scanItemList)", NULL, 0);
244 if (*items <= 0) {
245 *flags = 0;
246 return 1;
247 }
248 if (*items > maxitems) {
249 valueptr = trealloc(valueptr, sizeof(*valueptr) * (maxitems = *items));
250 keylength = trealloc(keylength, sizeof(*keylength) * maxitems);
251 item_matched = trealloc(item_matched, sizeof(*item_matched) * maxitems);
252 has_equals = trealloc(has_equals, sizeof(*has_equals) * maxitems);
253 }
254 *flags = 0;
255 for (i = 0; i < *items; i++) {
256 item_matched[i] = 0;
257#if DEBUG
258 fprintf(stderr, "item %ld: %s\n", i, item[i]);
259#endif
260 if ((valueptr[i] = strchr(item[i], '='))) {
261 if ((keylength[i] = valueptr[i] - item[i]) <= 0)
262 return bombre("zero-length keyword seen (scanItemList)", NULL, 0);
263 *valueptr[i]++ = 0;
264 has_equals[i] = 1;
265 } else {
266 keylength[i] = strlen(item[i]);
267 has_equals[i] = 0;
268 }
269
270#if DEBUG
271 fprintf(stderr, " keyword: %s valueptr: %s\n", item[i], valueptr[i]);
272#endif
273 }
274
275 va_start(argptr, mode);
276 retval = 1;
277 do {
278 if (!(keyword = va_arg(argptr, char *)))
279 break;
280 type = va_arg(argptr, int32_t);
281 data = va_arg(argptr, void *);
282 number = va_arg(argptr, int32_t);
283 flag = va_arg(argptr, uint64_t);
284 length = strlen(keyword);
285 match = -1;
286 for (i = 0; i < *items; i++)
287 if (strncmp_case_insensitive(item[i], keyword, MIN(length, keylength[i])) == 0) {
288 if (match != -1) {
289 fprintf(stderr, "ambiguous item %s seen\n", keyword);
290 retval = 0;
291 }
292 match = i;
293 }
294#if defined(DEBUG)
295 if (match != -1)
296 fprintf(stderr, "keyword %s and item %ld (%s) match\n", keyword, match, item[match]);
297 else
298 fprintf(stderr, "no match for keyword %s\n", keyword);
299#endif
300 if (!retval)
301 break;
302 if (match == -1)
303 continue;
304 if (!has_equals[match] && number && mode & SCANITEMLIST_IGNORE_VALUELESS)
305 continue;
306 if (item_matched[match]) {
307 fprintf(stderr, "error: ambiguous qualifier %s seen\n", item[match]);
308 retval = 0;
309 break;
310 }
311 item_matched[match] = 1;
312 *flags |= flag;
313 if (!valueptr[match]) {
314 if (type == -1)
315 continue;
316 fprintf(stderr, "error: value not given for %s\n", keyword);
317 retval = 0;
318 break;
319 }
320 switch (type) {
321 case SDDS_DOUBLE:
322 *((double *)data) = atof(valueptr[match]);
323 break;
324 case SDDS_FLOAT:
325 *((float *)data) = (float)atof(valueptr[match]);
326 break;
327 case SDDS_LONG:
328 *((int32_t *)data) = atol(valueptr[match]);
329 break;
330 case SDDS_ULONG:
331#if defined(_WIN32)
332 *((uint32_t *)data) = (uint32_t)_atoi64(valueptr[match]);
333#else
334# if defined(vxWorks)
335 epicsParseUInt32(valueptr[match], (uint32_t *)data, 10, NULL);
336# else
337 *((uint32_t *)data) = (uint32_t)atoll(valueptr[match]);
338# endif
339#endif
340 break;
341 case SDDS_SHORT:
342 *((short *)data) = (short)atol(valueptr[match]);
343 break;
344 case SDDS_USHORT:
345 *((unsigned short *)data) = (unsigned short)atol(valueptr[match]);
346 break;
347 case SDDS_STRING:
348 cp_str((char **)data, valueptr[match]);
349 break;
350 case SDDS_CHARACTER:
351 *((char *)data) = valueptr[match][0];
352 break;
353 default:
354 fprintf(stderr, "Error: value not accepted for qualifier %s\n",
355 item[match]);
356 break;
357 }
358 } while (retval == 1);
359 va_end(argptr);
360 for (i = 0; i < *items; i++) {
361 if (!item_matched[i]) {
362 if (!has_equals[i] && mode & SCANITEMLIST_UNKNOWN_VALUE_OK)
363 continue;
364 if (has_equals[i] && mode & SCANITEMLIST_UNKNOWN_KEYVALUE_OK)
365 continue;
366 fprintf(stderr, "unknown keyword/value given: %s\n", item[i]);
367 return 0;
368 }
369 }
370 if (mode & SCANITEMLIST_REMOVE_USED_ITEMS) {
371 for (i = j = 0; i < *items; i++) {
372 if (!item_matched[i]) {
373 if (i != j) {
374 item_matched[j] = 1;
375 item[j] = item[i];
376 }
377 j++;
378 }
379 }
380 *items = j;
381 }
382 return retval;
383}
384
385/**
386 * @brief Scans a list of items without flag extension and assigns values based on provided keywords and types.
387 *
388 * This version of the scanning function lacks certain functionalities such as flag extension
389 * and may not flag entries that don't match any keywords. It is used in various locations within the codebase.
390 *
391 * @param flags Pointer to an unsigned long variable where flags will be set based on matched items.
392 * @param item Array of strings containing items to be scanned, each in the format "keyword=value" or "keyword".
393 * @param items Pointer to a long variable indicating the number of items in the `item` array.
394 * It will be updated based on the scanning process.
395 * @param ... Variable arguments specifying pairs of <keyword>, <SDDS-type>, <pointer>, <number-required>, <set-flag>, etc.,
396 * ending with NULL.
397 *
398 * @return Returns 1 on successful scanning and parsing of items, or 0 on failure.
399 */
400long scan_item_list(unsigned long *flags, char **item, long *items, ...)
401{
402 va_list argptr;
403 long i, j, type, flag, retval, length, match;
404 //long number;
405 char *keyword;
406 void *data;
407 static char **valueptr = NULL;
408 static long *keylength = NULL, *item_matched = NULL;
409 static long maxitems = 0;
410
411 if (!flags)
412 return bombre("null flags pointer seen (scan_item_list)", NULL, 0);
413 if (!item)
414 return bombre("null item pointer seen (scan_item_list)", NULL, 0);
415 if (!items)
416 return bombre("null items pointer seen (scan_item_list)", NULL, 0);
417 if (*items <= 0) {
418 *flags = 0;
419 return 1;
420 }
421 if (*items > maxitems) {
422 valueptr = trealloc(valueptr, sizeof(*valueptr) * (maxitems = *items));
423 keylength = trealloc(keylength, sizeof(*keylength) * maxitems);
424 item_matched = trealloc(item_matched, sizeof(*item_matched) * maxitems);
425 }
426 *flags = 0;
427 for (i = 0; i < *items; i++) {
428 item_matched[i] = 0;
429#if DEBUG
430 fprintf(stderr, "item %ld: %s\n", i, item[i]);
431#endif
432 if ((valueptr[i] = strchr(item[i], '='))) {
433 if ((keylength[i] = valueptr[i] - item[i]) <= 0)
434 return bombre("zero-length keyword seen (scan_item_list)", NULL, 0);
435 *valueptr[i]++ = 0;
436 } else
437 keylength[i] = strlen(item[i]);
438#if DEBUG
439 fprintf(stderr, " keyword: %s valueptr: %s\n", item[i], valueptr[i]);
440#endif
441 }
442
443 va_start(argptr, items);
444 retval = 1;
445 do {
446 if (!(keyword = va_arg(argptr, char *)))
447 break;
448 type = va_arg(argptr, int32_t);
449 data = va_arg(argptr, void *);
450 //number = va_arg(argptr, int32_t);
451 va_arg(argptr, int32_t);
452 flag = va_arg(argptr, uint32_t);
453 length = strlen(keyword);
454 match = -1;
455 for (i = 0; i < *items; i++)
456 if (strncmp_case_insensitive(item[i], keyword, MIN(length, keylength[i])) == 0) {
457 if (match != -1) {
458 fprintf(stderr, "ambiguous item %s seen\n", keyword);
459 retval = 0;
460 }
461 match = i;
462 }
463#if defined(DEBUG)
464 if (match != -1)
465 fprintf(stderr, "keyword %s and item %ld (%s) match\n", keyword, match, item[match]);
466 else
467 fprintf(stderr, "no match for keyword %s\n", keyword);
468#endif
469 if (!retval)
470 break;
471 if (match == -1)
472 continue;
473 if (item_matched[match]) {
474 fprintf(stderr, "error: ambiguous qualifier %s seen\n", item[match]);
475 retval = 0;
476 break;
477 }
478 item_matched[match] = 1;
479 *flags |= flag;
480 if (!valueptr[match]) {
481 if (type == -1)
482 continue;
483 fprintf(stderr, "error: value not given for %s\n", keyword);
484 retval = 0;
485 break;
486 }
487 switch (type) {
488 case SDDS_DOUBLE:
489 *((double *)data) = atof(valueptr[match]);
490 break;
491 case SDDS_FLOAT:
492 *((float *)data) = (float)atof(valueptr[match]);
493 break;
494 case SDDS_LONG:
495 *((int32_t *)data) = atol(valueptr[match]);
496 break;
497 case SDDS_ULONG:
498#if defined(_WIN32)
499 *((uint32_t *)data) = (uint32_t)_atoi64(valueptr[match]);
500#else
501# if defined(vxWorks)
502 epicsParseUInt32(valueptr[match], (uint32_t *)data, 10, NULL);
503# else
504 *((uint32_t *)data) = (uint32_t)atoll(valueptr[match]);
505# endif
506#endif
507 break;
508 case SDDS_SHORT:
509 *((short *)data) = (short)atol(valueptr[match]);
510 break;
511 case SDDS_USHORT:
512 *((unsigned short *)data) = (unsigned short)atol(valueptr[match]);
513 break;
514 case SDDS_STRING:
515 cp_str((char **)data, valueptr[match]);
516 break;
517 case SDDS_CHARACTER:
518 *((char *)data) = valueptr[match][0];
519 break;
520 default:
521 fprintf(stderr, "Error: value not accepted for qualifier %s\n", item[match]);
522 break;
523 }
524 free(item[match]);
525 (*items)--;
526 for (j = match; j < *items; j++) {
527 item[j] = item[j + 1];
528 valueptr[j] = valueptr[j + 1];
529 keylength[j] = keylength[j + 1];
530 }
531 } while (retval == 1 && *items);
532 va_end(argptr);
533 return retval;
534}
535
536/**
537 * @brief Checks if a string contains an unescaped equal sign, indicating a keyword-value phrase.
538 *
539 * This function scans the input string for the presence of an equal sign ('=') that is not preceded by a backslash ('\\').
540 * It returns 1 if such a keyword-value pair is found, otherwise returns 0.
541 * Additionally, it handles escaped equal signs by removing the escape character.
542 *
543 * @param string The input string to be checked for keyword-value phrases.
544 *
545 * @return Returns 1 if the string contains an unescaped equal sign, otherwise returns 0.
546 */
547long contains_keyword_phrase(char *string) {
548 char *ptr, *ptr0;
549 ptr0 = string;
550 while ((ptr = strchr(string, '='))) {
551 if (ptr != ptr0 && *(ptr - 1) != '\\')
552 return 1;
553 if (ptr != ptr0 && *(ptr - 1) == '\\')
554 strcpy_ss(ptr - 1, ptr);
555 string = ptr + 1;
556 }
557 return 0;
558}
#define SDDS_ULONG
Identifier for the unsigned 32-bit integer data type.
Definition SDDStypes.h:67
#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_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_USHORT
Identifier for the unsigned short integer data type.
Definition SDDStypes.h:79
#define SDDS_DOUBLE
Identifier for the double data type.
Definition SDDStypes.h:37
#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:181
long bombre(char *error, char *usage, long return_value)
Reports error messages to the terminal and returns a specified value.
Definition bomb.c:44
char * cp_str(char **s, char *t)
Copies a string, allocating memory for storage.
Definition cp_str.c:28
int strncmp_case_insensitive(char *s1, char *s2, long n)
Compares up to a specified number of characters of two strings in a case-insensitive manner.
long scanItemListLong(unsigned long long *flags, char **item, long *items, unsigned long mode,...)
Scans a list of items with extended flag support and assigns values based on provided keywords and ty...
long contains_keyword_phrase(char *string)
Checks if a string contains an unescaped equal sign, indicating a keyword-value phrase.
long scanItemList(unsigned long *flags, char **item, long *items, unsigned long mode,...)
Scans a list of items and assigns values based on provided keywords and types.
long scan_item_list(unsigned long *flags, char **item, long *items,...)
Scans a list of items without flag extension and assigns values based on provided keywords and types.
char * strcpy_ss(char *dest, const char *src)
Safely copies a string, handling memory overlap.
Definition str_copy.c:34