Browse Source

Implement the remaining writer functions, import fpconv

Adrian Perez de Castro 6 years ago
parent
commit
8768ec52d9
6 changed files with 213 additions and 4 deletions
  1. 1 0
      .gitignore
  2. 3 0
      .gitmodules
  3. 8 1
      Makefile
  4. 1 0
      fpconv
  5. 188 0
      hipack-writer.c
  6. 12 3
      hipack.h

+ 1 - 0
.gitignore

@@ -4,3 +4,4 @@
 *.gcda
 *.gcno
 tools/hipack-parse
+tools/hipack-roundtrip

+ 3 - 0
.gitmodules

@@ -0,0 +1,3 @@
+[submodule "fpconv"]
+	path = fpconv
+	url = https://github.com/night-shift/fpconv/

+ 8 - 1
Makefile

@@ -30,7 +30,14 @@ ${hipack_PATH}/tools/hipack-parse: \
 ${hipack_PATH}/tools/hipack-roundtrip: \
 	${hipack_PATH}/tools/hipack-roundtrip.o ${hipack}
 
-hipack-check: ${hipack_PATH}/tools/hipack-parse
+hipack-check: \
+		${hipack_PATH}/tools/hipack-parse \
+		${hipack_PATH}/tools/hipack-roundtrip
 	@${hipack_PATH}/tools/run-tests
 
+${hipack_PATH}/hipack-writer.o: ${hipack_PATH}/fpconv/src/fpconv.c
+${hipack_PATH}/fpconv/src/fpconv.c: ${hipack_PATH}/.gitmodules
+	cd ${hipack_PATH} && git submodule init fpconv
+	cd ${hipack_PATH} && git submodule update fpconv
+
 .PHONY: hipack hipack-objs hipack-tools hipack-check

+ 1 - 0
fpconv

@@ -0,0 +1 @@
+Subproject commit 11ed624b20a3bda6284a428b35d4e8815e47e098

+ 188 - 0
hipack-writer.c

@@ -7,6 +7,15 @@
 
 #include "hipack.h"
 
+/*
+ * Define FPCONV_H to avoid fpconv/src/fpconv.h being included.
+ * By making our own definition of the function here, it can be
+ * marked as "static inline".
+ */
+#define FPCONV_H 1
+static inline int fpconv_dtoa (double fp, char dest[24]);
+#include "fpconv/src/fpconv.c"
+
 
 static inline bool
 writechar (hipack_writer_t *writer, int ch)
@@ -28,6 +37,34 @@ writechar (hipack_writer_t *writer, int ch)
     } while (0)
 
 
+static inline void
+moreindent (hipack_writer_t *writer)
+{
+    if (writer->indent != HIPACK_WRITER_COMPACT)
+        writer->indent++;
+}
+
+
+static inline void
+lessindent (hipack_writer_t *writer)
+{
+    if (writer->indent != HIPACK_WRITER_COMPACT)
+        writer->indent--;
+}
+
+
+static inline bool
+writeindent (hipack_writer_t *writer)
+{
+    int32_t num_spaces = (writer->indent != HIPACK_WRITER_COMPACT)
+        ? writer->indent * 2 : 0;
+    while (num_spaces--) {
+        CHECK_IO (writechar (writer, ' '));
+    }
+    return false;
+}
+
+
 static inline bool
 writedata (hipack_writer_t *writer,
            const char      *data,
@@ -84,6 +121,35 @@ hipack_write_bool (hipack_writer_t *writer,
 }
 
 
+bool
+hipack_write_integer (hipack_writer_t *writer,
+                      const int32_t    value)
+{
+    assert (writer);
+    if (value < 0) {
+        CHECK_IO (writechar (writer, '-'));
+        return formatint (writer, -value, 10);
+    } else {
+        return formatint (writer, value, 10);
+    }
+}
+
+
+bool
+hipack_write_float (hipack_writer_t *writer,
+                    const double     value)
+{
+    assert (writer);
+
+    char buf[24];
+    int nchars = fpconv_dtoa (value, buf);
+    for (int i = 0; i < nchars; i++) {
+        CHECK_IO (writechar (writer, buf[i]));
+    }
+    return false;
+}
+
+
 bool
 hipack_write_string (hipack_writer_t       *writer,
                      const hipack_string_t *hstr)
@@ -128,12 +194,134 @@ hipack_write_string (hipack_writer_t       *writer,
 }
 
 
+static bool
+write_keyval (hipack_writer_t     *writer,
+              const hipack_dict_t *dict)
+{
+    const hipack_string_t *key;
+    hipack_value_t *value;
+    HIPACK_DICT_FOREACH (dict, key, value) {
+        writeindent (writer);
+        /* Key */
+        for (uint32_t i = 0; i < key->size; i++) {
+            CHECK_IO (writechar (writer, key->data[i]));
+        }
+
+        switch (value->type) {
+            case HIPACK_INTEGER:
+            case HIPACK_FLOAT:
+            case HIPACK_BOOL:
+            case HIPACK_STRING:
+                CHECK_IO (writechar (writer, ':'));
+                break;
+            case HIPACK_DICT:
+            case HIPACK_LIST:
+                /* No colon. */
+                break;
+            default:
+                assert (false);
+        }
+
+        if (writer->indent != HIPACK_WRITER_COMPACT) {
+            CHECK_IO (writechar (writer, ' '));
+        }
+
+        CHECK_IO (hipack_write_value (writer, value));
+        CHECK_IO (writechar (writer, ','));
+
+        if (writer->indent != HIPACK_WRITER_COMPACT) {
+            CHECK_IO (writechar (writer, '\n'));
+        }
+    }
+
+    return false;
+}
+
+
+bool
+hipack_write_list (hipack_writer_t     *writer,
+                   const hipack_list_t *list)
+{
+    assert (writer);
+    assert (list);
+
+    CHECK_IO (writechar (writer, '['));
+
+    if (writer->indent != HIPACK_WRITER_COMPACT) {
+        CHECK_IO (writechar (writer, '\n'));
+    }
+
+    moreindent (writer);
+    for (uint32_t i = 0; i < list->size; i++) {
+        CHECK_IO (writeindent (writer));
+        CHECK_IO (hipack_write_value (writer, &list->data[i]));
+        CHECK_IO (writechar (writer, ','));
+        if (writer->indent != HIPACK_WRITER_COMPACT) {
+            CHECK_IO (writechar (writer, '\n'));
+        }
+    }
+    lessindent (writer);
+
+    CHECK_IO (writechar (writer, ']'));
+    return false;
+}
+
+
+bool
+hipack_write_dict (hipack_writer_t     *writer,
+                   const hipack_dict_t *dict)
+{
+    CHECK_IO (writechar (writer, '{'));
+
+    if (writer->indent != HIPACK_WRITER_COMPACT) {
+        CHECK_IO (writechar (writer, '\n'));
+    }
+
+    moreindent (writer);
+    CHECK_IO (write_keyval (writer, dict));
+    lessindent (writer);
+
+    CHECK_IO (writeindent (writer));
+    CHECK_IO (writechar (writer, '}'));
+    return false;
+}
+
+
+bool
+hipack_write_value (hipack_writer_t      *writer,
+                    const hipack_value_t *value)
+{
+    assert (writer);
+    assert (value);
+
+    switch (value->type) {
+        case HIPACK_INTEGER:
+            return hipack_write_integer (writer, value->v_integer);
+        case HIPACK_FLOAT:
+            return hipack_write_float (writer, value->v_float);
+        case HIPACK_BOOL:
+            return hipack_write_bool (writer, value->v_bool);
+        case HIPACK_STRING:
+            return hipack_write_string (writer, value->v_string);
+        case HIPACK_LIST:
+            return hipack_write_list (writer, value->v_list);
+        case HIPACK_DICT:
+            return hipack_write_dict (writer, value->v_dict);
+    }
+
+    assert (false); /* Never reached. */
+    return false;
+}
+
+
 bool
 hipack_write (hipack_writer_t     *writer,
               const hipack_dict_t *message)
 {
     assert (writer);
     assert (message);
+    writer->indent = 0;
+    return write_keyval (writer, message);
 }
 
 

+ 12 - 3
hipack.h

@@ -222,9 +222,15 @@ extern int hipack_stdio_getchar (void* fp);
 extern hipack_dict_t* hipack_read (hipack_reader_t *reader);
 
 
+enum {
+    HIPACK_WRITER_COMPACT = -1,
+    HIPACK_WRITER_INDENTED = 0,
+};
+
 typedef struct {
-    int (*putchar) (void*, int);
-    void *putchar_data;
+    int   (*putchar) (void*, int);
+    void   *putchar_data;
+    int32_t indent;
 } hipack_writer_t;
 
 
@@ -236,9 +242,12 @@ HIPACK_TYPES (HIPACK_DEFINE_WRITE_VALUE)
 
 #undef HIPACK_DEFINE_WRITE_VALUE
 
+extern bool hipack_write_value (hipack_writer_t      *writer,
+                                const hipack_value_t *value);
+
 extern bool hipack_write (hipack_writer_t     *writer,
                           const hipack_dict_t *message);
-extern int hipack_stdio_putchar (void* fp, int ch);
 
+extern int hipack_stdio_putchar (void* fp, int ch);
 
 #endif /* !HIPACK_H */