2 * vim:ts=4:sw=4:expandtab
4 * i3bar - an xcb-based status- and ws-bar for i3
5 * © 2010-2012 Axel Wagner and contributors (see also: LICENSE)
7 * parse_json_header.c: Parse the JSON protocol header to determine
8 * protocol version and features.
13 #include <sys/types.h>
24 #include <yajl/yajl_common.h>
25 #include <yajl/yajl_parse.h>
26 #include <yajl/yajl_version.h>
39 static int header_integer(void *ctx, long long val) {
41 static int header_integer(void *ctx, long val) {
43 i3bar_child *child = ctx;
45 switch (current_key) {
50 child->stop_signal = val;
53 child->cont_signal = val;
62 static int header_boolean(void *ctx, int val) {
63 i3bar_child *child = ctx;
65 switch (current_key) {
66 case KEY_CLICK_EVENTS:
67 child->click_events = val;
76 #define CHECK_KEY(name) (stringlen == strlen(name) && \
77 STARTS_WITH((const char*)stringval, stringlen, name))
80 static int header_map_key(void *ctx, const unsigned char *stringval, size_t stringlen) {
82 static int header_map_key(void *ctx, const unsigned char *stringval, unsigned int stringlen) {
84 if (CHECK_KEY("version")) {
85 current_key = KEY_VERSION;
86 } else if (CHECK_KEY("stop_signal")) {
87 current_key = KEY_STOP_SIGNAL;
88 } else if (CHECK_KEY("cont_signal")) {
89 current_key = KEY_CONT_SIGNAL;
90 } else if (CHECK_KEY("click_events")) {
91 current_key = KEY_CLICK_EVENTS;
96 static yajl_callbacks version_callbacks = {
98 &header_boolean, /* boolean */
103 NULL, /* start_map */
106 NULL, /* start_array */
110 static void child_init(i3bar_child *child) {
112 child->stop_signal = SIGSTOP;
113 child->cont_signal = SIGCONT;
117 * Parse the JSON protocol header to determine protocol version and features.
118 * In case the buffer does not contain a valid header (invalid JSON, or no
119 * version field found), the 'correct' field of the returned header is set to
120 * false. The amount of bytes consumed by parsing the header is returned in
121 * *consumed (if non-NULL).
124 void parse_json_header(i3bar_child *child, const unsigned char *buffer, int length, unsigned int *consumed) {
127 current_key = NO_KEY;
130 yajl_handle handle = yajl_alloc(&version_callbacks, NULL, child);
131 /* Allow trailing garbage. yajl 1 always behaves that way anyways, but for
132 * yajl 2, we need to be explicit. */
133 yajl_config(handle, yajl_allow_trailing_garbage, 1);
135 yajl_parser_config parse_conf = { 0, 0 };
137 yajl_handle handle = yajl_alloc(&version_callbacks, &parse_conf, NULL, child);
140 yajl_status state = yajl_parse(handle, buffer, length);
141 if (state != yajl_status_ok) {
143 if (consumed != NULL)
146 if (consumed != NULL)
147 *consumed = yajl_get_bytes_consumed(handle);