#include <ucl.h>
#include <Python.h>
static
PyObject *SchemaError;
static
PyObject *
_basic_ucl_type (ucl_object_t
const
*obj)
{
switch
(obj->type) {
case
UCL_INT:
return
Py_BuildValue (
"L"
, (
long
long
)ucl_object_toint (obj));
case
UCL_FLOAT:
return
Py_BuildValue (
"d"
, ucl_object_todouble (obj));
case
UCL_STRING:
return
Py_BuildValue (
"s"
, ucl_object_tostring (obj));
case
UCL_BOOLEAN:
return
PyBool_FromLong (ucl_object_toboolean (obj));
case
UCL_TIME:
return
Py_BuildValue (
"d"
, ucl_object_todouble (obj));
case
UCL_NULL:
Py_RETURN_NONE;
}
return
NULL;
}
static
PyObject *
_iterate_valid_ucl (ucl_object_t
const
*obj)
{
const
ucl_object_t *tmp;
ucl_object_iter_t it = NULL;
tmp = obj;
while
((obj = ucl_object_iterate (tmp, &it,
false
))) {
PyObject *val;
val = _basic_ucl_type(obj);
if
(!val) {
PyObject *key = NULL;
if
(obj->key != NULL) {
key = Py_BuildValue(
"s"
, ucl_object_key(obj));
}
if
(obj->type == UCL_OBJECT) {
const
ucl_object_t *cur;
ucl_object_iter_t it_obj = NULL;
val = PyDict_New();
while
((cur = ucl_object_iterate (obj, &it_obj,
true
))) {
PyObject *keyobj = Py_BuildValue(
"s"
,ucl_object_key(cur));
PyDict_SetItem(val, keyobj, _iterate_valid_ucl(cur));
}
}
else
if
(obj->type == UCL_ARRAY) {
const
ucl_object_t *cur;
ucl_object_iter_t it_obj = NULL;
val = PyList_New(0);
while
((cur = ucl_object_iterate (obj, &it_obj,
true
))) {
PyList_Append(val, _iterate_valid_ucl(cur));
}
}
else
if
(obj->type == UCL_USERDATA) {
val = PyBytes_FromString(obj->value.ud);
}
}
return
val;
}
PyErr_SetString(PyExc_SystemError,
"unhandled type"
);
return
NULL;
}
static
PyObject *
_internal_load_ucl (
char
*uclstr)
{
PyObject *ret;
struct
ucl_parser *parser = ucl_parser_new (UCL_PARSER_NO_TIME);
bool
r = ucl_parser_add_string(parser, uclstr, 0);
if
(r) {
if
(ucl_parser_get_error (parser)) {
PyErr_SetString(PyExc_ValueError, ucl_parser_get_error(parser));
ucl_parser_free(parser);
ret = NULL;
goto
return_with_parser;
}
else
{
ucl_object_t *uclobj = ucl_parser_get_object(parser);
ret = _iterate_valid_ucl(uclobj);
ucl_object_unref(uclobj);
goto
return_with_parser;
}
}
else
{
PyErr_SetString(PyExc_ValueError, ucl_parser_get_error (parser));
ret = NULL;
goto
return_with_parser;
}
return_with_parser:
ucl_parser_free(parser);
return
ret;
}
static
PyObject*
ucl_load (PyObject *self, PyObject *args)
{
char
*uclstr;
if
(PyArg_ParseTuple(args,
"z"
, &uclstr)) {
if
(!uclstr) {
Py_RETURN_NONE;
}
return
_internal_load_ucl(uclstr);
}
return
NULL;
}
static
ucl_object_t *
_iterate_python (PyObject *obj)
{
if
(obj == Py_None) {
return
ucl_object_new();
}
else
if
(PyBool_Check (obj)) {
return
ucl_object_frombool (obj == Py_True);
}
#if PY_MAJOR_VERSION < 3
else
if
(PyInt_Check (obj)) {
return
ucl_object_fromint (PyInt_AsLong (obj));
}
#endif
else
if
(PyLong_Check (obj)) {
return
ucl_object_fromint (PyLong_AsLong (obj));
}
else
if
(PyFloat_Check (obj)) {
return
ucl_object_fromdouble (PyFloat_AsDouble (obj));
}
else
if
(PyUnicode_Check (obj)) {
ucl_object_t *ucl_str;
PyObject *str = PyUnicode_AsASCIIString(obj);
ucl_str = ucl_object_fromstring (PyBytes_AsString (str));
Py_DECREF(str);
return
ucl_str;
}
#if PY_MAJOR_VERSION < 3
else
if
(PyString_Check (obj)) {
return
ucl_object_fromstring (PyString_AsString (obj));
}
#endif
else
if
(PyDict_Check(obj)) {
PyObject *key, *value;
Py_ssize_t pos = 0;
ucl_object_t *top, *elm;
char
*keystr = NULL;
top = ucl_object_typed_new (UCL_OBJECT);
while
(PyDict_Next(obj, &pos, &key, &value)) {
elm = _iterate_python(value);
if
(PyUnicode_Check(key)) {
PyObject *keyascii = PyUnicode_AsASCIIString(key);
keystr = PyBytes_AsString(keyascii);
Py_DECREF(keyascii);
}
#if PY_MAJOR_VERSION < 3
else
if
(PyString_Check(key)) {
keystr = PyString_AsString(key);
}
#endif
else
{
PyErr_SetString(PyExc_TypeError,
"Unknown key type"
);
return
NULL;
}
ucl_object_insert_key (top, elm, keystr, 0,
true
);
}
return
top;
}
else
if
(PySequence_Check(obj)) {
PyObject *value;
Py_ssize_t len, pos;
ucl_object_t *top, *elm;
len = PySequence_Length(obj);
top = ucl_object_typed_new (UCL_ARRAY);
for
(pos = 0; pos < len; pos++) {
value = PySequence_GetItem(obj, pos);
elm = _iterate_python(value);
ucl_array_append(top, elm);
}
return
top;
}
else
{
PyErr_SetString(PyExc_TypeError,
"Unhandled object type"
);
return
NULL;
}
return
NULL;
}
static
PyObject *
ucl_dump (PyObject *self, PyObject *args)
{
PyObject *obj;
ucl_emitter_t emitter;
ucl_object_t *root = NULL;
emitter = UCL_EMIT_CONFIG;
if
(!PyArg_ParseTuple(args,
"O|i"
, &obj, &emitter)) {
PyErr_SetString(PyExc_TypeError,
"Unhandled object type"
);
return
NULL;
}
if
(emitter >= UCL_EMIT_MAX) {
PyErr_SetString(PyExc_TypeError,
"Invalid emitter type"
);
return
NULL;
}
if
(obj == Py_None) {
Py_RETURN_NONE;
}
root = _iterate_python(obj);
if
(root) {
PyObject *ret;
char
*buf;
buf = (
char
*) ucl_object_emit (root, emitter);
ucl_object_unref (root);
#if PY_MAJOR_VERSION < 3
ret = PyString_FromString (buf);
#else
ret = PyUnicode_FromString (buf);
#endif
free
(buf);
return
ret;
}
return
NULL;
}
static
PyObject *
ucl_validate (PyObject *self, PyObject *args)
{
PyObject *dataobj, *schemaobj;
ucl_object_t *data, *schema;
bool
r;
struct
ucl_schema_error err;
if
(!PyArg_ParseTuple (args,
"OO"
, &schemaobj, &dataobj)) {
PyErr_SetString (PyExc_TypeError,
"Unhandled object type"
);
return
NULL;
}
schema = _iterate_python(schemaobj);
if
(!schema)
return
NULL;
data = _iterate_python(dataobj);
if
(!data)
return
NULL;
r = ucl_object_validate (schema, data, &err);
ucl_object_unref (schema);
ucl_object_unref (data);
if
(!r) {
PyErr_SetString (SchemaError, err.msg);
return
NULL;
}
Py_RETURN_TRUE;
}
static
PyMethodDef uclMethods[] = {
{
"load"
, ucl_load, METH_VARARGS,
"Load UCL from stream"
},
{
"dump"
, ucl_dump, METH_VARARGS,
"Dump UCL to stream"
},
{
"validate"
, ucl_validate, METH_VARARGS,
"Validate ucl stream against schema"
},
{NULL, NULL, 0, NULL}
};
static
void
init_macros(PyObject *mod)
{
PyModule_AddIntMacro(mod, UCL_EMIT_JSON);
PyModule_AddIntMacro(mod, UCL_EMIT_JSON_COMPACT);
PyModule_AddIntMacro(mod, UCL_EMIT_CONFIG);
PyModule_AddIntMacro(mod, UCL_EMIT_YAML);
PyModule_AddIntMacro(mod, UCL_EMIT_MSGPACK);
SchemaError = PyErr_NewException(
"ucl.SchemaError"
, NULL, NULL);
Py_INCREF(SchemaError);
PyModule_AddObject(mod,
"SchemaError"
, SchemaError);
}
#if PY_MAJOR_VERSION >= 3
static
struct
PyModuleDef uclmodule = {
PyModuleDef_HEAD_INIT,
"ucl"
,
NULL,
-1,
uclMethods
};
PyMODINIT_FUNC
PyInit_ucl (
void
)
{
PyObject *mod = PyModule_Create (&uclmodule);
init_macros (mod);
return
mod;
}
#else
void
initucl (
void
)
{
PyObject *mod = Py_InitModule (
"ucl"
, uclMethods);
init_macros (mod);
}
#endif