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