1318663Sdim// Attempts to load a UCL structure from a string 2318663Sdim#include <ucl.h> 3318663Sdim#include <Python.h> 4318663Sdim 5318663Sdimstatic PyObject *SchemaError; 6318663Sdim 7318663Sdimstatic PyObject * 8318663Sdim_basic_ucl_type (ucl_object_t const *obj) 9318663Sdim{ 10318663Sdim switch (obj->type) { 11318663Sdim case UCL_INT: 12318663Sdim return Py_BuildValue ("L", (long long)ucl_object_toint (obj)); 13318663Sdim case UCL_FLOAT: 14318663Sdim return Py_BuildValue ("d", ucl_object_todouble (obj)); 15319799Sdim case UCL_STRING: 16319799Sdim return Py_BuildValue ("s", ucl_object_tostring (obj)); 17327952Sdim case UCL_BOOLEAN: 18319799Sdim return PyBool_FromLong (ucl_object_toboolean (obj)); 19319799Sdim case UCL_TIME: 20319799Sdim return Py_BuildValue ("d", ucl_object_todouble (obj)); 21318663Sdim case UCL_NULL: 22318663Sdim Py_RETURN_NONE; 23320397Sdim } 24320397Sdim return NULL; 25320397Sdim} 26318663Sdim 27318663Sdimstatic PyObject * 28318663Sdim_iterate_valid_ucl (ucl_object_t const *obj) 29319479Sdim{ 30319479Sdim const ucl_object_t *tmp; 31319479Sdim ucl_object_iter_t it = NULL; 32319479Sdim 33319479Sdim tmp = obj; 34319479Sdim 35320041Sdim while ((obj = ucl_object_iterate (tmp, &it, false))) { 36320041Sdim PyObject *val; 37320041Sdim 38320041Sdim val = _basic_ucl_type(obj); 39319799Sdim if (!val) { 40319799Sdim PyObject *key = NULL; 41319799Sdim 42318663Sdim if (obj->key != NULL) { 43318663Sdim key = Py_BuildValue("s", ucl_object_key(obj)); 44320397Sdim } 45318663Sdim 46318663Sdim if (obj->type == UCL_OBJECT) { 47318663Sdim const ucl_object_t *cur; 48318663Sdim ucl_object_iter_t it_obj = NULL; 49318663Sdim 50318663Sdim val = PyDict_New(); 51320397Sdim 52318663Sdim while ((cur = ucl_object_iterate (obj, &it_obj, true))) { 53318663Sdim PyObject *keyobj = Py_BuildValue("s",ucl_object_key(cur)); 54318663Sdim PyDict_SetItem(val, keyobj, _iterate_valid_ucl(cur)); 55318663Sdim } 56318663Sdim } else if (obj->type == UCL_ARRAY) { 57318663Sdim const ucl_object_t *cur; 58318663Sdim ucl_object_iter_t it_obj = NULL; 59318663Sdim 60327952Sdim val = PyList_New(0); 61327952Sdim 62327952Sdim while ((cur = ucl_object_iterate (obj, &it_obj, true))) { 63327952Sdim PyList_Append(val, _iterate_valid_ucl(cur)); 64318663Sdim } 65318663Sdim } else if (obj->type == UCL_USERDATA) { 66318663Sdim // XXX: this should be 67327952Sdim // PyBytes_FromStringAndSize; where is the 68327952Sdim // length from? 69327952Sdim val = PyBytes_FromString(obj->value.ud); 70327952Sdim } 71327952Sdim } 72327952Sdim return val; 73327952Sdim } 74327952Sdim 75327952Sdim PyErr_SetString(PyExc_SystemError, "unhandled type"); 76318663Sdim return NULL; 77318663Sdim} 78318663Sdim 79318663Sdimstatic PyObject * 80318663Sdim_internal_load_ucl (char *uclstr) 81318663Sdim{ 82318663Sdim PyObject *ret; 83318663Sdim struct ucl_parser *parser = 84318663Sdim ucl_parser_new (UCL_PARSER_NO_TIME|UCL_PARSER_NO_IMPLICIT_ARRAYS); 85318663Sdim bool r = ucl_parser_add_string(parser, uclstr, 0); 86318663Sdim 87318663Sdim if (r) { 88318663Sdim if (ucl_parser_get_error (parser)) { 89319479Sdim PyErr_SetString(PyExc_ValueError, ucl_parser_get_error(parser)); 90319479Sdim ucl_parser_free(parser); 91319479Sdim ret = NULL; 92319479Sdim goto return_with_parser; 93319479Sdim } else { 94319479Sdim ucl_object_t *uclobj = ucl_parser_get_object(parser); 95319479Sdim ret = _iterate_valid_ucl(uclobj); 96319479Sdim ucl_object_unref(uclobj); 97319479Sdim goto return_with_parser; 98319479Sdim } 99319479Sdim } 100319479Sdim else { 101319479Sdim PyErr_SetString(PyExc_ValueError, ucl_parser_get_error (parser)); 102319479Sdim ret = NULL; 103319479Sdim goto return_with_parser; 104319479Sdim } 105319479Sdim 106318663Sdimreturn_with_parser: 107320397Sdim ucl_parser_free(parser); 108320397Sdim return ret; 109319479Sdim} 110320397Sdim 111319479Sdimstatic PyObject* 112319479Sdimucl_load (PyObject *self, PyObject *args) 113319479Sdim{ 114319479Sdim char *uclstr; 115319479Sdim 116319479Sdim if (PyArg_ParseTuple(args, "z", &uclstr)) { 117319479Sdim if (!uclstr) { 118320397Sdim Py_RETURN_NONE; 119319479Sdim } 120319479Sdim 121319479Sdim return _internal_load_ucl(uclstr); 122320397Sdim } 123319479Sdim 124320397Sdim return NULL; 125319479Sdim} 126318663Sdim 127318663Sdimstatic ucl_object_t * 128318663Sdim_iterate_python (PyObject *obj) 129319799Sdim{ 130319479Sdim if (obj == Py_None) { 131319479Sdim return ucl_object_new(); 132319479Sdim } 133327952Sdim else if (PyBool_Check (obj)) { 134327952Sdim return ucl_object_frombool (obj == Py_True); 135327952Sdim } 136327952Sdim#if PY_MAJOR_VERSION < 3 137327952Sdim else if (PyInt_Check (obj)) { 138327952Sdim return ucl_object_fromint (PyInt_AsLong (obj)); 139327952Sdim } 140327952Sdim#endif 141327952Sdim else if (PyLong_Check (obj)) { 142327952Sdim return ucl_object_fromint (PyLong_AsLong (obj)); 143327952Sdim } 144327952Sdim else if (PyFloat_Check (obj)) { 145327952Sdim return ucl_object_fromdouble (PyFloat_AsDouble (obj)); 146327952Sdim } 147319479Sdim else if (PyUnicode_Check (obj)) { 148319479Sdim ucl_object_t *ucl_str; 149319479Sdim PyObject *str = PyUnicode_AsASCIIString(obj); 150319479Sdim ucl_str = ucl_object_fromstring (PyBytes_AsString (str)); 151319799Sdim Py_DECREF(str); 152319799Sdim return ucl_str; 153320041Sdim } 154320041Sdim#if PY_MAJOR_VERSION < 3 155320041Sdim else if (PyString_Check (obj)) { 156320041Sdim return ucl_object_fromstring (PyString_AsString (obj)); 157320041Sdim } 158320041Sdim#endif 159319799Sdim else if (PyDict_Check(obj)) { 160319799Sdim PyObject *key, *value; 161320041Sdim Py_ssize_t pos = 0; 162319799Sdim ucl_object_t *top, *elm; 163319799Sdim char *keystr = NULL; 164319479Sdim 165319479Sdim top = ucl_object_typed_new (UCL_OBJECT); 166319479Sdim 167319479Sdim while (PyDict_Next(obj, &pos, &key, &value)) { 168319479Sdim elm = _iterate_python(value); 169319479Sdim 170320041Sdim if (PyUnicode_Check(key)) { 171320041Sdim PyObject *keyascii = PyUnicode_AsASCIIString(key); 172319479Sdim keystr = PyBytes_AsString(keyascii); 173319479Sdim Py_DECREF(keyascii); 174319479Sdim } 175320041Sdim#if PY_MAJOR_VERSION < 3 176320041Sdim else if (PyString_Check(key)) { 177320041Sdim keystr = PyString_AsString(key); 178320041Sdim } 179320041Sdim#endif 180319479Sdim else { 181319479Sdim PyErr_SetString(PyExc_TypeError, "Unknown key type"); 182319479Sdim return NULL; 183319799Sdim } 184319799Sdim 185319799Sdim ucl_object_insert_key (top, elm, keystr, 0, true); 186319799Sdim } 187319479Sdim 188319799Sdim return top; 189319799Sdim } 190319799Sdim else if (PySequence_Check(obj)) { 191319799Sdim PyObject *value; 192319799Sdim Py_ssize_t len, pos; 193319799Sdim ucl_object_t *top, *elm; 194319799Sdim 195319799Sdim len = PySequence_Length(obj); 196319799Sdim top = ucl_object_typed_new (UCL_ARRAY); 197319799Sdim 198319799Sdim for (pos = 0; pos < len; pos++) { 199319799Sdim value = PySequence_GetItem(obj, pos); 200319799Sdim elm = _iterate_python(value); 201319799Sdim ucl_array_append(top, elm); 202319799Sdim } 203319799Sdim 204319799Sdim return top; 205319799Sdim } 206319799Sdim else { 207319799Sdim PyErr_SetString(PyExc_TypeError, "Unhandled object type"); 208319799Sdim return NULL; 209319799Sdim } 210319799Sdim 211319799Sdim return NULL; 212319799Sdim} 213319799Sdim 214319479Sdimstatic PyObject * 215320041Sdimucl_dump (PyObject *self, PyObject *args) 216320041Sdim{ 217319479Sdim PyObject *obj; 218320041Sdim ucl_emitter_t emitter; 219319479Sdim ucl_object_t *root = NULL; 220319479Sdim 221319479Sdim emitter = UCL_EMIT_CONFIG; 222319479Sdim 223319479Sdim if (!PyArg_ParseTuple(args, "O|i", &obj, &emitter)) { 224320041Sdim PyErr_SetString(PyExc_TypeError, "Unhandled object type"); 225320041Sdim return NULL; 226319479Sdim } 227320041Sdim 228319479Sdim if (emitter >= UCL_EMIT_MAX) { 229319479Sdim PyErr_SetString(PyExc_TypeError, "Invalid emitter type"); 230319479Sdim return NULL; 231319479Sdim } 232319479Sdim 233319479Sdim if (obj == Py_None) { 234319479Sdim Py_RETURN_NONE; 235319799Sdim } 236319799Sdim 237319479Sdim root = _iterate_python(obj); 238319479Sdim if (root) { 239319799Sdim PyObject *ret; 240319799Sdim char *buf; 241319799Sdim 242319479Sdim buf = (char *) ucl_object_emit (root, emitter); 243319479Sdim ucl_object_unref (root); 244319799Sdim#if PY_MAJOR_VERSION < 3 245319799Sdim ret = PyString_FromString (buf); 246319799Sdim#else 247319479Sdim ret = PyUnicode_FromString (buf); 248319479Sdim#endif 249319479Sdim free(buf); 250319479Sdim 251319479Sdim return ret; 252319479Sdim } 253319479Sdim 254319479Sdim return NULL; 255320041Sdim} 256320041Sdim 257319479Sdimstatic PyObject * 258319479Sdimucl_validate (PyObject *self, PyObject *args) 259319479Sdim{ 260320397Sdim PyObject *dataobj, *schemaobj; 261319479Sdim ucl_object_t *data, *schema; 262344779Sdim bool r; 263319479Sdim struct ucl_schema_error err; 264319479Sdim 265319479Sdim if (!PyArg_ParseTuple (args, "OO", &schemaobj, &dataobj)) { 266319479Sdim PyErr_SetString (PyExc_TypeError, "Unhandled object type"); 267320397Sdim return NULL; 268319479Sdim } 269319479Sdim 270319479Sdim schema = _iterate_python(schemaobj); 271319799Sdim if (!schema) 272320041Sdim return NULL; 273319479Sdim 274319479Sdim data = _iterate_python(dataobj); 275319479Sdim if (!data) 276319479Sdim return NULL; 277319479Sdim 278319479Sdim // validation 279319479Sdim r = ucl_object_validate (schema, data, &err); 280319479Sdim ucl_object_unref (schema); 281319479Sdim ucl_object_unref (data); 282319479Sdim 283319479Sdim if (!r) { 284319479Sdim PyErr_SetString (SchemaError, err.msg); 285319479Sdim return NULL; 286319479Sdim } 287319479Sdim 288319479Sdim Py_RETURN_TRUE; 289319479Sdim} 290319479Sdim 291319799Sdimstatic PyMethodDef uclMethods[] = { 292319799Sdim {"load", ucl_load, METH_VARARGS, "Load UCL from stream"}, 293319799Sdim {"dump", ucl_dump, METH_VARARGS, "Dump UCL to stream"}, 294319799Sdim {"validate", ucl_validate, METH_VARARGS, "Validate ucl stream against schema"}, 295319799Sdim {NULL, NULL, 0, NULL} 296320397Sdim}; 297319799Sdim 298319799Sdimstatic void 299319799Sdiminit_macros(PyObject *mod) 300320397Sdim{ 301319799Sdim PyModule_AddIntMacro(mod, UCL_EMIT_JSON); 302319799Sdim PyModule_AddIntMacro(mod, UCL_EMIT_JSON_COMPACT); 303319799Sdim PyModule_AddIntMacro(mod, UCL_EMIT_CONFIG); 304319799Sdim PyModule_AddIntMacro(mod, UCL_EMIT_YAML); 305319799Sdim PyModule_AddIntMacro(mod, UCL_EMIT_MSGPACK); 306320397Sdim 307319799Sdim SchemaError = PyErr_NewException("ucl.SchemaError", NULL, NULL); 308319799Sdim Py_INCREF(SchemaError); 309319799Sdim PyModule_AddObject(mod, "SchemaError", SchemaError); 310319799Sdim} 311319799Sdim 312319799Sdim#if PY_MAJOR_VERSION >= 3 313319799Sdimstatic struct PyModuleDef uclmodule = { 314319799Sdim PyModuleDef_HEAD_INIT, 315319799Sdim "ucl", 316319799Sdim NULL, 317319799Sdim -1, 318319799Sdim uclMethods 319320397Sdim}; 320319799Sdim 321320397SdimPyMODINIT_FUNC 322319799SdimPyInit_ucl (void) 323319799Sdim{ 324319799Sdim PyObject *mod = PyModule_Create (&uclmodule); 325319799Sdim init_macros (mod); 326319799Sdim 327319799Sdim return mod; 328319799Sdim} 329319799Sdim#else 330319799Sdimvoid initucl (void) 331319799Sdim{ 332319799Sdim PyObject *mod = Py_InitModule ("ucl", uclMethods); 333319799Sdim init_macros (mod); 334319799Sdim} 335319799Sdim#endif 336319799Sdim