[PATCH v3 1/3] Add support for structured output formatters.

craven at gmx.net craven at gmx.net
Wed Jul 11 01:26:33 PDT 2012


This patch adds a new type structure_printer, which is used for
structured formatting, e.g. JSON or S-Expressions.

The structure contains the following function pointers:

- initial_state: is called to create a state object, that is passed to
  all invocations. This should be used to keep track of the output file
  and everything else necessary to correctly format output.
- map: is called when a new map (associative array, dictionary) is
  started. map_key and the primitives (string, number, bool) are used
  alternatingly to add key/value pairs. pop is used to close the map
  (see there). This function must return a nesting level identifier that
  can be used to close all nested structures (maps and lists), backing
  out to the returned nesting level.
- list: is called when a new list (array, vector) is started. the
  primitives (string, number, bool) are used consecutively to add values
  to the list. pop is used to close the list. This function must return
  a nesting level identifier that can be used to close all nested
  structures (maps and lists), backing out to the returned nesting
  level.
- map_key: is called to write the key of a key/value pair.
- pop: is called to return to a given nesting level. All lists and maps
  with a deeper nesting level must be closed.
- number, string, bool: output one element of the specific type.

All functions should use state to insert delimiters etc. automatically
when appropriate. State is a user-defined object/data that can contain
arbitrary information. Initial state is constructed by a call to
initial_state.

Example:
int top, one;
top = map(state);
map_key(state, "foo");
one = list(state);
number(state, 1);
number(state, 2);
number(state, 3);
pop(state, one);
map_key(state, "bar");
map(state);
map_key(state, "baaz");
string(state, "hello world");
pop(state, top);

would output JSON as follows:

{"foo": [1, 2, 3], "bar": { "baaz": "hello world"}}
---
 structured-output.h | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 90 insertions(+)
 create mode 100644 structured-output.h

diff --git a/structured-output.h b/structured-output.h
new file mode 100644
index 0000000..73029f1
--- /dev/null
+++ b/structured-output.h
@@ -0,0 +1,90 @@
+/* notmuch - Not much of an email program, (just index and search)
+ *
+ * Copyright © 2009 Carl Worth
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see http://www.gnu.org/licenses/ .
+ *
+ * Author: Carl Worth <cworth at cworth.org>
+ */
+
+#include "notmuch-client.h"
+
+/* structured formatting, useful for JSON, S-Expressions, ...
+ *
+ * All functions should use state to insert delimiters
+ * etc. automatically when appropriate. State is a user-defined
+ * object/data that can contain arbitrary information. Initial state is
+ * constructed by a call to initial_state.
+ *
+ * Example:
+ * int top, one;
+ * top = map(state);
+ * map_key(state, "foo");
+ * one = list(state);
+ * number(state, 1);
+ * number(state, 2);
+ * number(state, 3);
+ * pop(state, one);
+ * map_key(state, "bar");
+ * map(state);
+ * map_key(state, "baaz");
+ * string(state, "hello world");
+ * pop(state, top);
+ *
+ * would output JSON as follows:
+ *
+ * {"foo": [1, 2, 3], "bar": { "baaz": "hello world"}}
+ */
+typedef struct structure_printer {
+    /* map: is called when a new map (associative array, dictionary) is
+     * started. map_key and the primitives (string, number, bool) are
+     * used alternatingly to add key/value pairs. pop is used to close
+     * the map (see there). This function must return a nesting level
+     * identifier number that can be used to close all nested structures
+     * (maps and lists), backing out to the returned nesting level.
+     */
+    int (*map) (void *state);
+
+    /* list: is called when a new list (array, vector) is started. the
+     * primitives (string, number, bool) are used consecutively to add
+     * values to the list. pop is used to close the list. This function
+     * must return a nesting level identifier number that can be used to
+     * close all nested structures (maps and lists), backing out to the
+     * returned nesting level.
+     */
+    int (*list) (void *state);
+
+    /* pop: is called to return to a given nesting level. All lists and
+     * maps with a deeper nesting level must be closed.
+     */
+    void (*pop) (void *state, int level);
+
+    /* map_key: is called to write the key of a key/value pair.
+     */
+    void (*map_key) (void *state, const char *key);
+
+    /* number, string, bool: output one element of the specific type. */
+    void (*number) (void *state, int val);
+    void (*string) (void *state, const char *val);
+    void (*bool) (void *state, notmuch_bool_t val);
+
+    /* initial_state: is called to create a state object, that is passed
+     * to all invocations. This should be used to keep track of the
+     * output file and everything else necessary to correctly format
+     * output.
+     */
+    void *(*initial_state) (const struct structure_printer *sp,
+			    FILE *output);
+
+} structure_printer_t;
-- 
1.7.11.1



More information about the notmuch mailing list