1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 #pragma once
3 
4 #include <printf.h>
5 #include <stdarg.h>
6 #include <stdio.h>
7 #include <sys/types.h>
8 
9 #include "macro.h"
10 #include "memory-util.h"
11 
12 #define snprintf_ok(buf, len, fmt, ...)                                \
13         ({                                                             \
14                 char *_buf = (buf);                                    \
15                 size_t _len = (len);                                   \
16                 int _snpf = snprintf(_buf, _len, (fmt), __VA_ARGS__);  \
17                 _snpf >= 0 && (size_t) _snpf < _len ? _buf : NULL;     \
18         })
19 
20 #define xsprintf(buf, fmt, ...) \
21         assert_message_se(snprintf_ok(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__), "xsprintf: " #buf "[] must be big enough")
22 
23 #define VA_FORMAT_ADVANCE(format, ap)                                   \
24 do {                                                                    \
25         int _argtypes[128];                                             \
26         size_t _i, _k;                                                  \
27         /* See https://github.com/google/sanitizers/issues/992 */       \
28         if (HAS_FEATURE_MEMORY_SANITIZER)                               \
29                 zero(_argtypes);                                        \
30         _k = parse_printf_format((format), ELEMENTSOF(_argtypes), _argtypes); \
31         assert(_k < ELEMENTSOF(_argtypes));                             \
32         for (_i = 0; _i < _k; _i++) {                                   \
33                 if (_argtypes[_i] & PA_FLAG_PTR)  {                     \
34                         (void) va_arg(ap, void*);                       \
35                         continue;                                       \
36                 }                                                       \
37                                                                         \
38                 switch (_argtypes[_i]) {                                \
39                 case PA_INT:                                            \
40                 case PA_INT|PA_FLAG_SHORT:                              \
41                 case PA_CHAR:                                           \
42                         (void) va_arg(ap, int);                         \
43                         break;                                          \
44                 case PA_INT|PA_FLAG_LONG:                               \
45                         (void) va_arg(ap, long int);                    \
46                         break;                                          \
47                 case PA_INT|PA_FLAG_LONG_LONG:                          \
48                         (void) va_arg(ap, long long int);               \
49                         break;                                          \
50                 case PA_WCHAR:                                          \
51                         (void) va_arg(ap, wchar_t);                     \
52                         break;                                          \
53                 case PA_WSTRING:                                        \
54                 case PA_STRING:                                         \
55                 case PA_POINTER:                                        \
56                         (void) va_arg(ap, void*);                       \
57                         break;                                          \
58                 case PA_FLOAT:                                          \
59                 case PA_DOUBLE:                                         \
60                         (void) va_arg(ap, double);                      \
61                         break;                                          \
62                 case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:                     \
63                         (void) va_arg(ap, long double);                 \
64                         break;                                          \
65                 default:                                                \
66                         assert_not_reached();                           \
67                 }                                                       \
68         }                                                               \
69 } while (false)
70