]> git.ipfire.org Git - people/ms/network.git/blob - src/networkd/string.h
Makefile: Fix typo in localstatedir
[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 required;
41
42 // Check if the entire string could be written
43 if ((size_t)required >= length) {
44 return -ENOMEM;
45 }
46
47 // Success
48 return 0;
49 }
50
51 #define nw_string_format(s, format, ...) \
52 __nw_string_format(s, sizeof(s), format, __VA_ARGS__)
53
54 static inline int __nw_string_format(char* s, const size_t length,
55 const char* format, ...) {
56 va_list args;
57 int r;
58
59 // Call __nw_string_vformat
60 va_start(args, format);
61 r = __nw_string_vformat(s, length, format, args);
62 va_end(args);
63
64 return r;
65 }
66
67 #define nw_string_set(s, value) __nw_string_set(s, sizeof(s), value)
68
69 static inline int __nw_string_set(char* s, const size_t length, const char* value) {
70 // If value is NULL, we will overwrite the buffer with just zeros
71 if (!value) {
72 for (unsigned int i = 0; i < length; i++)
73 s[i] = '\0';
74
75 return 0;
76 }
77
78 // Otherwise just copy
79 return __nw_string_format(s, length, "%s", value);
80 }
81
82 static inline int nw_string_lstrip(char* s) {
83 char* p = s;
84
85 // Count any leading spaces
86 while (*p && isspace(*p))
87 p++;
88
89 // Move the string to the beginning of the buffer
90 while (*p)
91 *s++ = *p++;
92
93 // Terminate the string
94 *s = '\0';
95
96 return 0;
97 }
98
99 static inline int nw_string_rstrip(char* s) {
100 ssize_t l = strlen(s) - 1;
101
102 while (l >= 0 && isspace(s[l]))
103 s[l--] = '\0';
104
105 return 0;
106 }
107
108 static inline int nw_string_strip(char* s) {
109 int r;
110
111 r = nw_string_lstrip(s);
112 if (r)
113 return r;
114
115 r = nw_string_rstrip(s);
116 if (r)
117 return r;
118
119 return 0;
120 }
121
122 static inline void nw_string_empty(char* s) {
123 if (s)
124 *s = '\0';
125 }
126
127 /*
128 Tables
129 */
130
131 typedef struct nw_string_table {
132 const int id;
133 const char* string;
134 } nw_string_table_t;
135
136 static inline const char* nw_string_table_lookup_string(
137 const nw_string_table_t* table, const int id) {
138 const nw_string_table_t* entry = NULL;
139
140 for (entry = table; entry->string; entry++)
141 if (entry->id == id)
142 return entry->string;
143
144 return NULL;
145 }
146
147 static inline int nw_string_table_lookup_id(
148 const nw_string_table_t* table, const char* string) {
149 const nw_string_table_t* entry = NULL;
150
151 for (entry = table; entry->string; entry++)
152 if (strcmp(entry->string, string) == 0)
153 return entry->id;
154
155 return -1;
156 }
157
158 #define NW_STRING_TABLE_LOOKUP_ID(type, table, method) \
159 __attribute__((unused)) static type method(const char* s) { \
160 return nw_string_table_lookup_id(table, s); \
161 }
162
163 #define NW_STRING_TABLE_LOOKUP_STRING(type, table, method) \
164 __attribute__((unused)) static const char* method(const type id) { \
165 return nw_string_table_lookup_string(table, id); \
166 }
167
168 #define NW_STRING_TABLE_LOOKUP(type, table) \
169 NW_STRING_TABLE_LOOKUP_ID(type, table, table ## _from_string) \
170 NW_STRING_TABLE_LOOKUP_STRING(type, table, table ## _to_string)
171
172 /*
173 Paths
174 */
175
176 #define nw_path_join(s, first, second) \
177 __nw_path_join(s, sizeof(s), first, second)
178
179 static inline int __nw_path_join(char* s, const size_t length,
180 const char* first, const char* second) {
181 if (!first)
182 return __nw_string_format(s, length, "%s", second);
183
184 if (!second)
185 return __nw_string_format(s, length, "%s", first);
186
187 // Remove leading slashes from second argument
188 while (*second == '/')
189 second++;
190
191 return __nw_string_format(s, length, "%s/%s", first, second);
192 }
193
194 static inline const char* nw_path_basename(const char* path) {
195 const char* basename = strrchr(path, '/');
196 if (!basename)
197 return NULL;
198
199 return basename + 1;
200 }
201
202 #endif /* NETWORKD_STRING_H */