139ee7a7aSBaptiste Daroussin // Attempts to load a UCL structure from a string
239ee7a7aSBaptiste Daroussin #include <ucl.h>
339ee7a7aSBaptiste Daroussin #include <Python.h>
439ee7a7aSBaptiste Daroussin
5273c26a3SBaptiste Daroussin static PyObject *SchemaError;
6273c26a3SBaptiste Daroussin
739ee7a7aSBaptiste Daroussin static PyObject *
_basic_ucl_type(ucl_object_t const * obj)8d9f0ce31SBaptiste Daroussin _basic_ucl_type (ucl_object_t const *obj)
9d9f0ce31SBaptiste Daroussin {
10d9f0ce31SBaptiste Daroussin switch (obj->type) {
11d9f0ce31SBaptiste Daroussin case UCL_INT:
1239ee7a7aSBaptiste Daroussin return Py_BuildValue ("L", (long long)ucl_object_toint (obj));
13d9f0ce31SBaptiste Daroussin case UCL_FLOAT:
1439ee7a7aSBaptiste Daroussin return Py_BuildValue ("d", ucl_object_todouble (obj));
15d9f0ce31SBaptiste Daroussin case UCL_STRING:
1639ee7a7aSBaptiste Daroussin return Py_BuildValue ("s", ucl_object_tostring (obj));
17d9f0ce31SBaptiste Daroussin case UCL_BOOLEAN:
18273c26a3SBaptiste Daroussin return PyBool_FromLong (ucl_object_toboolean (obj));
19d9f0ce31SBaptiste Daroussin case UCL_TIME:
2039ee7a7aSBaptiste Daroussin return Py_BuildValue ("d", ucl_object_todouble (obj));
21273c26a3SBaptiste Daroussin case UCL_NULL:
22273c26a3SBaptiste Daroussin Py_RETURN_NONE;
2339ee7a7aSBaptiste Daroussin }
2439ee7a7aSBaptiste Daroussin return NULL;
2539ee7a7aSBaptiste Daroussin }
2639ee7a7aSBaptiste Daroussin
2739ee7a7aSBaptiste Daroussin static PyObject *
_iterate_valid_ucl(ucl_object_t const * obj)28d9f0ce31SBaptiste Daroussin _iterate_valid_ucl (ucl_object_t const *obj)
29d9f0ce31SBaptiste Daroussin {
3039ee7a7aSBaptiste Daroussin const ucl_object_t *tmp;
3139ee7a7aSBaptiste Daroussin ucl_object_iter_t it = NULL;
3239ee7a7aSBaptiste Daroussin
3339ee7a7aSBaptiste Daroussin tmp = obj;
3439ee7a7aSBaptiste Daroussin
35d9f0ce31SBaptiste Daroussin while ((obj = ucl_object_iterate (tmp, &it, false))) {
3639ee7a7aSBaptiste Daroussin PyObject *val;
3739ee7a7aSBaptiste Daroussin
3839ee7a7aSBaptiste Daroussin val = _basic_ucl_type(obj);
3939ee7a7aSBaptiste Daroussin if (!val) {
4039ee7a7aSBaptiste Daroussin PyObject *key = NULL;
41d9f0ce31SBaptiste Daroussin
4239ee7a7aSBaptiste Daroussin if (obj->key != NULL) {
4339ee7a7aSBaptiste Daroussin key = Py_BuildValue("s", ucl_object_key(obj));
4439ee7a7aSBaptiste Daroussin }
4539ee7a7aSBaptiste Daroussin
4639ee7a7aSBaptiste Daroussin if (obj->type == UCL_OBJECT) {
4739ee7a7aSBaptiste Daroussin const ucl_object_t *cur;
4839ee7a7aSBaptiste Daroussin ucl_object_iter_t it_obj = NULL;
49d9f0ce31SBaptiste Daroussin
50d9f0ce31SBaptiste Daroussin val = PyDict_New();
51d9f0ce31SBaptiste Daroussin
52d9f0ce31SBaptiste Daroussin while ((cur = ucl_object_iterate (obj, &it_obj, true))) {
5339ee7a7aSBaptiste Daroussin PyObject *keyobj = Py_BuildValue("s",ucl_object_key(cur));
5439ee7a7aSBaptiste Daroussin PyDict_SetItem(val, keyobj, _iterate_valid_ucl(cur));
5539ee7a7aSBaptiste Daroussin }
56d9f0ce31SBaptiste Daroussin } else if (obj->type == UCL_ARRAY) {
5739ee7a7aSBaptiste Daroussin const ucl_object_t *cur;
5839ee7a7aSBaptiste Daroussin ucl_object_iter_t it_obj = NULL;
59d9f0ce31SBaptiste Daroussin
60d9f0ce31SBaptiste Daroussin val = PyList_New(0);
61d9f0ce31SBaptiste Daroussin
62d9f0ce31SBaptiste Daroussin while ((cur = ucl_object_iterate (obj, &it_obj, true))) {
6339ee7a7aSBaptiste Daroussin PyList_Append(val, _iterate_valid_ucl(cur));
6439ee7a7aSBaptiste Daroussin }
65d9f0ce31SBaptiste Daroussin } else if (obj->type == UCL_USERDATA) {
6639ee7a7aSBaptiste Daroussin // XXX: this should be
6739ee7a7aSBaptiste Daroussin // PyBytes_FromStringAndSize; where is the
6839ee7a7aSBaptiste Daroussin // length from?
6939ee7a7aSBaptiste Daroussin val = PyBytes_FromString(obj->value.ud);
7039ee7a7aSBaptiste Daroussin }
7139ee7a7aSBaptiste Daroussin }
7239ee7a7aSBaptiste Daroussin return val;
7339ee7a7aSBaptiste Daroussin }
7439ee7a7aSBaptiste Daroussin
7539ee7a7aSBaptiste Daroussin PyErr_SetString(PyExc_SystemError, "unhandled type");
7639ee7a7aSBaptiste Daroussin return NULL;
7739ee7a7aSBaptiste Daroussin }
7839ee7a7aSBaptiste Daroussin
7939ee7a7aSBaptiste Daroussin static PyObject *
_internal_load_ucl(char * uclstr)80d9f0ce31SBaptiste Daroussin _internal_load_ucl (char *uclstr)
81d9f0ce31SBaptiste Daroussin {
8239ee7a7aSBaptiste Daroussin PyObject *ret;
83*a0409676SBaptiste Daroussin struct ucl_parser *parser =
84*a0409676SBaptiste Daroussin ucl_parser_new (UCL_PARSER_NO_TIME|UCL_PARSER_NO_IMPLICIT_ARRAYS);
8539ee7a7aSBaptiste Daroussin bool r = ucl_parser_add_string(parser, uclstr, 0);
86d9f0ce31SBaptiste Daroussin
8739ee7a7aSBaptiste Daroussin if (r) {
8839ee7a7aSBaptiste Daroussin if (ucl_parser_get_error (parser)) {
8939ee7a7aSBaptiste Daroussin PyErr_SetString(PyExc_ValueError, ucl_parser_get_error(parser));
9039ee7a7aSBaptiste Daroussin ucl_parser_free(parser);
9139ee7a7aSBaptiste Daroussin ret = NULL;
9239ee7a7aSBaptiste Daroussin goto return_with_parser;
9339ee7a7aSBaptiste Daroussin } else {
9439ee7a7aSBaptiste Daroussin ucl_object_t *uclobj = ucl_parser_get_object(parser);
9539ee7a7aSBaptiste Daroussin ret = _iterate_valid_ucl(uclobj);
9639ee7a7aSBaptiste Daroussin ucl_object_unref(uclobj);
9739ee7a7aSBaptiste Daroussin goto return_with_parser;
9839ee7a7aSBaptiste Daroussin }
99d9f0ce31SBaptiste Daroussin }
100d9f0ce31SBaptiste Daroussin else {
10139ee7a7aSBaptiste Daroussin PyErr_SetString(PyExc_ValueError, ucl_parser_get_error (parser));
10239ee7a7aSBaptiste Daroussin ret = NULL;
10339ee7a7aSBaptiste Daroussin goto return_with_parser;
10439ee7a7aSBaptiste Daroussin }
10539ee7a7aSBaptiste Daroussin
10639ee7a7aSBaptiste Daroussin return_with_parser:
10739ee7a7aSBaptiste Daroussin ucl_parser_free(parser);
10839ee7a7aSBaptiste Daroussin return ret;
10939ee7a7aSBaptiste Daroussin }
11039ee7a7aSBaptiste Daroussin
11139ee7a7aSBaptiste Daroussin static PyObject*
ucl_load(PyObject * self,PyObject * args)112d9f0ce31SBaptiste Daroussin ucl_load (PyObject *self, PyObject *args)
113d9f0ce31SBaptiste Daroussin {
11439ee7a7aSBaptiste Daroussin char *uclstr;
115d9f0ce31SBaptiste Daroussin
11639ee7a7aSBaptiste Daroussin if (PyArg_ParseTuple(args, "z", &uclstr)) {
11739ee7a7aSBaptiste Daroussin if (!uclstr) {
11839ee7a7aSBaptiste Daroussin Py_RETURN_NONE;
11939ee7a7aSBaptiste Daroussin }
120d9f0ce31SBaptiste Daroussin
12139ee7a7aSBaptiste Daroussin return _internal_load_ucl(uclstr);
12239ee7a7aSBaptiste Daroussin }
123d9f0ce31SBaptiste Daroussin
124d9f0ce31SBaptiste Daroussin return NULL;
125d9f0ce31SBaptiste Daroussin }
126d9f0ce31SBaptiste Daroussin
127d9f0ce31SBaptiste Daroussin static ucl_object_t *
_iterate_python(PyObject * obj)128d9f0ce31SBaptiste Daroussin _iterate_python (PyObject *obj)
129d9f0ce31SBaptiste Daroussin {
130d9f0ce31SBaptiste Daroussin if (obj == Py_None) {
131d9f0ce31SBaptiste Daroussin return ucl_object_new();
132d9f0ce31SBaptiste Daroussin }
133273c26a3SBaptiste Daroussin else if (PyBool_Check (obj)) {
134273c26a3SBaptiste Daroussin return ucl_object_frombool (obj == Py_True);
135273c26a3SBaptiste Daroussin }
136273c26a3SBaptiste Daroussin #if PY_MAJOR_VERSION < 3
137273c26a3SBaptiste Daroussin else if (PyInt_Check (obj)) {
138273c26a3SBaptiste Daroussin return ucl_object_fromint (PyInt_AsLong (obj));
139273c26a3SBaptiste Daroussin }
140273c26a3SBaptiste Daroussin #endif
141273c26a3SBaptiste Daroussin else if (PyLong_Check (obj)) {
142273c26a3SBaptiste Daroussin return ucl_object_fromint (PyLong_AsLong (obj));
143273c26a3SBaptiste Daroussin }
144273c26a3SBaptiste Daroussin else if (PyFloat_Check (obj)) {
145273c26a3SBaptiste Daroussin return ucl_object_fromdouble (PyFloat_AsDouble (obj));
146273c26a3SBaptiste Daroussin }
147273c26a3SBaptiste Daroussin else if (PyUnicode_Check (obj)) {
148273c26a3SBaptiste Daroussin ucl_object_t *ucl_str;
149273c26a3SBaptiste Daroussin PyObject *str = PyUnicode_AsASCIIString(obj);
150273c26a3SBaptiste Daroussin ucl_str = ucl_object_fromstring (PyBytes_AsString (str));
151273c26a3SBaptiste Daroussin Py_DECREF(str);
152273c26a3SBaptiste Daroussin return ucl_str;
153273c26a3SBaptiste Daroussin }
154273c26a3SBaptiste Daroussin #if PY_MAJOR_VERSION < 3
155273c26a3SBaptiste Daroussin else if (PyString_Check (obj)) {
156273c26a3SBaptiste Daroussin return ucl_object_fromstring (PyString_AsString (obj));
157273c26a3SBaptiste Daroussin }
158273c26a3SBaptiste Daroussin #endif
159d9f0ce31SBaptiste Daroussin else if (PyDict_Check(obj)) {
160d9f0ce31SBaptiste Daroussin PyObject *key, *value;
161d9f0ce31SBaptiste Daroussin Py_ssize_t pos = 0;
162d9f0ce31SBaptiste Daroussin ucl_object_t *top, *elm;
163273c26a3SBaptiste Daroussin char *keystr = NULL;
164d9f0ce31SBaptiste Daroussin
165d9f0ce31SBaptiste Daroussin top = ucl_object_typed_new (UCL_OBJECT);
166d9f0ce31SBaptiste Daroussin
167d9f0ce31SBaptiste Daroussin while (PyDict_Next(obj, &pos, &key, &value)) {
168d9f0ce31SBaptiste Daroussin elm = _iterate_python(value);
169273c26a3SBaptiste Daroussin
170273c26a3SBaptiste Daroussin if (PyUnicode_Check(key)) {
171273c26a3SBaptiste Daroussin PyObject *keyascii = PyUnicode_AsASCIIString(key);
172273c26a3SBaptiste Daroussin keystr = PyBytes_AsString(keyascii);
173273c26a3SBaptiste Daroussin Py_DECREF(keyascii);
174273c26a3SBaptiste Daroussin }
175273c26a3SBaptiste Daroussin #if PY_MAJOR_VERSION < 3
176273c26a3SBaptiste Daroussin else if (PyString_Check(key)) {
177273c26a3SBaptiste Daroussin keystr = PyString_AsString(key);
178273c26a3SBaptiste Daroussin }
179273c26a3SBaptiste Daroussin #endif
180273c26a3SBaptiste Daroussin else {
181273c26a3SBaptiste Daroussin PyErr_SetString(PyExc_TypeError, "Unknown key type");
182273c26a3SBaptiste Daroussin return NULL;
183273c26a3SBaptiste Daroussin }
184273c26a3SBaptiste Daroussin
185273c26a3SBaptiste Daroussin ucl_object_insert_key (top, elm, keystr, 0, true);
186d9f0ce31SBaptiste Daroussin }
187d9f0ce31SBaptiste Daroussin
188d9f0ce31SBaptiste Daroussin return top;
189d9f0ce31SBaptiste Daroussin }
190d9f0ce31SBaptiste Daroussin else if (PySequence_Check(obj)) {
191d9f0ce31SBaptiste Daroussin PyObject *value;
192d9f0ce31SBaptiste Daroussin Py_ssize_t len, pos;
193d9f0ce31SBaptiste Daroussin ucl_object_t *top, *elm;
194d9f0ce31SBaptiste Daroussin
195d9f0ce31SBaptiste Daroussin len = PySequence_Length(obj);
196d9f0ce31SBaptiste Daroussin top = ucl_object_typed_new (UCL_ARRAY);
197d9f0ce31SBaptiste Daroussin
198d9f0ce31SBaptiste Daroussin for (pos = 0; pos < len; pos++) {
199d9f0ce31SBaptiste Daroussin value = PySequence_GetItem(obj, pos);
200d9f0ce31SBaptiste Daroussin elm = _iterate_python(value);
201d9f0ce31SBaptiste Daroussin ucl_array_append(top, elm);
202d9f0ce31SBaptiste Daroussin }
203d9f0ce31SBaptiste Daroussin
204d9f0ce31SBaptiste Daroussin return top;
205d9f0ce31SBaptiste Daroussin }
206d9f0ce31SBaptiste Daroussin else {
207d9f0ce31SBaptiste Daroussin PyErr_SetString(PyExc_TypeError, "Unhandled object type");
208d9f0ce31SBaptiste Daroussin return NULL;
209d9f0ce31SBaptiste Daroussin }
210d9f0ce31SBaptiste Daroussin
21139ee7a7aSBaptiste Daroussin return NULL;
21239ee7a7aSBaptiste Daroussin }
21339ee7a7aSBaptiste Daroussin
21439ee7a7aSBaptiste Daroussin static PyObject *
ucl_dump(PyObject * self,PyObject * args)215d9f0ce31SBaptiste Daroussin ucl_dump (PyObject *self, PyObject *args)
216d9f0ce31SBaptiste Daroussin {
217d9f0ce31SBaptiste Daroussin PyObject *obj;
218d9f0ce31SBaptiste Daroussin ucl_emitter_t emitter;
219d9f0ce31SBaptiste Daroussin ucl_object_t *root = NULL;
220d9f0ce31SBaptiste Daroussin
221d9f0ce31SBaptiste Daroussin emitter = UCL_EMIT_CONFIG;
222d9f0ce31SBaptiste Daroussin
223d9f0ce31SBaptiste Daroussin if (!PyArg_ParseTuple(args, "O|i", &obj, &emitter)) {
224d9f0ce31SBaptiste Daroussin PyErr_SetString(PyExc_TypeError, "Unhandled object type");
225d9f0ce31SBaptiste Daroussin return NULL;
226d9f0ce31SBaptiste Daroussin }
227d9f0ce31SBaptiste Daroussin
228d9f0ce31SBaptiste Daroussin if (emitter >= UCL_EMIT_MAX) {
229d9f0ce31SBaptiste Daroussin PyErr_SetString(PyExc_TypeError, "Invalid emitter type");
230d9f0ce31SBaptiste Daroussin return NULL;
231d9f0ce31SBaptiste Daroussin }
232d9f0ce31SBaptiste Daroussin
233d9f0ce31SBaptiste Daroussin if (obj == Py_None) {
234d9f0ce31SBaptiste Daroussin Py_RETURN_NONE;
235d9f0ce31SBaptiste Daroussin }
236d9f0ce31SBaptiste Daroussin
237d9f0ce31SBaptiste Daroussin root = _iterate_python(obj);
238d9f0ce31SBaptiste Daroussin if (root) {
239d9f0ce31SBaptiste Daroussin PyObject *ret;
240d9f0ce31SBaptiste Daroussin char *buf;
241d9f0ce31SBaptiste Daroussin
242d9f0ce31SBaptiste Daroussin buf = (char *) ucl_object_emit (root, emitter);
243d9f0ce31SBaptiste Daroussin ucl_object_unref (root);
244273c26a3SBaptiste Daroussin #if PY_MAJOR_VERSION < 3
245d9f0ce31SBaptiste Daroussin ret = PyString_FromString (buf);
246273c26a3SBaptiste Daroussin #else
247273c26a3SBaptiste Daroussin ret = PyUnicode_FromString (buf);
248273c26a3SBaptiste Daroussin #endif
249d9f0ce31SBaptiste Daroussin free(buf);
250d9f0ce31SBaptiste Daroussin
251d9f0ce31SBaptiste Daroussin return ret;
252d9f0ce31SBaptiste Daroussin }
253d9f0ce31SBaptiste Daroussin
254d9f0ce31SBaptiste Daroussin return NULL;
255d9f0ce31SBaptiste Daroussin }
256d9f0ce31SBaptiste Daroussin
257d9f0ce31SBaptiste Daroussin static PyObject *
ucl_validate(PyObject * self,PyObject * args)258d9f0ce31SBaptiste Daroussin ucl_validate (PyObject *self, PyObject *args)
259d9f0ce31SBaptiste Daroussin {
260273c26a3SBaptiste Daroussin PyObject *dataobj, *schemaobj;
261273c26a3SBaptiste Daroussin ucl_object_t *data, *schema;
262273c26a3SBaptiste Daroussin bool r;
263273c26a3SBaptiste Daroussin struct ucl_schema_error err;
264d9f0ce31SBaptiste Daroussin
265273c26a3SBaptiste Daroussin if (!PyArg_ParseTuple (args, "OO", &schemaobj, &dataobj)) {
266273c26a3SBaptiste Daroussin PyErr_SetString (PyExc_TypeError, "Unhandled object type");
26739ee7a7aSBaptiste Daroussin return NULL;
26839ee7a7aSBaptiste Daroussin }
26939ee7a7aSBaptiste Daroussin
270273c26a3SBaptiste Daroussin schema = _iterate_python(schemaobj);
271273c26a3SBaptiste Daroussin if (!schema)
272273c26a3SBaptiste Daroussin return NULL;
273273c26a3SBaptiste Daroussin
274273c26a3SBaptiste Daroussin data = _iterate_python(dataobj);
275273c26a3SBaptiste Daroussin if (!data)
276273c26a3SBaptiste Daroussin return NULL;
277273c26a3SBaptiste Daroussin
278273c26a3SBaptiste Daroussin // validation
279273c26a3SBaptiste Daroussin r = ucl_object_validate (schema, data, &err);
280273c26a3SBaptiste Daroussin ucl_object_unref (schema);
281273c26a3SBaptiste Daroussin ucl_object_unref (data);
282273c26a3SBaptiste Daroussin
283273c26a3SBaptiste Daroussin if (!r) {
284273c26a3SBaptiste Daroussin PyErr_SetString (SchemaError, err.msg);
285273c26a3SBaptiste Daroussin return NULL;
286273c26a3SBaptiste Daroussin }
287273c26a3SBaptiste Daroussin
288273c26a3SBaptiste Daroussin Py_RETURN_TRUE;
289273c26a3SBaptiste Daroussin }
290273c26a3SBaptiste Daroussin
29139ee7a7aSBaptiste Daroussin static PyMethodDef uclMethods[] = {
29239ee7a7aSBaptiste Daroussin {"load", ucl_load, METH_VARARGS, "Load UCL from stream"},
293d9f0ce31SBaptiste Daroussin {"dump", ucl_dump, METH_VARARGS, "Dump UCL to stream"},
29439ee7a7aSBaptiste Daroussin {"validate", ucl_validate, METH_VARARGS, "Validate ucl stream against schema"},
29539ee7a7aSBaptiste Daroussin {NULL, NULL, 0, NULL}
29639ee7a7aSBaptiste Daroussin };
29739ee7a7aSBaptiste Daroussin
298d9f0ce31SBaptiste Daroussin static void
init_macros(PyObject * mod)299d9f0ce31SBaptiste Daroussin init_macros(PyObject *mod)
300d9f0ce31SBaptiste Daroussin {
301d9f0ce31SBaptiste Daroussin PyModule_AddIntMacro(mod, UCL_EMIT_JSON);
302d9f0ce31SBaptiste Daroussin PyModule_AddIntMacro(mod, UCL_EMIT_JSON_COMPACT);
303d9f0ce31SBaptiste Daroussin PyModule_AddIntMacro(mod, UCL_EMIT_CONFIG);
304d9f0ce31SBaptiste Daroussin PyModule_AddIntMacro(mod, UCL_EMIT_YAML);
305d9f0ce31SBaptiste Daroussin PyModule_AddIntMacro(mod, UCL_EMIT_MSGPACK);
306273c26a3SBaptiste Daroussin
307273c26a3SBaptiste Daroussin SchemaError = PyErr_NewException("ucl.SchemaError", NULL, NULL);
308273c26a3SBaptiste Daroussin Py_INCREF(SchemaError);
309273c26a3SBaptiste Daroussin PyModule_AddObject(mod, "SchemaError", SchemaError);
310d9f0ce31SBaptiste Daroussin }
311d9f0ce31SBaptiste Daroussin
31239ee7a7aSBaptiste Daroussin #if PY_MAJOR_VERSION >= 3
31339ee7a7aSBaptiste Daroussin static struct PyModuleDef uclmodule = {
31439ee7a7aSBaptiste Daroussin PyModuleDef_HEAD_INIT,
31539ee7a7aSBaptiste Daroussin "ucl",
31639ee7a7aSBaptiste Daroussin NULL,
31739ee7a7aSBaptiste Daroussin -1,
31839ee7a7aSBaptiste Daroussin uclMethods
31939ee7a7aSBaptiste Daroussin };
32039ee7a7aSBaptiste Daroussin
32139ee7a7aSBaptiste Daroussin PyMODINIT_FUNC
PyInit_ucl(void)322d9f0ce31SBaptiste Daroussin PyInit_ucl (void)
323d9f0ce31SBaptiste Daroussin {
324d9f0ce31SBaptiste Daroussin PyObject *mod = PyModule_Create (&uclmodule);
325d9f0ce31SBaptiste Daroussin init_macros (mod);
326d9f0ce31SBaptiste Daroussin
327d9f0ce31SBaptiste Daroussin return mod;
32839ee7a7aSBaptiste Daroussin }
32939ee7a7aSBaptiste Daroussin #else
initucl(void)330d9f0ce31SBaptiste Daroussin void initucl (void)
331d9f0ce31SBaptiste Daroussin {
332d9f0ce31SBaptiste Daroussin PyObject *mod = Py_InitModule ("ucl", uclMethods);
333d9f0ce31SBaptiste Daroussin init_macros (mod);
33439ee7a7aSBaptiste Daroussin }
33539ee7a7aSBaptiste Daroussin #endif
336