* 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>
* 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
* 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 {
}
yajl_free(handle);
-
- return version_number;
}