Commit fe5c484c authored by Niels Möller's avatar Niels Möller
Browse files

(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
parent 40157693
......@@ -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;
}
......@@ -27,6 +27,7 @@
#define NETTLE_SEXP_H_INCLUDED
#include <inttypes.h>
#include <stdarg.h>
enum sexp_type
{ SEXP_ATOM, SEXP_LIST, SEXP_END };
......@@ -94,6 +95,8 @@ sexp_iterator_check_types(struct sexp_iterator *iterator,
*
* For a matching key, the corresponding iterator is initialized
* pointing at the start of REST.
*
* On success, exits the current list.
*/
int
sexp_iterator_assoc(struct sexp_iterator *iterator,
......@@ -108,15 +111,42 @@ sexp_iterator_assoc(struct sexp_iterator *iterator,
/* Declared for real in buffer.h */
struct nettle_buffer;
int
sexp_format(struct nettle_buffer *buffer, const char *format, ...);
/* Returns the number of output characters, or 0 on out of memory. If
* buffer == NULL, just compute length.
*
* Format strings can contained matched parentheses, and the following
* formatting specifiers:
*
* %z NUL-terminated string, const uint8_t *.
*
* %s String represented as unsigned length, const uint8_t *data.
*
* %i Non-negative small integer, uint32_t.
*
* %b Non-negative bignum, mpz_t.
*
* %l Literal string (no length added), typically a balanced
* subexpression. Represented as unsigned length, const uint8_t
* *data.
*/
int
unsigned
sexp_format(struct nettle_buffer *buffer,
const char *format, ...);
unsigned
sexp_vformat(struct nettle_buffer *buffer,
const char *format, va_list args);
/* FIXME: Add argument LINE_WIDTH. If non-zero, break lines to at most
* that width. */
unsigned
sexp_transport_format(struct nettle_buffer *buffer,
/* If non-zero, break lines to at most
* line_length characters. */
unsigned line_length,
const char *format, ...);
unsigned
sexp_transport_vformat(struct nettle_buffer *buffer,
const char *format, va_list args);
#endif /* NETTLE_SEXP_H_INCLUDED */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment