diff options
author | Niels Möller <nisse@lysator.liu.se> | 2002-11-07 09:26:30 +0100 |
---|---|---|
committer | Niels Möller <nisse@lysator.liu.se> | 2002-11-07 09:26:30 +0100 |
commit | fe5c484c4e3da3465f63c393a0386c7f87aaae71 (patch) | |
tree | 403555a82168114c5ff863ebf352bdf90e17a42e /sexp-format.c | |
parent | 40157693bc73f3816b8804840bb8a0d6224764ad (diff) | |
download | nettle-fe5c484c4e3da3465f63c393a0386c7f87aaae71.tar.gz |
(sexp_format): Return length of output. Allow
buffer == NULL, and onyl compute the needed length in this case.
Renamed %s to %z. New format specifiers %s, %i, and %l.
(sexp_vformat): New function.
(format_prefix): Rewrote to not use snprintf.
Rev: src/nettle/sexp-format.c:1.2
Rev: src/nettle/sexp.h:1.7
Diffstat (limited to 'sexp-format.c')
-rw-r--r-- | sexp-format.c | 210 |
1 files changed, 159 insertions, 51 deletions
diff --git a/sexp-format.c b/sexp-format.c index 2480613c..22b7bc4a 100644 --- a/sexp-format.c +++ b/sexp-format.c @@ -30,6 +30,7 @@ #include "sexp.h" #include "buffer.h" +#include <assert.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> @@ -39,109 +40,203 @@ # include "bignum.h" #endif -static int +/* Code copied from sexp-conv.c: sexp_put_length */ +static unsigned format_prefix(struct nettle_buffer *buffer, unsigned length) { - unsigned prefix_length; - char prefix[10]; + unsigned digit = 1; + unsigned prefix_length = 1; + + for (;;) + { + unsigned next = digit * 10; + if (next > length) + break; - /* NOTE: Using the return value of sprintf is not entirely - * portable. */ - prefix_length = snprintf(prefix, sizeof(prefix), "%u:", length); - if (prefix_length >= sizeof(prefix)) - return 0; + prefix_length++; + digit = next; + } - return nettle_buffer_write(buffer, prefix_length, prefix); + if (buffer) + { + for (; digit; length %= digit, digit /= 10) + if (!NETTLE_BUFFER_PUTC(buffer, '0' + length / digit)) + return 0; + + if (!NETTLE_BUFFER_PUTC(buffer, ':')) + return 0; + } + + return prefix_length + 1; } -static int +static unsigned format_length_string(struct nettle_buffer *buffer, unsigned length, const char *s) { - return format_prefix(buffer, length) - && nettle_buffer_write(buffer, length, s); -} + unsigned done = format_prefix(buffer, length); + if (!done) + return 0; -static uint8_t * -format_space(struct nettle_buffer *buffer, - unsigned length) -{ - return format_prefix(buffer, length) - ? nettle_buffer_space(buffer, length) : NULL; + if (buffer && !nettle_buffer_write(buffer, length, s)) + return 0; + + return done + length; } -static int +static unsigned format_string(struct nettle_buffer *buffer, const char *s) { return format_length_string(buffer, strlen(s), s); } -int -sexp_format(struct nettle_buffer *buffer, const char *format, ...) +unsigned +sexp_vformat(struct nettle_buffer *buffer, const char *format, va_list args) { - va_list args; unsigned nesting = 0; - - va_start(args, format); + unsigned done = 0; for (;;) switch (*format++) { case '\0': - if (nesting) - { - fail: - va_end(args); - return 0; - } - else - { - va_end(args); - return 1; - } + assert(!nesting); + + return done; + case '(': - if (!NETTLE_BUFFER_PUTC(buffer, '(')) - goto fail; + if (buffer && !NETTLE_BUFFER_PUTC(buffer, '(')) + return 0; + done++; nesting++; break; case ')': - if (!nesting) - abort(); - if (!NETTLE_BUFFER_PUTC(buffer, ')')) - goto fail; - + assert (nesting); + if (buffer && !NETTLE_BUFFER_PUTC(buffer, ')')) + return 0; + + done++; nesting--; break; case '%': switch (*format++) { + case 'z': + { + const char *s = va_arg(args, const char *); + unsigned length = format_string(buffer, s); + + if (!length) + return 0; + + done += length; + break; + } case 's': { + unsigned length = va_arg(args, unsigned); + const char *s = va_arg(args, const char *); + unsigned prefix_length = format_prefix(buffer, length); + + if (!prefix_length) + return 0; + + done += prefix_length; + + if (buffer && !nettle_buffer_write(buffer, length, s)) + return 0; + + done += length; + + break; + } + case 'l': + { + unsigned length = va_arg(args, unsigned); const char *s = va_arg(args, const char *); - format_string(buffer, s); + + if (buffer && !nettle_buffer_write(buffer, length, s)) + return 0; + + done += length; + break; + } + case 'i': + { + uint32_t x = va_arg(args, uint32_t); + unsigned length; + + if (x < 0x100) + length = 1; + else if (x < 0x10000L) + length = 2; + else if (x < 0x1000000L) + length = 3; + else + length = 4; + + if (buffer && !(NETTLE_BUFFER_PUTC(buffer, '0' + length) + && NETTLE_BUFFER_PUTC(buffer, ':'))) + return 0; + + done += (2 + length); + + if (buffer) + switch(length) + { + case 4: + if (!NETTLE_BUFFER_PUTC(buffer, x >> 24)) + return 0; + /* Fall through */ + case 3: + if (!NETTLE_BUFFER_PUTC(buffer, (x >> 16) & 0xff)) + return 0; + /* Fall through */ + case 2: + if (!NETTLE_BUFFER_PUTC(buffer, (x >> 8) & 0xff)) + return 0; + /* Fall through */ + case 1: + if (!NETTLE_BUFFER_PUTC(buffer, x & 0xff)) + return 0; + break; + default: + abort(); + } break; } case 'b': { #if HAVE_LIBGMP const MP_INT *n = va_arg(args, const MP_INT *); - uint8_t *space; unsigned length; + unsigned prefix_length; - if (mpz_sgn(n) < 0) - goto fail; + assert(mpz_sgn(n) >= 0); length = nettle_mpz_sizeinbase_256(n); + prefix_length = format_prefix(buffer, length); + if (!prefix_length) + return 0; + + done += prefix_length; - space = format_space(buffer, length); - if (!space) - goto fail; - nettle_mpz_get_str_256(length, space, n); + if (buffer) + { + uint8_t *space = nettle_buffer_space(buffer, length); + if (!space) + return 0; + + nettle_mpz_get_str_256(length, space, n); + } + + done += length; + #else /* ! HAVE_LIBGMP */ abort(); #endif /* ! HAVE_LIBGMP */ @@ -152,3 +247,16 @@ sexp_format(struct nettle_buffer *buffer, const char *format, ...) } } } + +unsigned +sexp_format(struct nettle_buffer *buffer, const char *format, ...) +{ + va_list args; + unsigned done; + + va_start(args, format); + done = sexp_vformat(buffer, format, args); + va_end(args); + + return done; +} |