/* See LICENSE file for copyright and license details. */ #ifndef LIBABORT_H #define LIBABORT_H #include #include #include #include #include #if defined(__GNUC__) # if defined(__clang__) # define LIBABORT_PRINTF__(FMT, ARGS) __attribute__((__format__(__printf__, FMT, ARGS))) # else # define LIBABORT_PRINTF__(FMT, ARGS) __attribute__((__format__(__gnu_printf__, FMT, ARGS))) # endif # define LIBABORT_NONNULL__(INDEX) __attribute__((__nonnull__(INDEX))) # define LIBABORT_ALL_NONNULL__ __attribute__((__nonnull__)) # define LIBABORT_PURE__ __attribute__((__pure__)) #else # define LIBABORT_PRINTF__(FMT, ARGS) # define LIBABORT_NONNULL__(INDEX) # define LIBABORT_ALL_NONNULL__ # define LIBABORT_PURE__ #endif #ifndef LIBABORT_NO_SHORTHANDS # ifndef stracpy # define stracpy libabort_stracpy # endif # ifndef saprintf # define saprintf libabort_saprintf # endif # ifndef vsaprintf # define vsaprintf libabort_vsaprintf # endif # ifndef stpacpy # define stpacpy libabort_stpacpy # endif # ifndef stracat # define stracat libabort_stracat # endif # ifndef stralen # define stralen libabort_stralen # endif # ifndef stpacat # define stpacat libabort_stpacat # endif #endif /** * libabort_stracpy * * Copy a string like strncpy(3), but abort if truncation would occur * * @param dst The destination buffer * @param src The source string * @param size The size of `dst`, in bytes * @return `dst` */ LIBABORT_ALL_NONNULL__ inline char * libabort_stracpy(char *dst, const char *src, size_t size) { size_t i; for (i = 0; i < size; i++) if ((dst[i] = src[i]) == '\0') return dst; abort(); } /** * libabort_stpacpy * * Copy a string like stpcpy(3), but abort if truncation would occur. * * @param dst The destination buffer * @param src The source string * @param size The size of `dst`, in bytes * @return A pointer to the terminating NUL byte in `dst` */ LIBABORT_ALL_NONNULL__ inline char * libabort_stpacpy(char *dst, const char *src, size_t size) { size_t i; for (i = 0; i < size; i++) if ((dst[i] = src[i]) == '\0') return &dst[i]; abort(); } /** * libabort_stracat * * Concatenate strings like strcat(3), but abort if truncation would occur. * * @param dst The destination buffer (must contain a NUL-terminated string) * @param src The source string * @param size The size of `dst`, in bytes * @return `dst` */ LIBABORT_ALL_NONNULL__ inline char * libabort_stracat(char *dst, const char *src, size_t size) { size_t i, j; for (i = 0; i < size; i++) if (dst[i] == '\0') break; if (i == size) abort(); for (j = 0; i < size; i++, j++) if ((dst[i] = src[j]) == '\0') return dst; abort(); } /** * libabort_stralen * * Get the length of a string like strlen(3), but abort if no NUL byte is found * within `size` bytes. * * @param str The string * @param size The maximum number of bytes to examine * @return The length of the string, excluding the terminating NUL byte */ LIBABORT_PURE__ LIBABORT_ALL_NONNULL__ inline size_t libabort_stralen(const char *str, size_t size) { size_t i; for (i = 0; i < size; i++) if (!str[i]) return i; abort(); } /** * libabort_stpacat * * Concatenate strings like stpcat(3) would (non-standard), but abort if * truncation would occur. * * @param dst The destination buffer (must contain a NUL-terminated string) * @param src The source string * @param size The size of `dst`, in bytes * @return A pointer to the terminating NUL byte in `dst` */ LIBABORT_ALL_NONNULL__ inline char * libabort_stpacat(char *dst, const char *src, size_t size) { size_t i, j; for (i = 0; i < size; i++) if (dst[i] == '\0') break; if (i == size) abort(); for (j = 0; i < size; i++, j++) if ((dst[i] = src[j]) == '\0') return &dst[i]; abort(); } /** * libabort_vsaprintf * * Format a string like vsnprintf(3), but abort if truncation would occur * * @param buf The output buffer * @param size The size of `buf`, in bytes * @param fmt The format string * @param ap The format arguments * @return The number of bytes written excluding the terminating NUL byte * * NB! This function aborts if `size` is 0, use vsnprintf(3) get the size required for `buf` */ LIBABORT_NONNULL__(1) LIBABORT_NONNULL__(3) LIBABORT_PRINTF__(3, 0) inline int libabort_vsaprintf(char *buf, size_t size, const char *fmt, va_list ap) { int n = vsnprintf(buf, size, fmt, ap); if (n < 0 || (size_t)n >= size) abort(); return n; } /** * libabort_saprintf * * Format a string like snprintf(3), but abort if truncation would occur * * @param buf The output buffer * @param size The size of `buf`, in bytes * @param fmt The format string * @return The number of bytes written excluding the terminating NUL byte * * NB! This function aborts if `size` is 0, use snprintf(3) get the size required for `buf` */ LIBABORT_NONNULL__(1) LIBABORT_NONNULL__(3) LIBABORT_PRINTF__(3, 4) inline int libabort_saprintf(char *buf, size_t size, const char *fmt, ...) { va_list ap; int r; va_start(ap, fmt); r = libabort_vsaprintf(buf, size, fmt, ap); va_end(ap); return r; } #undef LIBABORT_PRINTF__ #undef LIBABORT_NONNULL__ #undef LIBABORT_ALL_NONNULL__ #endif