diff options
author | kientzle <kientzle@FreeBSD.org> | 2005-01-16 22:13:51 +0000 |
---|---|---|
committer | kientzle <kientzle@FreeBSD.org> | 2005-01-16 22:13:51 +0000 |
commit | c78b57210eccac72647f863add37103f63772aa7 (patch) | |
tree | bfb0a79c240b0b2d8edd9439617cd84a4665df3f /lib/libarchive | |
parent | a8c5c0fe7e55b0a11c3233f483e36f391f998b16 (diff) | |
download | FreeBSD-src-c78b57210eccac72647f863add37103f63772aa7.zip FreeBSD-src-c78b57210eccac72647f863add37103f63772aa7.tar.gz |
Implement a custom print formatter (archive_string_vsprintf)
for libarchive error messages. Mostly, this
avoids a portability headache related to
copying va_list arguments (some FreeBSD 5
platforms require va_copy; FreeBSD 4 doesn't
support va_copy at all). It also dramatically reduces the
size of libarchive for embedded applications:
a minimal "untar" program using libarchive can now be
under 64k statically linked (as opposed to ~100k
using library *printf() functions).
MFC after: 14 days
Diffstat (limited to 'lib/libarchive')
-rw-r--r-- | lib/libarchive/archive_platform.h | 6 | ||||
-rw-r--r-- | lib/libarchive/archive_string.h | 1 | ||||
-rw-r--r-- | lib/libarchive/archive_string_sprintf.c | 91 | ||||
-rw-r--r-- | lib/libarchive/configure.ac.in | 6 |
4 files changed, 90 insertions, 14 deletions
diff --git a/lib/libarchive/archive_platform.h b/lib/libarchive/archive_platform.h index 490bcba..0e98ad3 100644 --- a/lib/libarchive/archive_platform.h +++ b/lib/libarchive/archive_platform.h @@ -105,6 +105,12 @@ #include <inttypes.h> #endif +/* FreeBSD 4 and earlier lack intmax_t/uintmax_t */ +#if defined(__FreeBSD__) && __FreeBSD__ < 5 +#define intmax_t int64_t +#define uintmax_t uint64_t +#endif + /* TODO: Test for the functions we use as well... */ #if HAVE_SYS_ACL_H #define HAVE_POSIX_ACLS 1 diff --git a/lib/libarchive/archive_string.h b/lib/libarchive/archive_string.h index f4e8b76..c9d1c00 100644 --- a/lib/libarchive/archive_string.h +++ b/lib/libarchive/archive_string.h @@ -67,6 +67,7 @@ __archive_strappend_char_UTF8(struct archive_string *, int); /* Append an integer in the specified base (2 <= base <= 16). */ struct archive_string * __archive_strappend_int(struct archive_string *as, int d, int base); +#define archive_strappend_int __archive_strappend_int /* Basic append operation. */ struct archive_string * diff --git a/lib/libarchive/archive_string_sprintf.c b/lib/libarchive/archive_string_sprintf.c index d5e8d86..64ca7d0 100644 --- a/lib/libarchive/archive_string_sprintf.c +++ b/lib/libarchive/archive_string_sprintf.c @@ -28,10 +28,16 @@ __FBSDID("$FreeBSD$"); /* - * This uses 'printf' family functions, which can cause issues - * for size-critical applications. I've separated it out to make - * this issue clear. (Currently, it is called directly from within - * the core code, so it cannot easily be omitted.) + * The use of printf()-family functions can be troublesome + * for space-constrained applications. In addition, correctly + * implementing this function in terms of vsnprintf() requires + * two calls (one to determine the size, another to format the + * result), which in turn requires duplicating the argument list + * using va_copy, which isn't yet universally available. + * + * So, I've implemented a bare minimum of printf()-like capability + * here. This is only used to format error messages, so doesn't + * require any floating-point support or field-width handling. */ #include <stdio.h> @@ -46,21 +52,78 @@ void __archive_string_vsprintf(struct archive_string *as, const char *fmt, va_list ap) { - size_t l; - va_list ap1; + char long_flag; + intmax_t s; /* Signed integer temp. */ + uintmax_t u; /* Unsigned integer temp. */ + const char *p, *p2; + + __archive_string_ensure(as, 64); if (fmt == NULL) { as->s[0] = 0; return; } - va_copy(ap1, ap); - l = vsnprintf(as->s, as->buffer_length, fmt, ap); - /* If output is bigger than the buffer, resize and try again. */ - if (l+1 >= as->buffer_length) { - __archive_string_ensure(as, l + 1); - l = vsnprintf(as->s, as->buffer_length, fmt, ap1); + long_flag = '\0'; + for (p = fmt; *p != '\0'; p++) { + const char *saved_p = p; + + if (*p != '%') { + archive_strappend_char(as, *p); + continue; + } + + p++; + + switch(*p) { + case 'j': + long_flag = 'j'; + p++; + break; + case 'l': + long_flag = 'l'; + p++; + break; + } + + switch (*p) { + case '%': + __archive_strappend_char(as, '%'); + break; + case 'c': + s = va_arg(ap, int); + __archive_strappend_char(as, s); + break; + case 'd': + switch(long_flag) { + case 'j': s = va_arg(ap, intmax_t); break; + case 'l': s = va_arg(ap, long); break; + default: s = va_arg(ap, int); break; + } + archive_strappend_int(as, s, 10); + break; + case 's': + p2 = va_arg(ap, char *); + archive_strcat(as, p2); + break; + case 'o': case 'u': case 'x': case 'X': + /* Common handling for unsigned integer formats. */ + switch(long_flag) { + case 'j': u = va_arg(ap, uintmax_t); break; + case 'l': u = va_arg(ap, unsigned long); break; + default: u = va_arg(ap, unsigned int); break; + } + /* Format it in the correct base. */ + switch (*p) { + case 'o': archive_strappend_int(as, u, 8); break; + case 'u': archive_strappend_int(as, u, 10); break; + default: archive_strappend_int(as, u, 16); break; + } + break; + default: + /* Rewind and print the initial '%' literally. */ + p = saved_p; + archive_strappend_char(as, *p); + } } - as->length = l; - va_end(ap1); } diff --git a/lib/libarchive/configure.ac.in b/lib/libarchive/configure.ac.in index 2bb657c..0068c8d 100644 --- a/lib/libarchive/configure.ac.in +++ b/lib/libarchive/configure.ac.in @@ -36,6 +36,9 @@ AC_CHECK_TYPE(__int64_t, [long long]) AC_CHECK_TYPE(_int64_t, [__int64_t]) AC_CHECK_TYPE(int64_t, [_int64_t]) +# Likewise, consider defining "intmax_t" in terms of int64_t +AC_CHECK_TYPE(intmax_t, [int64_t]) + # # If any of the common 64-bit unsigned types is defined, set "uint64_t" # @@ -44,6 +47,9 @@ AC_CHECK_TYPE(_uint64_t, [__uint64_t]) AC_CHECK_TYPE(u_int64_t, [_uint64_t]) AC_CHECK_TYPE(uint64_t, [u_int64_t]) +# Likewise, consider defining "uintmax_t" in terms of uint64_t +AC_CHECK_TYPE(uintmax_t, [uint64_t]) + AC_CHECK_MEMBERS([struct stat.st_rdev, struct stat.st_mtimespec.tv_nsec, struct stat.st_mtim.tv_nsec]) AC_CHECK_DECL([EFTYPE], |