1 #ifndef STRACE_XSTRING_H 2 #define STRACE_XSTRING_H 3 4 #include <stdarg.h> 5 #include <stdio.h> 6 7 #include "error_prints.h" 8 #include "gcc_compat.h" 9 10 /** 11 * Print to static buffer and die on (really unexpected) errors and overflows. 12 * Shouldn't be used directly; please refer to helper macros xsnprintf and 13 * xsprint instead. 14 * 15 * @param str String buffer to print into. 16 * @param size Size of the string buffer in bytes. 17 * @param func Function name from which this function is called. 18 * @param argstr Stringified arguments (including format argument). 19 * @param format Format string. 20 * @param ... Format arguments. 21 * @return Number of characters printed, excluding terminating null byte 22 * (the same as s(n)printf). 23 */ 24 static inline int ATTRIBUTE_FORMAT((printf, 5, 6)) 25 xsnprintf_(char *str, size_t size, const char *func, const char *argstr, 26 const char *format, ...) 27 { 28 int ret; 29 va_list ap; 30 31 va_start(ap, format); 32 ret = vsnprintf(str, size, format, ap); 33 va_end(ap); 34 35 if (ret < 0 || (unsigned int) ret >= size) 36 error_msg_and_die("%s: got unexpected return value %d for " 37 "snprintf(buf, %zu, %s)", 38 func, ret, size, argstr); 39 40 return ret; 41 } 42 43 /** 44 * snprintf that dies on (really unexpected) errors and overflows. 45 * 46 * @param str_ String buffer to print into. 47 * @param size_ Size of the string buffer in bytes. 48 * @param fmt_ Format string. 49 * @param ... Format arguments. 50 */ 51 #define xsnprintf(str_, size_, fmt_, ...) \ 52 xsnprintf_((str_), (size_), __func__, #fmt_ ", " #__VA_ARGS__, \ 53 (fmt_), __VA_ARGS__) 54 55 /** 56 * Print to a character array buffer and die on (really unexpected) errors and 57 * overflows. Buffer size is obtained with sizeof(). 58 * 59 * @param str_ Character array buffer to print into. 60 * @param fmt_ Format string. 61 * @param ... Format arguments. 62 */ 63 #define xsprintf(str_, fmt_, ...) \ 64 xsnprintf((str_), sizeof(str_) + MUST_BE_ARRAY(str_), (fmt_), \ 65 __VA_ARGS__) 66 67 static inline size_t 68 get_pos_diff_(char *str, size_t size, char *pos, const char *func, 69 const char *call) 70 { 71 if ((str + size) < str) 72 error_msg_and_die("%s: string size overflow (%p+%zu) in %s", 73 func, str, size, call); 74 75 if (pos > (str + size)) 76 error_msg_and_die("%s: got position (%p) beyond string " 77 "(%p+%zu) in %s", 78 func, pos, str, size, call); 79 80 if (pos < str) 81 error_msg_and_die("%s: got position %p before string %p in %s", 82 func, pos, str, call); 83 84 return pos - str; 85 } 86 87 /** 88 * Helper function for constructing string in a character array by appending 89 * new formatted parts. Returns new position. Fails on error or buffer 90 * overflow, in line with the rest of x* functions. Obtains buffer size via 91 * sizeof(str_). 92 * 93 * @param str_ Character array buffer to print into. 94 * @param pos_ Current position. 95 * @param fmt_ Format string. 96 * @param ... Format arguments. 97 * @return New position. 98 */ 99 #define xappendstr(str_, pos_, fmt_, ...) \ 100 (xsnprintf((pos_), sizeof(str_) + MUST_BE_ARRAY(str_) - \ 101 get_pos_diff_((str_), sizeof(str_), (pos_), __func__, \ 102 "xappendstr(" #str_ ", " #pos_ ", " #fmt_ ", " \ 103 #__VA_ARGS__ ")"), \ 104 (fmt_), ##__VA_ARGS__) + (pos_)) 105 106 #endif /* !STRACE_XSTRING_H */ 107