1 /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 3 #pragma once 4 5 #include <errno.h> 6 #include <stddef.h> 7 #include <stdio.h> 8 #include <sys/types.h> 9 10 #include "macro.h" 11 #include "parse-util.h" 12 #include "string-util.h" 13 14 ssize_t string_table_lookup(const char * const *table, size_t len, const char *key); 15 16 /* For basic lookup tables with strictly enumerated entries */ 17 #define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ 18 scope const char *name##_to_string(type i) { \ 19 if (i < 0 || i >= (type) ELEMENTSOF(name##_table)) \ 20 return NULL; \ 21 return name##_table[i]; \ 22 } 23 24 #define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \ 25 scope type name##_from_string(const char *s) { \ 26 return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \ 27 } 28 29 #define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \ 30 scope type name##_from_string(const char *s) { \ 31 if (!s) \ 32 return -EINVAL; \ 33 int b = parse_boolean(s); \ 34 if (b == 0) \ 35 return (type) 0; \ 36 if (b > 0) \ 37 return yes; \ 38 return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \ 39 } 40 41 #define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,scope) \ 42 scope int name##_to_string_alloc(type i, char **str) { \ 43 char *s; \ 44 if (i < 0 || i > max) \ 45 return -ERANGE; \ 46 if (i < (type) ELEMENTSOF(name##_table) && name##_table[i]) { \ 47 s = strdup(name##_table[i]); \ 48 if (!s) \ 49 return -ENOMEM; \ 50 } else { \ 51 if (asprintf(&s, "%i", i) < 0) \ 52 return -ENOMEM; \ 53 } \ 54 *str = s; \ 55 return 0; \ 56 } 57 58 #define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,scope) \ 59 scope type name##_from_string(const char *s) { \ 60 unsigned u = 0; \ 61 type i; \ 62 if (!s) \ 63 return -EINVAL; \ 64 i = (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \ 65 if (i >= 0) \ 66 return i; \ 67 if (safe_atou(s, &u) < 0) \ 68 return -EINVAL; \ 69 if (u > max) \ 70 return -EINVAL; \ 71 return (type) u; \ 72 } 73 74 #define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \ 75 _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ 76 _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) 77 78 #define _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,scope) \ 79 _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ 80 _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) 81 82 #define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,) 83 #define DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,) 84 #define DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,) 85 #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static) 86 #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static) 87 #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static) 88 89 #define DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes) _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,) 90 #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes) _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,static) 91 #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes) \ 92 _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,static) 93 94 /* For string conversions where numbers are also acceptable */ 95 #define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \ 96 _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,) \ 97 _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,) 98 99 #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max) \ 100 _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,static) 101 #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max) \ 102 _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,static) 103 104 #define DUMP_STRING_TABLE(name,type,max) \ 105 do { \ 106 flockfile(stdout); \ 107 for (type _k = 0; _k < (max); _k++) { \ 108 const char *_t; \ 109 _t = name##_to_string(_k); \ 110 if (!_t) \ 111 continue; \ 112 fputs_unlocked(_t, stdout); \ 113 fputc_unlocked('\n', stdout); \ 114 } \ 115 funlockfile(stdout); \ 116 } while (false) 117