]> git.ipfire.org Git - people/ms/network.git/blob - src/networkd/string.h
string: Define an own type for string tables
[people/ms/network.git] / src / networkd / string.h
1 /*#############################################################################
2 # #
3 # IPFire.org - A linux based firewall #
4 # Copyright (C) 2023 IPFire Network Development Team #
5 # #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
10 # #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
15 # #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
18 # #
19 #############################################################################*/
20
21 #ifndef NETWORKD_STRING_H
22 #define NETWORKD_STRING_H
23
24 #include <ctype.h>
25 #include <errno.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <string.h>
29
30 #define nw_string_vformat(s, format, ...) \
31 __nw_string_vformat(s, sizeof(s), format, __VA_ARGS__)
32
33 static inline int __nw_string_vformat(char* s, const size_t length,
34 const char* format, va_list args) {
35 // Write string to buffer
36 const ssize_t required = vsnprintf(s, length, format, args);
37
38 // Catch any errors
39 if (required < 0)
40 return 1;
41
42 // Check if the entire string could be written
43 if ((size_t)required >= length) {
44 errno = ENOMEM;
45 return 1;
46 }
47
48 // Success
49 return 0;
50 }
51
52 #define nw_string_format(s, format, ...) \
53 __nw_string_format(s, sizeof(s), format, __VA_ARGS__)
54
55 static inline int __nw_string_format(char* s, const size_t length,
56 const char* format, ...) {
57 va_list args;
58 int r;
59
60 // Call __nw_string_vformat
61 va_start(args, format);
62 r = __nw_string_vformat(s, length, format, args);
63 va_end(args);
64
65 return r;
66 }
67
68 #define nw_string_set(s, value) __nw_string_set(s, sizeof(s), value)
69
70 static inline int __nw_string_set(char* s, const size_t length, const char* value) {
71 // If value is NULL, we will overwrite the buffer with just zeros
72 if (!value) {
73 for (unsigned int i = 0; i < length; i++)
74 s[i] = '\0';
75
76 return 0;
77 }
78
79 // Otherwise just copy
80 return __nw_string_format(s, length, "%s", value);
81 }
82
83 static inline int nw_string_lstrip(char* s) {
84 char* p = s;
85
86 // Count any leading spaces
87 while (*p && isspace(*p))
88 p++;
89
90 // Move the string to the beginning of the buffer
91 while (*p)
92 *s++ = *p++;
93
94 // Terminate the string
95 *s = '\0';
96
97 return 0;
98 }
99
100 static inline int nw_string_rstrip(char* s) {
101 ssize_t l = strlen(s) - 1;
102
103 while (l >= 0 && isspace(s[l]))
104 s[l--] = '\0';
105
106 return 0;
107 }
108
109 static inline int nw_string_strip(char* s) {
110 int r;
111
112 r = nw_string_lstrip(s);
113 if (r)
114 return r;
115
116 r = nw_string_rstrip(s);
117 if (r)
118 return r;
119
120 return 0;
121 }
122
123 static inline void nw_string_empty(char* s) {
124 if (s)
125 *s = '\0';
126 }
127
128 /*
129 Tables
130 */
131
132 typedef struct nw_string_table {
133 const int id;
134 const char* string;
135 } nw_string_table_t;
136
137 static inline const char* nw_string_table_lookup_string(
138 const nw_string_table_t* table, const int id) {
139 const nw_string_table_t* entry = NULL;
140
141 for (entry = table; entry->string; entry++)
142 if (entry->id == id)
143 return entry->string;
144
145 return NULL;
146 }
147
148 static inline int nw_string_table_lookup_id(
149 const nw_string_table_t* table, const char* string) {
150 const nw_string_table_t* entry = NULL;
151
152 for (entry = table; entry->string; entry++)
153 if (strcmp(entry->string, string) == 0)
154 return entry->id;
155
156 return -1;
157 }
158
159 #define NW_STRING_TABLE_LOOKUP_ID(type, table, method) \
160 __attribute__((unused)) static type method(const char* s) { \
161 return nw_string_table_lookup_id(table, s); \
162 }
163
164 #define NW_STRING_TABLE_LOOKUP_STRING(type, table, method) \
165 __attribute__((unused)) static const char* method(const type id) { \
166 return nw_string_table_lookup_string(table, id); \
167 }
168
169 #define NW_STRING_TABLE_LOOKUP(type, table) \
170 NW_STRING_TABLE_LOOKUP_ID(type, table, table ## _from_string) \
171 NW_STRING_TABLE_LOOKUP_STRING(type, table, table ## _to_string)
172
173 /*
174 Paths
175 */
176
177 #define nw_path_join(s, first, second) \
178 __nw_path_join(s, sizeof(s), first, second)
179
180 static inline int __nw_path_join(char* s, const size_t length,
181 const char* first, const char* second) {
182 if (!first)
183 return __nw_string_format(s, length, "%s", second);
184
185 if (!second)
186 return __nw_string_format(s, length, "%s", first);
187
188 // Remove leading slashes from second argument
189 while (*second == '/')
190 second++;
191
192 return __nw_string_format(s, length, "%s/%s", first, second);
193 }
194
195 static inline const char* nw_path_basename(const char* path) {
196 const char* basename = strrchr(path, '/');
197 if (!basename)
198 return NULL;
199
200 return basename + 1;
201 }
202
203 #endif /* NETWORKD_STRING_H */