blob: b5e5464f106eb39ab306bb8909daac1eee66dadd [file] [log] [blame]
/*
* teamd_json.c - Teamd common json stuff
* Copyright (C) 2013-2015 Jiri Pirko <jiri@resnulli.us>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <string.h>
#include <stdarg.h>
#include <stdbool.h>
#include <ctype.h>
#include <errno.h>
#include <jansson.h>
#include "teamd_json.h"
static char *__strchrs(char *str, char *chars)
{
char *tmp;
while (*str != '\0') {
tmp = chars;
while (*tmp != '\0') {
if (*tmp == *str)
return str;
tmp++;
}
str++;
}
return NULL;
}
#define TEAMD_JSON_PATH_MAXLEN 128
typedef json_t *(*obj_constructor_t)(void);
static int __teamd_json_path_lite_va(json_t **p_json_obj, json_t *json_root,
obj_constructor_t obj_constructor,
const char *fmt, va_list ap)
{
json_t *json_obj = json_root;
json_t *prev_json_obj;
char *ptr;
char *end;
char path[TEAMD_JSON_PATH_MAXLEN];
size_t pathlen;
int ret;
if (*fmt == '@')
json_obj = va_arg(ap, void *);
else if (*fmt != '$')
return -EINVAL;
fmt++;
ret = vsnprintf(path, sizeof(path), fmt, ap);
if (ret < 0 || ret >= sizeof(path))
return -EINVAL;
pathlen = strlen(path);
ptr = path;
while (ptr - path < pathlen) {
if (*ptr == '.') {
char tmp = 0; /* gcc needs this initialized */
ptr++;
if (*ptr == '\"') {
ptr++;
end = strrchr(ptr, '\"');
if (end) {
*end = '\0';
end++;
}
} else {
end = __strchrs(ptr, ".[");
}
if (end) {
tmp = *end;
*end = '\0';
}
prev_json_obj = json_obj;
json_obj = json_object_get(prev_json_obj, ptr);
if (!json_obj && obj_constructor) {
/* In case new object is not supposed to be
* leaf, use json_object() as a constructor.
*/
json_obj = end ? json_object() : obj_constructor();
if (!json_obj)
return -ENOMEM;
ret = json_object_set_new(prev_json_obj, ptr,
json_obj);
if (ret)
return -EINVAL;
}
if (end)
*end = tmp;
else
end = ptr + strlen(ptr);
ptr = end;
} else if (*ptr == '[') {
int i;
ptr++;
end = strchr(ptr, ']');
if (!end)
return -EINVAL;
*end = '\0';
for (i = 0; i < strlen(ptr); i++)
if (!isdigit(ptr[i]))
return -EINVAL;
json_obj = json_array_get(json_obj, atoi(ptr));
ptr = end + 1;
} else {
return -EINVAL;
}
if (!json_obj)
return -ENOENT;
}
*p_json_obj = json_obj;
return 0;
}
int teamd_json_path_lite_va(json_t **p_json_obj, json_t *json_root,
const char *fmt, va_list ap)
{
return __teamd_json_path_lite_va(p_json_obj, json_root, NULL, fmt, ap);
}
int teamd_json_path_lite(json_t **p_json_obj, json_t *json_root,
const char *fmt, ...)
{
va_list ap;
int err;
va_start(ap, fmt);
err = teamd_json_path_lite_va(p_json_obj, json_root, fmt, ap);
va_end(ap);
return err;
}
int teamd_json_path_lite_build_va(json_t **p_json_obj, json_t *json_root,
const char *fmt, va_list ap)
{
return __teamd_json_path_lite_va(p_json_obj, json_root,
json_object, fmt, ap);
}
int teamd_json_path_lite_build(json_t **p_json_obj, json_t *json_root,
const char *fmt, ...)
{
va_list ap;
int err;
va_start(ap, fmt);
err = teamd_json_path_lite_build_va(p_json_obj, json_root, fmt, ap);
va_end(ap);
return err;
}
static json_t *string_constructor()
{
return json_string("");
}
static json_t *int_constructor()
{
return json_integer(0);
}
static json_t *true_constructor()
{
return json_true();
}
static json_t *false_constructor()
{
return json_false();
}
static json_t *array_constructor()
{
return json_array();
}
int teamd_json_path_lite_build_type_va(json_t **p_json_obj, json_t *json_root,
json_type obj_type,
const char *fmt, va_list ap)
{
obj_constructor_t obj_constructor;
int err;
switch (obj_type) {
case JSON_STRING:
obj_constructor = string_constructor;
break;
case JSON_INTEGER:
obj_constructor = int_constructor;
break;
case JSON_TRUE:
obj_constructor = true_constructor;
break;
case JSON_FALSE:
obj_constructor = false_constructor;
break;
case JSON_ARRAY:
obj_constructor = array_constructor;
break;
default:
return -EINVAL;
}
err = __teamd_json_path_lite_va(p_json_obj, json_root,
obj_constructor, fmt, ap);
if (err)
return err;
if (json_typeof(*p_json_obj) != obj_type)
return -EINVAL;
return 0;
}
int teamd_json_path_lite_build_type(json_t **p_json_obj, json_t *json_root,
json_type obj_type, const char *fmt, ...)
{
va_list ap;
int err;
va_start(ap, fmt);
err = teamd_json_path_lite_build_type_va(p_json_obj, json_root,
obj_type, fmt, ap);
va_end(ap);
return err;
}