]> git.sur5r.net Git - i3/i3/commitdiff
i3bar: Fully parse the JSON header
authorQuentin Glidic <sardemff7+git@sardemff7.net>
Mon, 3 Sep 2012 08:43:29 +0000 (10:43 +0200)
committerMichael Stapelberg <michael@stapelberg.de>
Sat, 22 Sep 2012 13:13:21 +0000 (15:13 +0200)
i3bar/include/parse_json_header.h
i3bar/include/util.h
i3bar/src/child.c
i3bar/src/parse_json_header.c

index 52c6f5d257c7afd88c3dce5fa0189944af7b6a75..6495eeb13a299ea23d5cd7e1972d1743d6afe483 100644 (file)
@@ -4,12 +4,12 @@
  * i3bar - an xcb-based status- and ws-bar for i3
  * © 2010-2012 Axel Wagner and contributors (see also: LICENSE)
  *
- * determine_json_version.c: Determines the JSON protocol version based on the
- *                           first line of input from a child program.
+ * parse_json_header.c: Parse the JSON protocol header to determine
+ *                      protocol version and features.
  *
  */
-#ifndef DETERMINE_JSON_VERSION_H_
-#define DETERMINE_JSON_VERSION_H_
+#ifndef PARSE_JSON_HEADER_H_
+#define PARSE_JSON_HEADER_H_
 
 #include <stdint.h>
 
@@ -24,6 +24,6 @@
  * even an int8_t, but still…
  *
  */
-int32_t determine_json_version(const unsigned char *buffer, int length, unsigned int *consumed);
+void parse_json_header(i3bar_child *child, const unsigned char *buffer, int length, unsigned int *consumed);
 
 #endif
index 43c56c58d3e93794d6f56becc86ae128a73d84bb..6ae97815384049ec87d95ec94fd6788c19b648d4 100644 (file)
@@ -16,6 +16,8 @@
 #undef MIN
 #define MIN(x,y) ((x) < (y) ? (x) : (y))
 
+#define STARTS_WITH(string, len, needle) ((len >= strlen(needle)) && strncasecmp(string, needle, strlen(needle)) == 0)
+
 /* Securely free p */
 #define FREE(p) do { \
     if (p != NULL) { \
index 22a028a6775d3ab6dce9372b83885b9cea3856bb..f3832d9c47a9ca8330f7e142d075e7ba8d91d60e 100644 (file)
@@ -249,7 +249,7 @@ void stdin_io_first_line_cb(struct ev_loop *loop, ev_io *watcher, int revents) {
     unsigned int consumed = 0;
     /* At the moment, we don’t care for the version. This might change
      * in the future, but for now, we just discard it. */
-    child.version = determine_json_version(buffer, rec, &consumed);
+    parse_json_header(&child, buffer, rec, &consumed);
     if (child.version > 0) {
         read_json_input(buffer + consumed, rec - consumed);
     } else {
index abd43038350c6a63de06c21f7f735184de68e775..a3fefb8aee96e086e11e223b1fb63c307450b3be 100644 (file)
@@ -4,8 +4,8 @@
  * i3bar - an xcb-based status- and ws-bar for i3
  * © 2010-2012 Axel Wagner and contributors (see also: LICENSE)
  *
- * determine_json_version.c: Determines the JSON protocol version based on the
- *                           first line of input from a child program.
+ * parse_json_header.c: Parse the JSON protocol header to determine
+ *                      protocol version and features.
  *
  */
 #include <stdlib.h>
 #include <yajl/yajl_parse.h>
 #include <yajl/yajl_version.h>
 
-static bool version_key;
-static int32_t version_number;
+#include "common.h"
+
+static enum {
+    KEY_VERSION,
+    NO_KEY
+} current_key;
 
 #if YAJL_MAJOR >= 2
-static int version_integer(void *ctx, long long val) {
+static int header_integer(void *ctx, long long val) {
 #else
-static int version_integer(void *ctx, long val) {
+static int header_integer(void *ctx, long val) {
 #endif
-    if (version_key)
-        version_number = (uint32_t)val;
+    i3bar_child *child = ctx;
+
+    switch (current_key) {
+        case KEY_VERSION:
+            child->version = val;
+            break;
+        default:
+            break;
+    }
     return 1;
 }
 
+#define CHECK_KEY(name) (stringlen == strlen(name) && \
+                         STARTS_WITH((const char*)stringval, stringlen, name))
+
 #if YAJL_MAJOR >= 2
-static int version_map_key(void *ctx, const unsigned char *stringval, size_t stringlen) {
+static int header_map_key(void *ctx, const unsigned char *stringval, size_t stringlen) {
 #else
-static int version_map_key(void *ctx, const unsigned char *stringval, unsigned int stringlen) {
+static int header_map_key(void *ctx, const unsigned char *stringval, unsigned int stringlen) {
 #endif
-    version_key = (stringlen == strlen("version") &&
-                   strncmp((const char*)stringval, "version", strlen("version")) == 0);
+    if (CHECK_KEY("version")) {
+        current_key = KEY_VERSION;
+    }
     return 1;
 }
 
 static yajl_callbacks version_callbacks = {
     NULL, /* null */
     NULL, /* boolean */
-    &version_integer,
+    &header_integer,
     NULL, /* double */
     NULL, /* number */
     NULL, /* string */
     NULL, /* start_map */
-    &version_map_key,
+    &header_map_key,
     NULL, /* end_map */
     NULL, /* start_array */
     NULL /* end_array */
 };
 
+static void child_init(i3bar_child *child) {
+    child->version = 0;
+}
+
 /*
- * Determines the JSON i3bar protocol version from the given buffer. In case
- * the buffer does not contain valid JSON, or no version field is found, this
- * function returns -1. The amount of bytes consumed by parsing the header is
- * returned in *consumed (if non-NULL).
- *
- * The return type is an int32_t to avoid machines with different sizes of
- * 'int' to allow different values here. It’s highly unlikely we ever exceed
- * even an int8_t, but still…
+ * Parse the JSON protocol header to determine protocol version and features.
+ * In case the buffer does not contain a valid header (invalid JSON, or no
+ * version field found), the 'correct' field of the returned header is set to
+ * false. The amount of bytes consumed by parsing the header is returned in
+ * *consumed (if non-NULL).
  *
  */
-int32_t determine_json_version(const unsigned char *buffer, int length, unsigned int *consumed) {
+void parse_json_header(i3bar_child *child, const unsigned char *buffer, int length, unsigned int *consumed) {
+    child_init(child);
+
+    current_key = NO_KEY;
+
 #if YAJL_MAJOR >= 2
-    yajl_handle handle = yajl_alloc(&version_callbacks, NULL, NULL);
+    yajl_handle handle = yajl_alloc(&version_callbacks, NULL, child);
     /* Allow trailing garbage. yajl 1 always behaves that way anyways, but for
      * yajl 2, we need to be explicit. */
     yajl_config(handle, yajl_allow_trailing_garbage, 1);
 #else
     yajl_parser_config parse_conf = { 0, 0 };
 
-    yajl_handle handle = yajl_alloc(&version_callbacks, &parse_conf, NULL, NULL);
+    yajl_handle handle = yajl_alloc(&version_callbacks, &parse_conf, NULL, child);
 #endif
 
-    version_key = false;
-    version_number = -1;
-
     yajl_status state = yajl_parse(handle, buffer, length);
     if (state != yajl_status_ok) {
-        version_number = -1;
+        child_init(child);
         if (consumed != NULL)
             *consumed = 0;
     } else {
@@ -99,6 +116,4 @@ int32_t determine_json_version(const unsigned char *buffer, int length, unsigned
     }
 
     yajl_free(handle);
-
-    return version_number;
 }