/*
* json.c - basic JSON parsing and printing
* Copyright (C) 2014 Vivien Didelot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include "bar.h"
#include "block.h"
static inline bool
is_number(const char *str)
{
char *end;
strtoul(str, &end, 10);
/* not a valid number if end is not a null character */
return !(*str == 0 || *end != 0);
}
static inline void
escape(const char *str)
{
fprintf(stdout, "\"");
while (*str) {
switch (*str) {
case '"':
case '\\':
fprintf(stdout, "\\%c", *str);
break;
default:
fprintf(stdout, "%c", *str);
}
str++;
}
fprintf(stdout, "\"");
}
static void
print_prop(const char *key, const char *value, int flags)
{
/* Only print i3bar-specific properties */
if (!(flags & PROP_I3BAR))
return;
if (!*value)
return;
fprintf(stdout, ",\"%s\":", key);
/* Print as-is (except strings which must be escaped) */
if (flags & PROP_STRING && flags & PROP_NUMBER && is_number(value))
fprintf(stdout, "%s", value);
else if (flags & PROP_STRING)
escape(value);
else
fprintf(stdout, "%s", value);
}
static void
print_block(struct block *block)
{
#define PRINT(_name, _size, _flags) \
print_prop(#_name, block->updated_props._name, _flags); \
fprintf(stdout, ",{\"\":\"\"");
PROPERTIES(PRINT);
fprintf(stdout, "}");
#undef PRINT
}
/*
* Parse the input for the key and store the start of its value
* into and its size into .
*
* set to 0 means that the key was not present.
*/
void
json_parse(const char *json, const char *name, int *start, int *len)
{
const size_t keylen = strlen(name) + 2;
char key[keylen + 1];
snprintf(key, sizeof(key), "\"%s\"", name);
*start = *len = 0;
char *here = strstr(json, key);
if (here) {
here += keylen + 1;
/* skip pre-value whitespace */
while (isspace(*here))
here++;
if (*here == '"') {
/* string */
here++;
*start = here - json;
while (*here && *here != '"')
*len += 1, here++;
/* invalidate on incomplete string */
if (*here != '"')
*start = 0;
} else {
/* number */
*start = here - json;
while (isdigit(*here++))
*len += 1;
}
}
}
void
json_print_bar(struct bar *bar)
{
fprintf(stdout, ",[{\"full_text\":\"\"}");
for (int i = 0; i < bar->num; ++i) {
struct block *block = bar->blocks + i;
/* full_text is the only mandatory key, skip if empty */
if (!*FULL_TEXT(block)) {
bdebug(block, "no text to display, skipping");
continue;
}
print_block(block);
}
fprintf(stdout, "]\n");
fflush(stdout);
}