gri3-wm/i3bar/src/determine_json_version.c

105 lines
2.9 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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. Its 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;
}