+static int stdin_start_array(void *context) {
+ struct status_block *first;
+ while (!TAILQ_EMPTY(&statusline_head)) {
+ first = TAILQ_FIRST(&statusline_head);
+ I3STRING_FREE(first->full_text);
+ FREE(first->color);
+ FREE(first->name);
+ FREE(first->instance);
+ TAILQ_REMOVE(&statusline_head, first, blocks);
+ free(first);
+ }
+ return 1;
+}
+
+/*
+ * The start of a map is the start of a single block of the status line.
+ *
+ */
+static int stdin_start_map(void *context) {
+ parser_ctx *ctx = context;
+ memset(&(ctx->block), '\0', sizeof(struct status_block));
+
+ /* Default width of the separator block. */
+ ctx->block.sep_block_width = 9;
+
+ return 1;
+}
+
+#if YAJL_MAJOR >= 2
+static int stdin_map_key(void *context, const unsigned char *key, size_t len) {
+#else
+static int stdin_map_key(void *context, const unsigned char *key, unsigned int len) {
+#endif
+ parser_ctx *ctx = context;
+ FREE(ctx->last_map_key);
+ sasprintf(&(ctx->last_map_key), "%.*s", len, key);
+ return 1;
+}
+
+static int stdin_boolean(void *context, int val) {
+ parser_ctx *ctx = context;
+ if (strcasecmp(ctx->last_map_key, "urgent") == 0) {
+ ctx->block.urgent = val;
+ }
+ if (strcasecmp(ctx->last_map_key, "separator") == 0) {
+ ctx->block.no_separator = !val;
+ }
+ return 1;
+}
+
+#if YAJL_MAJOR >= 2
+static int stdin_string(void *context, const unsigned char *val, size_t len) {
+#else
+static int stdin_string(void *context, const unsigned char *val, unsigned int len) {
+#endif
+ parser_ctx *ctx = context;
+ if (strcasecmp(ctx->last_map_key, "full_text") == 0) {
+ ctx->block.full_text = i3string_from_utf8_with_length((const char *)val, len);
+ }
+ if (strcasecmp(ctx->last_map_key, "color") == 0) {
+ sasprintf(&(ctx->block.color), "%.*s", len, val);
+ }
+ if (strcasecmp(ctx->last_map_key, "align") == 0) {
+ if (len == strlen("left") && !strncmp((const char*)val, "left", strlen("left"))) {
+ ctx->block.align = ALIGN_LEFT;
+ } else if (len == strlen("right") && !strncmp((const char*)val, "right", strlen("right"))) {
+ ctx->block.align = ALIGN_RIGHT;
+ } else {
+ ctx->block.align = ALIGN_CENTER;
+ }
+ } else if (strcasecmp(ctx->last_map_key, "min_width") == 0) {
+ i3String *text = i3string_from_utf8_with_length((const char *)val, len);
+ ctx->block.min_width = (uint32_t)predict_text_width(text);
+ i3string_free(text);
+ }
+ if (strcasecmp(ctx->last_map_key, "name") == 0) {
+ char *copy = (char*)malloc(len+1);
+ strncpy(copy, (const char *)val, len);
+ copy[len] = 0;
+ ctx->block.name = copy;
+ }
+ if (strcasecmp(ctx->last_map_key, "instance") == 0) {
+ char *copy = (char*)malloc(len+1);
+ strncpy(copy, (const char *)val, len);
+ copy[len] = 0;
+ ctx->block.instance = copy;
+ }
+ return 1;
+}
+
+#if YAJL_MAJOR >= 2
+static int stdin_integer(void *context, long long val) {
+#else
+static int stdin_integer(void *context, long val) {
+#endif
+ parser_ctx *ctx = context;
+ if (strcasecmp(ctx->last_map_key, "min_width") == 0) {
+ ctx->block.min_width = (uint32_t)val;
+ }
+ if (strcasecmp(ctx->last_map_key, "separator_block_width") == 0) {
+ ctx->block.sep_block_width = (uint32_t)val;
+ }
+ return 1;
+}
+
+static int stdin_end_map(void *context) {
+ parser_ctx *ctx = context;
+ struct status_block *new_block = smalloc(sizeof(struct status_block));
+ memcpy(new_block, &(ctx->block), sizeof(struct status_block));
+ /* Ensure we have a full_text set, so that when it is missing (or null),
+ * i3bar doesn’t crash and the user gets an annoying message. */
+ if (!new_block->full_text)
+ new_block->full_text = i3string_from_utf8("SPEC VIOLATION (null)");
+ if (new_block->urgent)
+ ctx->has_urgent = true;
+ TAILQ_INSERT_TAIL(&statusline_head, new_block, blocks);
+ return 1;
+}
+
+static int stdin_end_array(void *context) {
+ DLOG("dumping statusline:\n");
+ struct status_block *current;
+ TAILQ_FOREACH(current, &statusline_head, blocks) {
+ DLOG("full_text = %s\n", i3string_as_utf8(current->full_text));
+ DLOG("color = %s\n", current->color);
+ }
+ DLOG("end of dump\n");
+ return 1;
+}
+
+/*
+ * Helper function to read stdin
+ *
+ */
+static unsigned char *get_buffer(ev_io *watcher, int *ret_buffer_len) {