i3bar: be less strict about the {"version":1} JSON header
This commit is contained in:
parent
dbe406641f
commit
e53405c216
|
@ -56,5 +56,6 @@ TAILQ_HEAD(statusline_head, status_block) statusline_head;
|
||||||
#include "xcb.h"
|
#include "xcb.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "libi3.h"
|
#include "libi3.h"
|
||||||
|
#include "determine_json_version.h"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
*
|
||||||
|
* determine_json_version.c: Determines the JSON protocol version based on the
|
||||||
|
* first line of input from a child program.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef DETERMINE_JSON_VERSION_H_
|
||||||
|
#define DETERMINE_JSON_VERSION_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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…
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int32_t determine_json_version(const unsigned char *buffer, int length, unsigned int *consumed);
|
||||||
|
|
||||||
|
#endif
|
|
@ -192,19 +192,18 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) {
|
||||||
if (first_line) {
|
if (first_line) {
|
||||||
DLOG("Detecting input type based on buffer *%.*s*\n", rec, buffer);
|
DLOG("Detecting input type based on buffer *%.*s*\n", rec, buffer);
|
||||||
/* Detect whether this is JSON or plain text. */
|
/* Detect whether this is JSON or plain text. */
|
||||||
plaintext = (strncasecmp((char*)buffer, "{\"version\":", strlen("{\"version\":")) != 0);
|
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. */
|
||||||
|
plaintext = (determine_json_version(buffer, buffer_len, &consumed) == -1);
|
||||||
if (plaintext) {
|
if (plaintext) {
|
||||||
/* In case of plaintext, we just add a single block and change its
|
/* In case of plaintext, we just add a single block and change its
|
||||||
* full_text pointer later. */
|
* full_text pointer later. */
|
||||||
struct status_block *new_block = scalloc(sizeof(struct status_block));
|
struct status_block *new_block = scalloc(sizeof(struct status_block));
|
||||||
TAILQ_INSERT_TAIL(&statusline_head, new_block, blocks);
|
TAILQ_INSERT_TAIL(&statusline_head, new_block, blocks);
|
||||||
} else {
|
} else {
|
||||||
/* At the moment, we don’t care for the version. This might change
|
json_input += consumed;
|
||||||
* in the future, but for now, we just discard it. */
|
rec -= consumed;
|
||||||
while (*json_input != '\n' && *json_input != '\0') {
|
|
||||||
json_input++;
|
|
||||||
rec--;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
first_line = false;
|
first_line = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
*
|
||||||
|
* determine_json_version.c: Determines the JSON protocol version based on the
|
||||||
|
* first line of input from a child program.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <ev.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <yajl/yajl_common.h>
|
||||||
|
#include <yajl/yajl_parse.h>
|
||||||
|
#include <yajl/yajl_version.h>
|
||||||
|
|
||||||
|
static bool version_key;
|
||||||
|
static int32_t version_number;
|
||||||
|
|
||||||
|
#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);
|
||||||
|
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 */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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…
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
/* 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;
|
||||||
|
if (consumed != NULL)
|
||||||
|
*consumed = 0;
|
||||||
|
} else {
|
||||||
|
if (consumed != NULL)
|
||||||
|
*consumed = yajl_get_bytes_consumed(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
yajl_free(handle);
|
||||||
|
|
||||||
|
return version_number;
|
||||||
|
}
|
Loading…
Reference in New Issue