Commit e09300bd authored by Christian Hergert's avatar Christian Hergert
Browse files

jsonrpc-glib: vendor our new jsonrpc-glib library

This will eventually become it's own library some day, but for now it can
just live inside of Builder. Once we can depend on it externally, we can
drop the vendoring of the library.
parent b399d840
......@@ -191,7 +191,6 @@ m4_define([libxml_required_version], [2.9.0])
m4_define([pangoft2_required_version], [1.38.0])
m4_define([peas_required_version], [1.18.0])
m4_define([json_glib_required_version], [1.2.0])
m4_define([jsonrpc_glib_required_version], [0.1.0])
PKG_CHECK_MODULES(EGG, [glib-2.0 >= glib_required_version
gmodule-2.0 >= glib_required_version
......@@ -203,12 +202,12 @@ PKG_CHECK_MODULES(GSTYLE, [glib-2.0 >= glib_required_version
gtk+-3.0 >= gtk_required_version
gtksourceview-3.0 >= gtksourceview_required_version])
PKG_CHECK_MODULES(ICONS, [gio-2.0 >= glib_required_version])
PKG_CHECK_MODULES(JSONRPC, [json-glib-1.0 >= json_glib_required_version])
PKG_CHECK_MODULES(LIBIDE, [gio-2.0 >= glib_required_version
gio-unix-2.0 >= glib_required_version
gtk+-3.0 >= gtk_required_version
gtksourceview-3.0 >= gtksourceview_required_version
json-glib-1.0 >= json_glib_required_version
jsonrpc-glib-0 >= jsonrpc_glib_required_version
libpeas-1.0 >= peas_required_version
libxml-2.0 >= libxml_required_version
pangoft2 >= pangoft2_required_version])
......@@ -512,6 +511,8 @@ AC_CONFIG_FILES([
contrib/gd/Makefile
contrib/gstyle/Makefile
contrib/gstyle/tests/Makefile
contrib/jsonrpc-glib/Makefile
contrib/jsonrpc-glib/jsonrpc-version.h
contrib/libeditorconfig/Makefile
contrib/nautilus/Makefile
contrib/pnl/Makefile
......
......@@ -2,6 +2,7 @@ SUBDIRS = \
egg \
gd \
libeditorconfig \
jsonrpc-glib \
nautilus \
pnl \
rg \
......
noinst_LTLIBRARIES = libjsonrpc-glib.la
libjsonrpc_glib_la_SOURCES = \
jcon.c \
jcon.h \
jsonrpc-client.c \
jsonrpc-client.h \
jsonrpc-glib.h \
jsonrpc-input-stream.c \
jsonrpc-input-stream.h \
jsonrpc-output-stream.c \
jsonrpc-output-stream.h \
jsonrpc-version.h \
$(NULL)
libjsonrpc_glib_la_CFLAGS = \
-DJSONRPC_GLIB_INSIDE \
$(DEBUG_CFLAGS) \
$(JSONRPC_CFLAGS) \
$(OPTIMIZE_CFLAGS) \
$(NULL)
libjsonrpc_glib_la_LIBADD = $(JSONRPC_LIBS)
libjsonrpc_glib_la_LDFLAGS = $(OPTIMIZE_LDFLAGS)
-include $(top_srcdir)/git.mk
/* jcon.c
*
* Copyright (C) 2016 Christian Hergert <chergert@redhat.com>
*
* This file 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 file 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 General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* Copyright 2009-2013 MongoDB, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define G_LOG_DOMAIN "jcon"
#include <stdarg.h>
#include <string.h>
#include "jcon.h"
#define STACK_DEPTH 50
typedef union
{
const gchar *v_string;
gdouble v_double;
JsonObject *v_object;
JsonArray *v_array;
JsonNode *v_node;
gboolean v_boolean;
gint v_int;
} JconAppend;
typedef union
{
const gchar *v_key;
const gchar **v_string;
gdouble *v_double;
JsonObject **v_object;
JsonArray **v_array;
JsonNode **v_node;
gboolean *v_boolean;
gint *v_int;
} JconExtract;
const char *
jcon_magic (void)
{
return "THIS_IS_JCON_MAGIC";
}
const char *
jcone_magic (void)
{
return "THIS_IS_JCONE_MAGIC";
}
static JsonNode *
jcon_append_to_node (JconType type,
JconAppend *val)
{
JsonNode *node;
switch (type)
{
case JCON_TYPE_STRING:
node = json_node_new (JSON_NODE_VALUE);
json_node_set_string (node, val->v_string);
return node;
case JCON_TYPE_DOUBLE:
node = json_node_new (JSON_NODE_VALUE);
json_node_set_double (node, val->v_double);
return node;
case JCON_TYPE_BOOLEAN:
node = json_node_new (JSON_NODE_VALUE);
json_node_set_boolean (node, val->v_boolean);
return node;
case JCON_TYPE_NULL:
return json_node_new (JSON_NODE_NULL);
case JCON_TYPE_INT:
node = json_node_new (JSON_NODE_VALUE);
json_node_set_int (node, val->v_int);
return node;
case JCON_TYPE_NODE:
return json_node_copy (val->v_node);
case JCON_TYPE_ARRAY:
node = json_node_new (JSON_NODE_ARRAY);
json_node_set_array (node, val->v_array);
return node;
case JCON_TYPE_OBJECT:
node = json_node_new (JSON_NODE_OBJECT);
json_node_set_object (node, val->v_object);
return node;
case JCON_TYPE_OBJECT_START:
case JCON_TYPE_OBJECT_END:
case JCON_TYPE_ARRAY_START:
case JCON_TYPE_ARRAY_END:
case JCON_TYPE_END:
case JCON_TYPE_RAW:
default:
return NULL;
}
}
static JconType
jcon_append_tokenize (va_list *ap,
JconAppend *u)
{
const gchar *mark;
JconType type;
g_assert (ap != NULL);
g_assert (u != NULL);
/* Consumes ap, storing output values into u and returning the type of the
* captured token.
*
* The basic workflow goes like this:
*
* 1. Look at the current arg. It will be a gchar *
* a. If it's a NULL, we're done processing.
* b. If it's JCON_MAGIC (a symbol with storage in this module)
* I. The next token is the type
* II. The type specifies how many args to eat and their types
* c. Otherwise it's either recursion related or a raw string
* I. If the first byte is '{', '}', '[', or ']' pass back an
* appropriate recursion token
* II. If not, just call it a v_string token and pass that back
*/
memset (u, 0, sizeof *u);
mark = va_arg (*ap, const gchar *);
g_assert (mark != JCONE_MAGIC);
if (mark == NULL)
{
type = JCON_TYPE_END;
}
else if (mark == JCON_MAGIC)
{
type = va_arg (*ap, JconType);
switch (type)
{
case JCON_TYPE_STRING:
u->v_string = va_arg (*ap, const gchar *);
break;
case JCON_TYPE_DOUBLE:
u->v_double = va_arg (*ap, double);
break;
case JCON_TYPE_NODE:
u->v_node = va_arg (*ap, JsonNode *);
break;
case JCON_TYPE_OBJECT:
u->v_object = va_arg (*ap, JsonObject *);
break;
case JCON_TYPE_ARRAY:
u->v_array = va_arg (*ap, JsonArray *);
break;
case JCON_TYPE_BOOLEAN:
u->v_boolean = va_arg (*ap, gboolean);
break;
case JCON_TYPE_NULL:
break;
case JCON_TYPE_INT:
u->v_int = va_arg (*ap, gint);
break;
case JCON_TYPE_ARRAY_START:
case JCON_TYPE_ARRAY_END:
case JCON_TYPE_OBJECT_START:
case JCON_TYPE_OBJECT_END:
case JCON_TYPE_END:
case JCON_TYPE_RAW:
default:
g_assert_not_reached ();
break;
}
}
else
{
switch (mark[0])
{
case '{':
type = JCON_TYPE_OBJECT_START;
break;
case '}':
type = JCON_TYPE_OBJECT_END;
break;
case '[':
type = JCON_TYPE_ARRAY_START;
break;
case ']':
type = JCON_TYPE_ARRAY_END;
break;
default:
type = JCON_TYPE_STRING;
u->v_string = mark;
break;
}
}
return type;
}
static void
jcon_append_va_list (JsonNode *node,
va_list *args)
{
g_assert (JSON_NODE_HOLDS_OBJECT (node));
g_assert (args != NULL);
for (;;)
{
const gchar *key = NULL;
JconAppend val = { 0 };
JconType type;
g_assert (node != NULL);
if (!JSON_NODE_HOLDS_ARRAY (node))
{
type = jcon_append_tokenize (args, &val);
if (type == JCON_TYPE_END)
return;
if (type == JCON_TYPE_OBJECT_END)
{
node = json_node_get_parent (node);
continue;
}
if (type != JCON_TYPE_STRING)
g_error ("string keys are required for objects");
key = val.v_string;
}
type = jcon_append_tokenize (args, &val);
if (type == JCON_TYPE_END)
g_error ("implausable time to reach end token");
if (type == JCON_TYPE_OBJECT_START)
{
JsonNode *child_node = json_node_new (JSON_NODE_OBJECT);
JsonObject *child_object = json_object_new ();
json_node_take_object (child_node, child_object);
if (JSON_NODE_HOLDS_ARRAY (node))
json_array_add_element (json_node_get_array (node), child_node);
else
json_object_set_member (json_node_get_object (node), key, child_node);
json_node_set_parent (child_node, node);
node = child_node;
continue;
}
else if (type == JCON_TYPE_ARRAY_START)
{
JsonNode *child_node = json_node_new (JSON_NODE_ARRAY);
JsonArray *child_array = json_array_new ();
json_node_take_array (child_node, child_array);
if (JSON_NODE_HOLDS_ARRAY (node))
json_array_add_element (json_node_get_array (node), child_node);
else
json_object_set_member (json_node_get_object (node), key, child_node);
json_node_set_parent (child_node, node);
node = child_node;
continue;
}
else if (type == JCON_TYPE_OBJECT_END || type == JCON_TYPE_ARRAY_END)
{
node = json_node_get_parent (node);
continue;
}
if (JSON_NODE_HOLDS_ARRAY (node))
json_array_add_element (json_node_get_array (node), jcon_append_to_node (type, &val));
else
json_object_set_member (json_node_get_object (node), key, jcon_append_to_node (type, &val));
}
}
JsonNode *
jcon_new (gpointer unused,
...)
{
g_autoptr(JsonNode) node = NULL;
va_list args;
g_return_val_if_fail (unused == NULL, NULL);
node = json_node_new (JSON_NODE_OBJECT);
json_node_take_object (node, json_object_new ());
va_start (args, unused);
jcon_append_va_list (node, &args);
va_end (args);
return g_steal_pointer (&node);
}
static gboolean
jcon_extract_tokenize (va_list *args,
JconExtract *val,
JconType *type)
{
const char *mark;
g_assert (args != NULL);
g_assert (val != NULL);
g_assert (type != NULL);
memset (val, 0, sizeof *val);
*type = -1;
mark = va_arg (*args, const char *);
if (mark == NULL)
{
*type = JCON_TYPE_END;
return TRUE;
}
if (mark == JCONE_MAGIC)
{
*type = va_arg (*args, JconType);
switch (*type)
{
case JCON_TYPE_STRING:
val->v_string = va_arg (*args, const gchar **);
return TRUE;
case JCON_TYPE_DOUBLE:
val->v_double = va_arg (*args, gdouble *);
return TRUE;
case JCON_TYPE_NODE:
val->v_node = va_arg (*args, JsonNode **);
return TRUE;
case JCON_TYPE_OBJECT:
val->v_object = va_arg (*args, JsonObject **);
return TRUE;
case JCON_TYPE_ARRAY:
val->v_array = va_arg (*args, JsonArray **);
return TRUE;
case JCON_TYPE_BOOLEAN:
val->v_boolean = va_arg (*args, gboolean *);
return TRUE;
case JCON_TYPE_NULL:
return TRUE;
case JCON_TYPE_INT:
val->v_int = va_arg (*args, gint *);
return TRUE;
case JCON_TYPE_ARRAY_START:
case JCON_TYPE_ARRAY_END:
case JCON_TYPE_OBJECT_START:
case JCON_TYPE_OBJECT_END:
case JCON_TYPE_END:
case JCON_TYPE_RAW:
default:
return FALSE;
}
}
switch (mark[0])
{
case '{':
*type = JCON_TYPE_OBJECT_START;
return TRUE;
case '}':
*type = JCON_TYPE_OBJECT_END;
return TRUE;
case '[':
*type = JCON_TYPE_ARRAY_START;
return TRUE;
case ']':
*type = JCON_TYPE_ARRAY_END;
return TRUE;
default:
break;
}
*type = JCON_TYPE_RAW;
val->v_key = mark;
return TRUE;
}
static void
jcon_extract_from_node (JsonNode *node,
JconType type,
JconExtract *val)
{
g_assert (node != NULL);
g_assert (val != NULL);
switch (type)
{
case JCON_TYPE_STRING:
if (JSON_NODE_HOLDS_VALUE (node))
*val->v_string = json_node_get_string (node);
else
*val->v_string = NULL;
break;
case JCON_TYPE_DOUBLE:
if (JSON_NODE_HOLDS_VALUE (node))
*val->v_double = json_node_get_double (node);
else
*val->v_double = 0.0;
break;
case JCON_TYPE_NODE:
*val->v_node = node;
break;
case JCON_TYPE_OBJECT:
if (JSON_NODE_HOLDS_OBJECT (node))
*val->v_object = json_node_get_object (node);
else
*val->v_object = NULL;
break;
case JCON_TYPE_ARRAY:
if (JSON_NODE_HOLDS_ARRAY (node))
*val->v_array = json_node_get_array (node);
else
*val->v_array = NULL;
break;
case JCON_TYPE_BOOLEAN:
if (JSON_NODE_HOLDS_VALUE (node))
*val->v_boolean = json_node_get_boolean (node);
else
*val->v_boolean = FALSE;
break;
case JCON_TYPE_NULL:
break;
case JCON_TYPE_INT:
if (JSON_NODE_HOLDS_VALUE (node))
*val->v_int = json_node_get_int (node);
else
*val->v_int = 0;
break;
case JCON_TYPE_ARRAY_START:
case JCON_TYPE_ARRAY_END:
case JCON_TYPE_OBJECT_START:
case JCON_TYPE_OBJECT_END:
case JCON_TYPE_END:
case JCON_TYPE_RAW:
default:
g_assert_not_reached ();
break;
}
}
static JsonNode *
get_stack_node (JsonNode *node,
const gchar *key,
guint idx)
{
g_assert (node != NULL);
if (JSON_NODE_HOLDS_ARRAY (node))
{
JsonArray *array = json_node_get_array (node);
if (array == NULL)
return NULL;
if (idx >= json_array_get_length (array))
return NULL;
return json_array_get_element (array, idx);
}
if (JSON_NODE_HOLDS_OBJECT (node))
{
JsonObject *object = json_node_get_object (node);
if (object == NULL)
return NULL;
if (!json_object_has_member (object, key))
return NULL;
return json_object_get_member (object, key);
}
return NULL;
}
static gboolean
jcon_extract_va_list (JsonNode *node,
va_list *args)
{
const gchar *keys[STACK_DEPTH];
guint indexes[STACK_DEPTH];
gint sp = 0;
g_assert (node != NULL);
g_assert (args != NULL);
#define POP_STACK() sp--
#define PUSH_STACK() \