summaryrefslogtreecommitdiff
path: root/sexp-format.c
diff options
context:
space:
mode:
authorNiels Möller <nisse@lysator.liu.se>2002-11-07 09:26:30 +0100
committerNiels Möller <nisse@lysator.liu.se>2002-11-07 09:26:30 +0100
commitfe5c484c4e3da3465f63c393a0386c7f87aaae71 (patch)
tree403555a82168114c5ff863ebf352bdf90e17a42e /sexp-format.c
parent40157693bc73f3816b8804840bb8a0d6224764ad (diff)
downloadnettle-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.c210
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;
+}