1 /* Simple Plugin API
2 *
3 * Copyright © 2021 Red Hat, Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25 #ifndef SPA_UTILS_STRING_H
26 #define SPA_UTILS_STRING_H
27
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31
32 #include <stdarg.h>
33 #include <stdbool.h>
34 #include <errno.h>
35
36 #include <spa/utils/defs.h>
37
38 /**
39 * \defgroup spa_string String handling
40 * String handling utilities
41 */
42
43 /**
44 * \addtogroup spa_string
45 * \{
46 */
47
48 /**
49 * \return true if the two strings are equal, false otherwise
50 *
51 * If both \a a and \a b are NULL, the two are considered equal.
52 *
53 */
spa_streq(const char * s1,const char * s2)54 static inline bool spa_streq(const char *s1, const char *s2)
55 {
56 return SPA_LIKELY(s1 && s2) ? strcmp(s1, s2) == 0 : s1 == s2;
57 }
58
59 /**
60 * \return true if the two strings are equal, false otherwise
61 *
62 * If both \a a and \a b are NULL, the two are considered equal.
63 */
spa_strneq(const char * s1,const char * s2,size_t len)64 static inline bool spa_strneq(const char *s1, const char *s2, size_t len)
65 {
66 return SPA_LIKELY(s1 && s2) ? strncmp(s1, s2, len) == 0 : s1 == s2;
67 }
68
69
70 /**
71 * \return true if \a s starts with the \a prefix or false otherwise.
72 * A \a s is NULL, it never starts with the given \a prefix. A \a prefix of
73 * NULL is a bug in the caller.
74 */
spa_strstartswith(const char * s,const char * prefix)75 static inline bool spa_strstartswith(const char *s, const char *prefix)
76 {
77 if (SPA_UNLIKELY(s == NULL))
78 return false;
79
80 spa_assert_se(prefix);
81
82 return strncmp(s, prefix, strlen(prefix)) == 0;
83 }
84
85
86 /**
87 * \return true if \a s ends with the \a suffix or false otherwise.
88 * A \a s is NULL, it never ends with the given \a suffix. A \a suffix of
89 * NULL is a bug in the caller.
90 */
spa_strendswith(const char * s,const char * suffix)91 static inline bool spa_strendswith(const char *s, const char *suffix)
92 {
93 size_t l1, l2;
94
95 if (SPA_UNLIKELY(s == NULL))
96 return false;
97
98 spa_assert_se(suffix);
99
100 l1 = strlen(s);
101 l2 = strlen(suffix);
102 return l1 >= l2 && spa_streq(s + l1 - l2, suffix);
103 }
104
105 /**
106 * Convert \a str to an int32_t with the given \a base and store the
107 * result in \a val.
108 *
109 * On failure, the value of \a val is unmodified.
110 *
111 * \return true on success, false otherwise
112 */
spa_atoi32(const char * str,int32_t * val,int base)113 static inline bool spa_atoi32(const char *str, int32_t *val, int base)
114 {
115 char *endptr;
116 long v;
117
118 if (!str || *str =='\0')
119 return false;
120
121 errno = 0;
122 v = strtol(str, &endptr, base);
123 if (errno != 0 || *endptr != '\0')
124 return false;
125
126 if (v != (int32_t)v)
127 return false;
128
129 *val = v;
130 return true;
131 }
132
133 /**
134 * Convert \a str to an uint32_t with the given \a base and store the
135 * result in \a val.
136 *
137 * On failure, the value of \a val is unmodified.
138 *
139 * \return true on success, false otherwise
140 */
spa_atou32(const char * str,uint32_t * val,int base)141 static inline bool spa_atou32(const char *str, uint32_t *val, int base)
142 {
143 char *endptr;
144 unsigned long long v;
145
146 if (!str || *str =='\0')
147 return false;
148
149 errno = 0;
150 v = strtoull(str, &endptr, base);
151 if (errno != 0 || *endptr != '\0')
152 return false;
153
154 if (v != (uint32_t)v)
155 return false;
156
157 *val = v;
158 return true;
159 }
160
161 /**
162 * Convert \a str to an int64_t with the given \a base and store the
163 * result in \a val.
164 *
165 * On failure, the value of \a val is unmodified.
166 *
167 * \return true on success, false otherwise
168 */
spa_atoi64(const char * str,int64_t * val,int base)169 static inline bool spa_atoi64(const char *str, int64_t *val, int base)
170 {
171 char *endptr;
172 long long v;
173
174 if (!str || *str =='\0')
175 return false;
176
177 errno = 0;
178 v = strtoll(str, &endptr, base);
179 if (errno != 0 || *endptr != '\0')
180 return false;
181
182 *val = v;
183 return true;
184 }
185
186 /**
187 * Convert \a str to an uint64_t with the given \a base and store the
188 * result in \a val.
189 *
190 * On failure, the value of \a val is unmodified.
191 *
192 * \return true on success, false otherwise
193 */
spa_atou64(const char * str,uint64_t * val,int base)194 static inline bool spa_atou64(const char *str, uint64_t *val, int base)
195 {
196 char *endptr;
197 unsigned long long v;
198
199 if (!str || *str =='\0')
200 return false;
201
202 errno = 0;
203 v = strtoull(str, &endptr, base);
204 if (errno != 0 || *endptr != '\0')
205 return false;
206
207 *val = v;
208 return true;
209 }
210
211 /**
212 * Convert \a str to a boolean. Allowed boolean values are "true" and a
213 * literal "1", anything else is false.
214 *
215 * \return true on success, false otherwise
216 */
spa_atob(const char * str)217 static inline bool spa_atob(const char *str)
218 {
219 return spa_streq(str, "true") || spa_streq(str, "1");
220 }
221
222 /**
223 * "Safe" version of vsnprintf. Exactly the same as vsnprintf but the
224 * returned value is clipped to `size - 1` and a negative or zero size
225 * will abort() the program.
226 *
227 * \return The number of bytes printed, capped to `size-1`, or a negative
228 * number on error.
229 */
230 SPA_PRINTF_FUNC(3, 0)
spa_vscnprintf(char * buffer,size_t size,const char * format,va_list args)231 static inline int spa_vscnprintf(char *buffer, size_t size, const char *format, va_list args)
232 {
233 int r;
234
235 spa_assert_se((ssize_t)size > 0);
236
237 r = vsnprintf(buffer, size, format, args);
238 if (SPA_UNLIKELY(r < 0))
239 buffer[0] = '\0';
240 if (SPA_LIKELY(r < (ssize_t)size))
241 return r;
242 return size - 1;
243 }
244
245 /**
246 * "Safe" version of snprintf. Exactly the same as snprintf but the
247 * returned value is clipped to `size - 1` and a negative or zero size
248 * will abort() the program.
249 *
250 * \return The number of bytes printed, capped to `size-1`, or a negative
251 * number on error.
252 */
253 SPA_PRINTF_FUNC(3, 4)
spa_scnprintf(char * buffer,size_t size,const char * format,...)254 static inline int spa_scnprintf(char *buffer, size_t size, const char *format, ...)
255 {
256 int r;
257 va_list args;
258
259 va_start(args, format);
260 r = spa_vscnprintf(buffer, size, format, args);
261 va_end(args);
262
263 return r;
264 }
265
266 /**
267 * Convert \a str to a float and store the result in \a val.
268 *
269 * On failure, the value of \a val is unmodified.
270 *
271 * \return true on success, false otherwise
272 */
spa_atof(const char * str,float * val)273 static inline bool spa_atof(const char *str, float *val)
274 {
275 char *endptr;
276 float v;
277
278 if (!str || *str =='\0')
279 return false;
280
281 errno = 0;
282 v = strtof(str, &endptr);
283 if (errno != 0 || *endptr != '\0')
284 return false;
285
286 *val = v;
287 return true;
288 }
289
290 /**
291 * Convert \a str to a double and store the result in \a val.
292 *
293 * On failure, the value of \a val is unmodified.
294 *
295 * \return true on success, false otherwise
296 */
spa_atod(const char * str,double * val)297 static inline bool spa_atod(const char *str, double *val)
298 {
299 char *endptr;
300 double v;
301
302 if (!str || *str =='\0')
303 return false;
304
305 errno = 0;
306 v = strtod(str, &endptr);
307 if (errno != 0 || *endptr != '\0')
308 return false;
309
310 *val = v;
311 return true;
312 }
313
314 /**
315 * \}
316 */
317
318 #ifdef __cplusplus
319 } /* extern "C" */
320 #endif
321
322 #endif /* SPA_UTILS_STRING_H */
323