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