argcheck: a module to check argument ranges
[ccan] / ccan / argcheck / argcheck.h
1 /*****************************************************************************
2  *
3  * argcheck - macros for argument value checking
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to deal
7  * in the Software without restriction, including without limitation the rights
8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9  * copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21  * THE SOFTWARE.
22  *
23  ****************************************************************************/
24
25 #ifndef CCAN_ARGCHECK_H
26 #define CCAN_ARGCHECK_H
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdarg.h>
30
31 #include <ccan/likely/likely.h>
32 #include <ccan/compiler/compiler.h>
33
34 /**
35  * ARGCHECK_DISABLE_LOGGING - define to disable any logging done by
36  * argcheck. This does not disable the actual checks, merely the invocation
37  * of the argcheck_log function, be it custom or the default logging
38  * function.
39  */
40 #ifdef ARGCHECK_DISABLE_LOGGING
41 #undef argcheck_log
42 #define argcheck_log(...) /* __VA_ARGS__ */
43 #else
44 #ifndef argcheck_log
45 /**
46  * argcheck_log - logging function for failed argcheck tests
47  *
48  * Override this function to hook up your own logging function. The function
49  * will be called once for each failed test.
50  */
51 #define argcheck_log argcheck_log_
52 #endif /* argcheck_log */
53
54 static inline void COLD PRINTF_FMT(4, 5)
55 argcheck_log_(const char *file, int line, const char *func,
56               const char *msg, ...)
57 {
58         va_list args;
59         va_start(args, msg);
60         fprintf(stderr, "argcheck: %s:%d %s\nargcheck: ", file, line, func);
61         vfprintf(stderr, msg, args);
62         va_end(args);
63 }
64 #endif
65
66 /**
67  * argcheck_int_eq - check the argument is equal to the value.
68  */
69 #define argcheck_int_eq(arg, val) \
70         argcheck_int_eq_(arg, val, #arg, #val, __FILE__, __LINE__, __func__)
71 /**
72  * argcheck_int_ne - check the argument is not equal to the value
73  */
74 #define argcheck_int_ne(arg, val) \
75         argcheck_int_ne_(arg, val, #arg, #val, __FILE__, __LINE__, __func__)
76 /**
77  * argcheck_int_ge - check the argument is equal or greater than the value
78  */
79 #define argcheck_int_ge(arg, val) \
80         argcheck_int_ge_(arg, val, #arg, #val, __FILE__, __LINE__, __func__)
81 /**
82  * argcheck_int_gt - check the argument is greater than the value
83  */
84 #define argcheck_int_gt(arg, val) \
85         argcheck_int_gt_(arg, val, #arg, #val, __FILE__, __LINE__, __func__)
86 /**
87  * argcheck_int_le - check the argument is equal or less than the value
88  */
89 #define argcheck_int_le(arg, val) \
90         argcheck_int_le_(arg, val, #arg, #val, __FILE__, __LINE__, __func__)
91 /**
92  * argcheck_int_lt - check the argument is less than the value
93  */
94 #define argcheck_int_lt(arg, val) \
95         argcheck_int_lt_(arg, val, #arg, #val, __FILE__, __LINE__, __func__)
96 /**
97  * argcheck_int_range - check the argument is within a range (inclusive)
98  */
99 #define argcheck_int_range(arg, min, max) \
100         argcheck_int_range_(arg, min, max, #arg, #min, #max, __FILE__, __LINE__, __func__)
101 /**
102  * argcheck_flag_set - check if a flag is set
103  */
104 #define argcheck_flag_set(arg, flag) \
105         argcheck_flag_set_(arg, flag, #arg, #flag, __FILE__, __LINE__, __func__)
106 /**
107  * argcheck_flag_unset - check if a flag is not set
108  */
109 #define argcheck_flag_unset(arg, flag) \
110         argcheck_flag_unset_(arg, flag, #arg, #flag, __FILE__, __LINE__, __func__)
111 /**
112  * argcheck_ptr_not_null - check that a pointer is not NULL
113  */
114 #define argcheck_ptr_not_null(arg) \
115         argcheck_ptr_not_null_(arg, #arg, __FILE__, __LINE__, __func__)
116 /**
117  * argcheck_ptr_null - check that a pointer is NULL
118  */
119 #define argcheck_ptr_null(arg) \
120         argcheck_ptr_null_(arg, #arg, __FILE__, __LINE__, __func__)
121 /**
122  * argcheck_str_null - see argcheck_ptr_null
123  */
124 #define argcheck_str_null(arg) \
125         argcheck_str_null_(arg, #arg, __FILE__, __LINE__, __func__)
126 /**
127  * argcheck_str_not_null - see argcheck_ptr_not_null
128  */
129 #define argcheck_str_not_null(arg) \
130         argcheck_str_not_null_(arg, #arg, __FILE__, __LINE__, __func__)
131 /**
132  * argcheck_str_zero - check that a string is not NULL and of zero length
133  */
134 #define argcheck_str_zero_len(arg) \
135         argcheck_str_zero_len_(arg, #arg, __FILE__, __LINE__, __func__)
136 /**
137  * argcheck_str_null_or_zero - check that a string is either NULL or of zero length
138  */
139 #define argcheck_str_null_or_zero_len(arg) \
140         argcheck_str_null_or_zero_len_(arg, #arg, __FILE__, __LINE__, __func__)
141 /**
142  * argcheck_str_not_zero - check that a string is not NULL and has a length greater than 0
143  */
144 #define argcheck_str_not_zero_len(arg) \
145         argcheck_str_not_zero_len_(arg, #arg, __FILE__, __LINE__, __func__)
146 /**
147  * argcheck_str_null_or_not_zero - check that a string is either NULL or has a length greater than 0
148  */
149 #define argcheck_str_null_or_not_zero_len(arg) \
150         argcheck_str_null_or_not_zero_len_(arg, #arg, __FILE__, __LINE__, __func__)
151 /**
152  * argcheck_str_min_len - check that a string is not NULL and has a length greater than or equal to a minimum
153  */
154 #define argcheck_str_min_len(arg, min) \
155         argcheck_str_min_len_(arg, #arg, min, #min, __FILE__, __LINE__, __func__)
156 /**
157  * argcheck_str_max_len - check that a string is not NULL and has a length less than or equal to a maximum
158  */
159 #define argcheck_str_max_len(arg, max) \
160         argcheck_str_max_len_(arg, #arg, max, #max, __FILE__, __LINE__, __func__)
161 /**
162  * argcheck_str_null_or_min_len - check that a string is NULL or has a length greater than or equal to a minimum
163  */
164 #define argcheck_str_null_or_min_len(arg, min) \
165         argcheck_str_null_or_min_len_(arg, #arg, min, #min, __FILE__, __LINE__, __func__)
166 /**
167  * argcheck_str_null_or_max_len - check that a string is NULL or has a length less than or equal to a maximum
168  */
169 #define argcheck_str_null_or_max_len(arg, max) \
170         argcheck_str_null_or_max_len_(arg, #arg, max, #max, __FILE__, __LINE__, __func__)
171
172 /*
173
174    below is the actual implemenation. do not use it directly, use the macros
175    above instead
176
177  */
178
179 static inline int argcheck_int_eq_(int a, int b, const char *astr, const char *bstr,
180                                    const char *file, int line, const char *func)
181 {
182         if (likely(a == b))
183                 return 1;
184
185         argcheck_log(file, line, func,
186                      "condition \"(%s == %s)\" (%d == %d) failed\n", astr, bstr, a, b);
187         return 0;
188 }
189
190 static inline int argcheck_int_ne_(int a, int b, const char *astr, const char *bstr,
191                                    const char *file, int line, const char *func)
192 {
193         if (likely(a != b))
194                 return 1;
195
196         argcheck_log(file, line, func,
197                      "condition \"(%s != %s)\" (%d != %d) failed\n", astr, bstr, a, b);
198         return 0;
199 }
200
201 static inline int argcheck_int_ge_(int a, int b, const char *astr, const char *bstr,
202                                    const char *file, int line, const char *func)
203 {
204         if (likely(a >= b))
205                 return 1;
206
207         argcheck_log(file, line, func,
208                      "condition \"(%s >= %s)\" (%d >= %d) failed\n", astr, bstr, a, b);
209         return 0;
210 }
211
212 static inline int argcheck_int_gt_(int a, int b, const char *astr, const char *bstr,
213                                    const char *file, int line, const char *func)
214 {
215         if (likely(a > b))
216                 return 1;
217
218         argcheck_log(file, line, func,
219                      "condition \"(%s > %s)\" (%d > %d) failed\n", astr, bstr, a, b);
220         return 0;
221 }
222
223 static inline int argcheck_int_le_(int a, int b, const char *astr, const char *bstr,
224                                    const char *file, int line, const char *func)
225 {
226         if (likely(a <= b))
227                 return 1;
228
229         argcheck_log(file, line, func,
230                      "condition \"(%s <= %s)\" (%d <= %d) failed\n", astr, bstr, a, b);
231         return 0;
232 }
233
234 static inline int argcheck_int_lt_(int a, int b, const char *astr, const char *bstr,
235                                    const char *file, int line, const char *func)
236 {
237         if (likely(a < b))
238                 return 1;
239
240         argcheck_log(file, line, func,
241                      "condition \"(%s < %s)\" (%d < %d) failed\n", astr, bstr, a, b);
242         return 0;
243 }
244
245 static inline int argcheck_int_range_(int v, int min,  int max,
246                                       const char *vstr,
247                                       const char *minstr, const char *maxstr,
248                                       const char *file, int line, const char *func)
249 {
250         if (!argcheck_int_le_(min, max, minstr, maxstr, file, line, func))
251                 return 0;
252
253         if (likely(v >= min && v <= max))
254                 return 1;
255
256         argcheck_log(file, line, func,
257                      "condition \"(%s <= %s <= %s)\" (%d <= %d <= %d) failed\n",
258                      minstr, vstr, maxstr, min, v, max);
259         return 0;
260 }
261
262 static inline int argcheck_flag_set_(int arg, int flag,
263                                      const char *argstr, const char *flagstr,
264                                      const char *file, int line, const char *func)
265 {
266         if (!argcheck_int_ne_(flag, 0, flagstr, "0", file, line, func))
267                 return 0;
268
269         if (likely(arg & flag))
270                 return 1;
271
272         argcheck_log(file, line, func,
273                      "flag \"%s\" (%d) is not set on \"%s\" (%d)\"\n",
274                      flagstr, flag, argstr, arg);
275         return 0;
276 }
277
278 static inline int argcheck_flag_unset_(int arg, int flag,
279                                        const char *argstr, const char *flagstr,
280                                        const char *file, int line, const char *func)
281 {
282         if (!argcheck_int_ne_(flag, 0, flagstr, "0", file, line, func))
283                 return 0;
284
285         if (likely((arg & flag) == 0))
286                 return 1;
287
288         argcheck_log(file, line, func,
289                      "flag \"%s\" (%d) must not be set on \"%s\" (%d)\"\n",
290                      flagstr, flag, argstr, arg);
291         return 0;
292 }
293
294 static inline int argcheck_ptr_not_null_(const void *arg, const char *argstr,
295                                         const char *file, int line, const char *func)
296 {
297         if (likely(arg != NULL))
298                 return 1;
299
300         argcheck_log(file, line, func,
301                      "\"%s\" must not be NULL\n", argstr);
302         return 0;
303 }
304
305 static inline int argcheck_ptr_null_(const void *arg, const char *argstr,
306                                      const char *file, int line, const char *func)
307 {
308         if (likely(arg == NULL))
309                 return 1;
310
311         argcheck_log(file, line, func,
312                      "\"%s\" must be NULL\n", argstr);
313         return 0;
314 }
315
316 static inline int argcheck_str_null_(const char *arg, const char *argstr,
317                                      const char *file, int line, const char *func)
318 {
319         return argcheck_ptr_null_(arg, argstr, file, line, func);
320 }
321
322 static inline int argcheck_str_not_null_(const char *arg, const char *argstr,
323                                          const char *file, int line, const char *func)
324 {
325         return argcheck_ptr_not_null_(arg, argstr, file, line, func);
326 }
327
328 static inline int argcheck_str_zero_len_(const char *arg, const char *argstr,
329                                          const char *file, int line, const char *func)
330 {
331         if (!argcheck_str_not_null_(arg, argstr, file, line, func))
332                 return 0;
333
334         if (likely(*arg == '\0'))
335                 return 1;
336
337         argcheck_log(file, line, func,
338                      "\"%s\" must be a zero-length string\n", argstr);
339         return 0;
340 }
341
342
343 static inline int argcheck_str_null_or_zero_len_(const char *arg, const char *argstr,
344                                                  const char *file, int line, const char *func)
345 {
346         if (likely(arg == NULL || *arg == '\0'))
347                 return 1;
348
349         argcheck_log(file, line, func,
350                      "\"%s\" must be NULL or a zero-length string\n", argstr);
351         return 0;
352 }
353
354 static inline int argcheck_str_not_zero_len_(const char *arg, const char *argstr,
355                                              const char *file, int line, const char *func)
356 {
357         if (!argcheck_str_not_null_(arg, argstr, file, line, func))
358                 return 0;
359
360         if (likely(*arg != '\0'))
361                 return 1;
362
363         argcheck_log(file, line, func,
364                      "\"%s\" must not be a zero-length string\n", argstr);
365         return 0;
366 }
367
368 static inline int argcheck_str_null_or_not_zero_len_(const char *arg, const char *argstr,
369                                                      const char *file, int line, const char *func)
370 {
371         if (likely(arg == NULL || *arg != '\0'))
372                 return 1;
373
374         argcheck_log(file, line, func,
375                      "\"%s\" must be NULL or not a zero-length string\n", argstr);
376         return 0;
377 }
378
379 static inline int argcheck_str_min_len_(const char *arg, const char *argstr,
380                                         int min, const char *minstr,
381                                         const char *file, int line, const char *func)
382 {
383         int len;
384
385         if (!argcheck_str_not_null_(arg, argstr, file, line, func))
386                 return 0;
387
388         len = strlen(arg);
389         if (likely(len >= min))
390                 return 1;
391
392         argcheck_log(file, line, func,
393                      "\"%s\" must be at least \"%s\" (%d) long, is '%s' (length %d)\n", argstr,
394                      minstr, min, arg, len);
395         return 0;
396 }
397
398 static inline int argcheck_str_max_len_(const char *arg, const char *argstr,
399                                         int max, const char *maxstr,
400                                         const char *file, int line, const char *func)
401 {
402         int len;
403
404         if (!argcheck_str_not_null_(arg, argstr, file, line, func))
405                 return 0;
406
407         len = strlen(arg);
408         if (likely(len <= max))
409                 return 1;
410
411         argcheck_log(file, line, func,
412                      "\"%s\" must be at most \"%s\" (%d) long, is '%s' (length %d)\n", argstr,
413                      maxstr, max, arg, len);
414         return 0;
415 }
416
417 static inline int argcheck_str_null_or_min_len_(const char *arg, const char *argstr,
418                                                 int min, const char *minstr,
419                                                 const char *file, int line, const char *func)
420 {
421         int len;
422
423         if (likely(arg == NULL))
424                 return 1;
425
426         len = strlen(arg);
427         if (likely(len >= min))
428                 return 1;
429
430         argcheck_log(file, line, func,
431                      "\"%s\" must be NULL or at least \"%s\" (%d) long, is '%s' (length %d)\n", argstr,
432                      minstr, min, arg, len);
433         return 0;
434 }
435
436 static inline int argcheck_str_null_or_max_len_(const char *arg, const char *argstr,
437                                                 int max, const char *maxstr,
438                                                 const char *file, int line, const char *func)
439 {
440         int len;
441
442         if (likely(arg == NULL))
443                 return 1;
444
445         len = strlen(arg);
446         if (likely(len <= max))
447                 return 1;
448
449         argcheck_log(file, line, func,
450                      "\"%s\" must be NULL or at most \"%s\" (%d) long, is '%s' (length %d)\n", argstr,
451                      maxstr, max, arg, len);
452         return 0;
453 }
454
455 #endif /* CCAN_ARGCHECK_H */