]> git.ipfire.org Git - people/ms/network.git/blame - src/networkd/string.h
string: Have all functions return negative values on error
[people/ms/network.git] / src / networkd / string.h
CommitLineData
4237caa2
MT
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
5ef56cff 24#include <ctype.h>
e4eebc6e 25#include <errno.h>
4237caa2 26#include <stdarg.h>
e4eebc6e
MT
27#include <stdio.h>
28#include <string.h>
4237caa2 29
00b5de56
MT
30#define nw_string_vformat(s, format, ...) \
31 __nw_string_vformat(s, sizeof(s), format, __VA_ARGS__)
32
4237caa2
MT
33static 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)
45a3d5aa 40 return required;
4237caa2
MT
41
42 // Check if the entire string could be written
43 if ((size_t)required >= length) {
45a3d5aa 44 return -ENOMEM;
4237caa2
MT
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
54static 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
69static 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
5ef56cff
MT
82static 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
99static 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
108static 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
c7761af8
MT
122static inline void nw_string_empty(char* s) {
123 if (s)
124 *s = '\0';
125}
126
f9975100
MT
127/*
128 Tables
129*/
130
644eb1c8 131typedef struct nw_string_table {
f9975100
MT
132 const int id;
133 const char* string;
644eb1c8 134} nw_string_table_t;
f9975100
MT
135
136static inline const char* nw_string_table_lookup_string(
644eb1c8
MT
137 const nw_string_table_t* table, const int id) {
138 const nw_string_table_t* entry = NULL;
f9975100
MT
139
140 for (entry = table; entry->string; entry++)
141 if (entry->id == id)
142 return entry->string;
143
144 return NULL;
145}
146
147static inline int nw_string_table_lookup_id(
644eb1c8
MT
148 const nw_string_table_t* table, const char* string) {
149 const nw_string_table_t* entry = NULL;
f9975100
MT
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
00b5de56
MT
172/*
173 Paths
174*/
175
176#define nw_path_join(s, first, second) \
177 __nw_path_join(s, sizeof(s), first, second)
178
179static 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
c791afc8
MT
194static 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
4237caa2 202#endif /* NETWORKD_STRING_H */