summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorkientzle <kientzle@FreeBSD.org>2005-01-16 22:13:51 +0000
committerkientzle <kientzle@FreeBSD.org>2005-01-16 22:13:51 +0000
commitc78b57210eccac72647f863add37103f63772aa7 (patch)
treebfb0a79c240b0b2d8edd9439617cd84a4665df3f /lib
parenta8c5c0fe7e55b0a11c3233f483e36f391f998b16 (diff)
downloadFreeBSD-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')
-rw-r--r--lib/libarchive/archive_platform.h6
-rw-r--r--lib/libarchive/archive_string.h1
-rw-r--r--lib/libarchive/archive_string_sprintf.c91
-rw-r--r--lib/libarchive/configure.ac.in6
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],
OpenPOWER on IntegriCloud