From 1e114d7ab5296a6d9edb58653039bd65098b412c Mon Sep 17 00:00:00 2001 From: Quentin Glidic Date: Mon, 3 Sep 2012 10:43:29 +0200 Subject: [PATCH] i3bar: Fully parse the JSON header --- i3bar/include/parse_json_header.h | 10 ++-- i3bar/include/util.h | 2 + i3bar/src/child.c | 2 +- i3bar/src/parse_json_header.c | 77 ++++++++++++++++++------------- 4 files changed, 54 insertions(+), 37 deletions(-) diff --git a/i3bar/include/parse_json_header.h b/i3bar/include/parse_json_header.h index 52c6f5d2..6495eeb1 100644 --- a/i3bar/include/parse_json_header.h +++ b/i3bar/include/parse_json_header.h @@ -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 @@ -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 diff --git a/i3bar/include/util.h b/i3bar/include/util.h index 43c56c58..6ae97815 100644 --- a/i3bar/include/util.h +++ b/i3bar/include/util.h @@ -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) { \ diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 22a028a6..f3832d9c 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -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 { diff --git a/i3bar/src/parse_json_header.c b/i3bar/src/parse_json_header.c index abd43038..a3fefb8a 100644 --- a/i3bar/src/parse_json_header.c +++ b/i3bar/src/parse_json_header.c @@ -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 @@ -25,72 +25,89 @@ #include #include -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; } -- 2.39.5