Skip to content

Commit

Permalink
lib/sprintf.[ch]: Add [v]snprintf_()
Browse files Browse the repository at this point in the history
These functions are like [v]snprintf(3), but return -1 on truncation,
which makes it easier to test.  snprintf(3) is iseful in two cases:

-  We don't care if the output is truncated.  snprintf(3) is fine for
   those, and the return value can be ignored.

-  Truncation is bad.  In that case, it's as bad as a hard error (-1)
   from snprintf, so merging both problems into the same error code
   makes it easier to handle errors.  Return the length if no truncation
   so that we can use it if necessary.

Signed-off-by: Alejandro Colomar <[email protected]>
  • Loading branch information
alejandro-colomar committed Sep 6, 2023
1 parent 1814877 commit 233370e
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 10 deletions.
5 changes: 5 additions & 0 deletions lib/sprintf.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ extern inline int xasprintf(char **restrict s, const char *restrict fmt, ...);
extern inline int xvasprintf(char **restrict s, const char *restrict fmt,
va_list ap);

extern inline int snprintf_(char *restrict s, int size,
const char *restrict fmt, ...);
extern inline int vsnprintf_(char *restrict s, int size,
const char *restrict fmt, va_list ap);

extern inline int xsnprintf(char *restrict s, int size,
const char *restrict fmt, ...);
extern inline int xvsnprintf(char *restrict s, int size,
Expand Down
46 changes: 36 additions & 10 deletions lib/sprintf.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,7 @@


#define SNPRINTF(s, fmt, ...) \
({ \
size_t sz_, len_; \
\
sz_ = SIZEOF_ARRAY(s); \
len_ = snprintf(s, sz_, fmt __VA_OPT__(,) __VA_ARGS__); \
\
(len_ >= sz_) ? -1 : len_; \
})
snprintf_(s, SIZEOF_ARRAY(s), fmt __VA_OPT__(,) __VA_ARGS__)

#define XSNPRINTF(s, fmt, ...) \
xsnprintf(s, SIZEOF_ARRAY(s), fmt __VA_OPT__(,) __VA_ARGS__)
Expand All @@ -37,6 +30,12 @@ inline int xasprintf(char **restrict s, const char *restrict fmt, ...);
format_attr(printf, 2, 0)
inline int xvasprintf(char **restrict s, const char *restrict fmt, va_list ap);

format_attr(printf, 3, 4)
inline int snprintf_(char *restrict s, int size, const char *restrict fmt, ...);
format_attr(printf, 3, 0)
inline int vsnprintf_(char *restrict s, int size, const char *restrict fmt,
va_list ap);

format_attr(printf, 3, 4)
inline int xsnprintf(char *restrict s, int size, const char *restrict fmt, ...);
format_attr(printf, 3, 0)
Expand Down Expand Up @@ -73,6 +72,33 @@ xvasprintf(char **restrict s, const char *restrict fmt, va_list ap)
}


inline int
snprintf_(char *restrict s, int size, const char *restrict fmt, ...)
{
int len;
va_list ap;

va_start(ap, fmt);
len = vsnprintf_(s, size, fmt, ap);
va_end(ap);

return len;
}


inline int
vsnprintf_(char *restrict s, int size, const char *restrict fmt, va_list ap)
{
int len;

len = vsnprintf(s, size, fmt, ap);
if (len >= size)
len = -1;

return len;
}


inline int
xsnprintf(char *restrict s, int size, const char *restrict fmt, ...)
{
Expand All @@ -92,8 +118,8 @@ xvsnprintf(char *restrict s, int size, const char *restrict fmt, va_list ap)
{
int len;

len = vsnprintf(s, size, fmt, ap);
if (len == -1 || len >= size) {
len = vsnprintf_(s, size, fmt, ap);
if (len == -1) {
perror("snprintf");
exit(EXIT_FAILURE);
}
Expand Down

0 comments on commit 233370e

Please sign in to comment.