]> git.sur5r.net Git - i3/i3/blobdiff - i3bar/src/parse_json_header.c
Merge branch 'master' into next
[i3/i3] / i3bar / src / parse_json_header.c
index abd43038350c6a63de06c21f7f735184de68e775..1cd951065c8e379f123d08671b12c769e8468e8f 100644 (file)
@@ -2,10 +2,10 @@
  * vim:ts=4:sw=4:expandtab
  *
  * i3bar - an xcb-based status- and ws-bar for i3
- * © 2010-2012 Axel Wagner and contributors (see also: LICENSE)
+ * © 2010 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,
+    KEY_STOP_SIGNAL,
+    KEY_CONT_SIGNAL,
+    KEY_CLICK_EVENTS,
+    NO_KEY
+} current_key;
+
+static int header_integer(void *ctx, long long val) {
+    i3bar_child *child = ctx;
+
+    switch (current_key) {
+        case KEY_VERSION:
+            child->version = val;
+            break;
+        case KEY_STOP_SIGNAL:
+            child->stop_signal = val;
+            break;
+        case KEY_CONT_SIGNAL:
+            child->cont_signal = val;
+            break;
+        default:
+            break;
+    }
+
+    return 1;
+}
+
+static int header_boolean(void *ctx, int val) {
+    i3bar_child *child = ctx;
+
+    switch (current_key) {
+        case KEY_CLICK_EVENTS:
+            child->click_events = val;
+            break;
+        default:
+            break;
+    }
 
-#if YAJL_MAJOR >= 2
-static int version_integer(void *ctx, long long val) {
-#else
-static int version_integer(void *ctx, long val) {
-#endif
-    if (version_key)
-        version_number = (uint32_t)val;
     return 1;
 }
 
-#if YAJL_MAJOR >= 2
-static int version_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) {
-#endif
-    version_key = (stringlen == strlen("version") &&
-                   strncmp((const char*)stringval, "version", strlen("version")) == 0);
+#define CHECK_KEY(name) (stringlen == strlen(name) && \
+                         STARTS_WITH((const char *)stringval, stringlen, name))
+
+static int header_map_key(void *ctx, const unsigned char *stringval, size_t stringlen) {
+    if (CHECK_KEY("version")) {
+        current_key = KEY_VERSION;
+    } else if (CHECK_KEY("stop_signal")) {
+        current_key = KEY_STOP_SIGNAL;
+    } else if (CHECK_KEY("cont_signal")) {
+        current_key = KEY_CONT_SIGNAL;
+    } else if (CHECK_KEY("click_events")) {
+        current_key = KEY_CLICK_EVENTS;
+    }
     return 1;
 }
 
-static yajl_callbacks version_callbacks = {
-    NULL, /* null */
-    NULL, /* boolean */
-    &version_integer,
-    NULL, /* double */
-    NULL, /* number */
-    NULL, /* string */
-    NULL, /* start_map */
-    &version_map_key,
-    NULL, /* end_map */
-    NULL, /* start_array */
-    NULL /* end_array */
-};
+static void child_init(i3bar_child *child) {
+    child->version = 0;
+    child->stop_signal = SIGSTOP;
+    child->cont_signal = SIGCONT;
+}
 
 /*
- * 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) {
-#if YAJL_MAJOR >= 2
-    yajl_handle handle = yajl_alloc(&version_callbacks, NULL, NULL);
+void parse_json_header(i3bar_child *child, const unsigned char *buffer, int length, unsigned int *consumed) {
+    static yajl_callbacks version_callbacks = {
+        .yajl_boolean = header_boolean,
+        .yajl_integer = header_integer,
+        .yajl_map_key = &header_map_key,
+    };
+
+    child_init(child);
+
+    current_key = NO_KEY;
+
+    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);
-#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 +126,4 @@ int32_t determine_json_version(const unsigned char *buffer, int length, unsigned
     }
 
     yajl_free(handle);
-
-    return version_number;
 }