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 @@ ...@@ -30,6 +30,7 @@
#include "sexp.h" #include "sexp.h"
#include "buffer.h" #include "buffer.h"
#include <assert.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
...@@ -39,109 +40,203 @@ ...@@ -39,109 +40,203 @@
# include "bignum.h" # include "bignum.h"
#endif #endif
static int /* Code copied from sexp-conv.c: sexp_put_length */
static unsigned
format_prefix(struct nettle_buffer *buffer, format_prefix(struct nettle_buffer *buffer,
unsigned length) unsigned length)
{ {
unsigned prefix_length; unsigned digit = 1;
char prefix[10]; unsigned prefix_length = 1;
for (;;)
{
unsigned next = digit * 10;
if (next > length)
break;
/* NOTE: Using the return value of sprintf is not entirely prefix_length++;
* portable. */ digit = next;
prefix_length = snprintf(prefix, sizeof(prefix), "%u:", length); }
if (prefix_length >= sizeof(prefix))
return 0;
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, format_length_string(struct nettle_buffer *buffer,
unsigned length, const char *s) unsigned length, const char *s)
{ {
return format_prefix(buffer, length) unsigned done = format_prefix(buffer, length);
&& nettle_buffer_write(buffer, length, s); if (!done)
} return 0;
static uint8_t * if (buffer && !nettle_buffer_write(buffer, length, s))
format_space(struct nettle_buffer *buffer, return 0;
unsigned length)
{ return done + length;
return format_prefix(buffer, length)
? nettle_buffer_space(buffer, length) : NULL;
} }
static int static unsigned
format_string(struct nettle_buffer *buffer, format_string(struct nettle_buffer *buffer,
const char *s) const char *s)
{ {
return format_length_string(buffer, strlen(s), s); return format_length_string(buffer, strlen(s), s);
} }
int unsigned
sexp_format(struct nettle_buffer *buffer, const char *format, ...) sexp_vformat(struct nettle_buffer *buffer, const char *format, va_list args)
{ {
va_list args;
unsigned nesting = 0; unsigned nesting = 0;
unsigned done = 0;
va_start(args, format);
for (;;) for (;;)
switch (*format++) switch (*format++)
{ {
case '\0': case '\0':
if (nesting) assert(!nesting);
{
fail: return done;
va_end(args);
return 0;
}
else
{
va_end(args);
return 1;
}
case '(': case '(':
if (!NETTLE_BUFFER_PUTC(buffer, '(')) if (buffer && !NETTLE_BUFFER_PUTC(buffer, '('))
goto fail; return 0;
done++;
nesting++; nesting++;
break; break;
case ')': case ')':
if (!nesting) assert (nesting);
abort(); if (buffer && !NETTLE_BUFFER_PUTC(buffer, ')'))
if (!NETTLE_BUFFER_PUTC(buffer, ')')) return 0;
goto fail;
done++;
nesting--; nesting--;
break; break;
case '%': case '%':
switch (*format++) 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': 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 *); 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; break;
} }
case 'b': case 'b':
{ {
#if HAVE_LIBGMP #if HAVE_LIBGMP
const MP_INT *n = va_arg(args, const MP_INT *); const MP_INT *n = va_arg(args, const MP_INT *);
uint8_t *space;
unsigned length; unsigned length;
unsigned prefix_length;
if (mpz_sgn(n) < 0) assert(mpz_sgn(n) >= 0);
goto fail;
length = nettle_mpz_sizeinbase_256(n); 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 (buffer)
if (!space) {
goto fail; uint8_t *space = nettle_buffer_space(buffer, length);
nettle_mpz_get_str_256(length, space, n); if (!space)
return 0;
nettle_mpz_get_str_256(length, space, n);
}
done += length;
#else /* ! HAVE_LIBGMP */ #else /* ! HAVE_LIBGMP */
abort(); abort();
#endif /* ! HAVE_LIBGMP */ #endif /* ! HAVE_LIBGMP */
...@@ -152,3 +247,16 @@ sexp_format(struct nettle_buffer *buffer, const char *format, ...) ...@@ -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 @@ ...@@ -27,6 +27,7 @@
#define NETTLE_SEXP_H_INCLUDED #define NETTLE_SEXP_H_INCLUDED
#include <inttypes.h> #include <inttypes.h>
#include <stdarg.h>
enum sexp_type enum sexp_type
{ SEXP_ATOM, SEXP_LIST, SEXP_END }; { SEXP_ATOM, SEXP_LIST, SEXP_END };
...@@ -94,6 +95,8 @@ sexp_iterator_check_types(struct sexp_iterator *iterator, ...@@ -94,6 +95,8 @@ sexp_iterator_check_types(struct sexp_iterator *iterator,
* *
* For a matching key, the corresponding iterator is initialized * For a matching key, the corresponding iterator is initialized
* pointing at the start of REST. * pointing at the start of REST.
*
* On success, exits the current list.
*/ */
int int
sexp_iterator_assoc(struct sexp_iterator *iterator, sexp_iterator_assoc(struct sexp_iterator *iterator,
...@@ -108,15 +111,42 @@ sexp_iterator_assoc(struct sexp_iterator *iterator, ...@@ -108,15 +111,42 @@ sexp_iterator_assoc(struct sexp_iterator *iterator,
/* Declared for real in buffer.h */ /* Declared for real in buffer.h */
struct nettle_buffer; struct nettle_buffer;
int /* Returns the number of output characters, or 0 on out of memory. If
sexp_format(struct nettle_buffer *buffer, const char *format, ...); * 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, sexp_transport_format(struct nettle_buffer *buffer,
/* If non-zero, break lines to at most
* line_length characters. */
unsigned line_length,
const char *format, ...); const char *format, ...);
unsigned
sexp_transport_vformat(struct nettle_buffer *buffer,
const char *format, va_list args);
#endif /* NETTLE_SEXP_H_INCLUDED */ #endif /* NETTLE_SEXP_H_INCLUDED */
Supports Markdown
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