]> git.ipfire.org Git - thirdparty/nettle.git/commitdiff
(sexp_format): Return length of output. Allow
authorNiels Möller <nisse@lysator.liu.se>
Thu, 7 Nov 2002 08:26:30 +0000 (09:26 +0100)
committerNiels Möller <nisse@lysator.liu.se>
Thu, 7 Nov 2002 08:26:30 +0000 (09:26 +0100)
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

sexp-format.c
sexp.h

index 2480613cc4cb86d9d1d98805664b944700c18640..22b7bc4a98deed5755581a5b992c7e6f15cab732 100644 (file)
@@ -30,6 +30,7 @@
 #include "sexp.h"
 #include "buffer.h"
 
+#include <assert.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 # 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;
+}
diff --git a/sexp.h b/sexp.h
index 24d1906315be2bffccc565904d3f306697284571..21e88eafe004d892cc98cb58310ca9e0f996890e 100644 (file)
--- a/sexp.h
+++ b/sexp.h
@@ -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 */