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