#ifndef STRACE_XSTRING_H #define STRACE_XSTRING_H #include <stdarg.h> #include <stdio.h> #include "error_prints.h" #include "gcc_compat.h" /** * Print to static buffer and die on (really unexpected) errors and overflows. * Shouldn't be used directly; please refer to helper macros xsnprintf and * xsprint instead. * * @param str String buffer to print into. * @param size Size of the string buffer in bytes. * @param func Function name from which this function is called. * @param argstr Stringified arguments (including format argument). * @param format Format string. * @param ... Format arguments. * @return Number of characters printed, excluding terminating null byte * (the same as s(n)printf). */ static inline int ATTRIBUTE_FORMAT((printf, 5, 6)) xsnprintf_(char *str, size_t size, const char *func, const char *argstr, const char *format, ...) { int ret; va_list ap; va_start(ap, format); ret = vsnprintf(str, size, format, ap); va_end(ap); if (ret < 0 || (unsigned int) ret >= size) error_msg_and_die("%s: got unexpected return value %d for " "snprintf(buf, %zu, %s)", func, ret, size, argstr); return ret; } /** * snprintf that dies on (really unexpected) errors and overflows. * * @param str_ String buffer to print into. * @param size_ Size of the string buffer in bytes. * @param fmt_ Format string. * @param ... Format arguments. */ #define xsnprintf(str_, size_, fmt_, ...) \ xsnprintf_((str_), (size_), __func__, #fmt_ ", " #__VA_ARGS__, \ (fmt_), __VA_ARGS__) /** * Print to a character array buffer and die on (really unexpected) errors and * overflows. Buffer size is obtained with sizeof(). * * @param str_ Character array buffer to print into. * @param fmt_ Format string. * @param ... Format arguments. */ #define xsprintf(str_, fmt_, ...) \ xsnprintf((str_), sizeof(str_) + MUST_BE_ARRAY(str_), (fmt_), \ __VA_ARGS__) static inline size_t get_pos_diff_(char *str, size_t size, char *pos, const char *func, const char *call) { if ((str + size) < str) error_msg_and_die("%s: string size overflow (%p+%zu) in %s", func, str, size, call); if (pos > (str + size)) error_msg_and_die("%s: got position (%p) beyond string " "(%p+%zu) in %s", func, pos, str, size, call); if (pos < str) error_msg_and_die("%s: got position %p before string %p in %s", func, pos, str, call); return pos - str; } /** * Helper function for constructing string in a character array by appending * new formatted parts. Returns new position. Fails on error or buffer * overflow, in line with the rest of x* functions. Obtains buffer size via * sizeof(str_). * * @param str_ Character array buffer to print into. * @param pos_ Current position. * @param fmt_ Format string. * @param ... Format arguments. * @return New position. */ #define xappendstr(str_, pos_, fmt_, ...) \ (xsnprintf((pos_), sizeof(str_) + MUST_BE_ARRAY(str_) - \ get_pos_diff_((str_), sizeof(str_), (pos_), __func__, \ "xappendstr(" #str_ ", " #pos_ ", " #fmt_ ", " \ #__VA_ARGS__ ")"), \ (fmt_), ##__VA_ARGS__) + (pos_)) #endif /* !STRACE_XSTRING_H */