139ee7a7aSBaptiste Daroussin // Attempts to load a UCL structure from a string 239ee7a7aSBaptiste Daroussin #include <ucl.h> 339ee7a7aSBaptiste Daroussin #include <Python.h> 439ee7a7aSBaptiste Daroussin 5*273c26a3SBaptiste Daroussin static PyObject *SchemaError; 6*273c26a3SBaptiste Daroussin 739ee7a7aSBaptiste Daroussin static PyObject * 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: 18*273c26a3SBaptiste Daroussin return PyBool_FromLong (ucl_object_toboolean (obj)); 19d9f0ce31SBaptiste Daroussin case UCL_TIME: 2039ee7a7aSBaptiste Daroussin return Py_BuildValue ("d", ucl_object_todouble (obj)); 21*273c26a3SBaptiste Daroussin case UCL_NULL: 22*273c26a3SBaptiste Daroussin Py_RETURN_NONE; 2339ee7a7aSBaptiste Daroussin } 2439ee7a7aSBaptiste Daroussin return NULL; 2539ee7a7aSBaptiste Daroussin } 2639ee7a7aSBaptiste Daroussin 2739ee7a7aSBaptiste Daroussin static PyObject * 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 * 80d9f0ce31SBaptiste Daroussin _internal_load_ucl (char *uclstr) 81d9f0ce31SBaptiste Daroussin { 8239ee7a7aSBaptiste Daroussin PyObject *ret; 8339ee7a7aSBaptiste Daroussin struct ucl_parser *parser = ucl_parser_new (UCL_PARSER_NO_TIME); 8439ee7a7aSBaptiste Daroussin bool r = ucl_parser_add_string(parser, uclstr, 0); 85d9f0ce31SBaptiste Daroussin 8639ee7a7aSBaptiste Daroussin if (r) { 8739ee7a7aSBaptiste Daroussin if (ucl_parser_get_error (parser)) { 8839ee7a7aSBaptiste Daroussin PyErr_SetString(PyExc_ValueError, ucl_parser_get_error(parser)); 8939ee7a7aSBaptiste Daroussin ucl_parser_free(parser); 9039ee7a7aSBaptiste Daroussin ret = NULL; 9139ee7a7aSBaptiste Daroussin goto return_with_parser; 9239ee7a7aSBaptiste Daroussin } else { 9339ee7a7aSBaptiste Daroussin ucl_object_t *uclobj = ucl_parser_get_object(parser); 9439ee7a7aSBaptiste Daroussin ret = _iterate_valid_ucl(uclobj); 9539ee7a7aSBaptiste Daroussin ucl_object_unref(uclobj); 9639ee7a7aSBaptiste Daroussin goto return_with_parser; 9739ee7a7aSBaptiste Daroussin } 98d9f0ce31SBaptiste Daroussin } 99d9f0ce31SBaptiste Daroussin else { 10039ee7a7aSBaptiste Daroussin PyErr_SetString(PyExc_ValueError, ucl_parser_get_error (parser)); 10139ee7a7aSBaptiste Daroussin ret = NULL; 10239ee7a7aSBaptiste Daroussin goto return_with_parser; 10339ee7a7aSBaptiste Daroussin } 10439ee7a7aSBaptiste Daroussin 10539ee7a7aSBaptiste Daroussin return_with_parser: 10639ee7a7aSBaptiste Daroussin ucl_parser_free(parser); 10739ee7a7aSBaptiste Daroussin return ret; 10839ee7a7aSBaptiste Daroussin } 10939ee7a7aSBaptiste Daroussin 11039ee7a7aSBaptiste Daroussin static PyObject* 111d9f0ce31SBaptiste Daroussin ucl_load (PyObject *self, PyObject *args) 112d9f0ce31SBaptiste Daroussin { 11339ee7a7aSBaptiste Daroussin char *uclstr; 114d9f0ce31SBaptiste Daroussin 11539ee7a7aSBaptiste Daroussin if (PyArg_ParseTuple(args, "z", &uclstr)) { 11639ee7a7aSBaptiste Daroussin if (!uclstr) { 11739ee7a7aSBaptiste Daroussin Py_RETURN_NONE; 11839ee7a7aSBaptiste Daroussin } 119d9f0ce31SBaptiste Daroussin 12039ee7a7aSBaptiste Daroussin return _internal_load_ucl(uclstr); 12139ee7a7aSBaptiste Daroussin } 122d9f0ce31SBaptiste Daroussin 123d9f0ce31SBaptiste Daroussin return NULL; 124d9f0ce31SBaptiste Daroussin } 125d9f0ce31SBaptiste Daroussin 126d9f0ce31SBaptiste Daroussin static ucl_object_t * 127d9f0ce31SBaptiste Daroussin _iterate_python (PyObject *obj) 128d9f0ce31SBaptiste Daroussin { 129d9f0ce31SBaptiste Daroussin if (obj == Py_None) { 130d9f0ce31SBaptiste Daroussin return ucl_object_new(); 131d9f0ce31SBaptiste Daroussin } 132*273c26a3SBaptiste Daroussin else if (PyBool_Check (obj)) { 133*273c26a3SBaptiste Daroussin return ucl_object_frombool (obj == Py_True); 134*273c26a3SBaptiste Daroussin } 135*273c26a3SBaptiste Daroussin #if PY_MAJOR_VERSION < 3 136*273c26a3SBaptiste Daroussin else if (PyInt_Check (obj)) { 137*273c26a3SBaptiste Daroussin return ucl_object_fromint (PyInt_AsLong (obj)); 138*273c26a3SBaptiste Daroussin } 139*273c26a3SBaptiste Daroussin #endif 140*273c26a3SBaptiste Daroussin else if (PyLong_Check (obj)) { 141*273c26a3SBaptiste Daroussin return ucl_object_fromint (PyLong_AsLong (obj)); 142*273c26a3SBaptiste Daroussin } 143*273c26a3SBaptiste Daroussin else if (PyFloat_Check (obj)) { 144*273c26a3SBaptiste Daroussin return ucl_object_fromdouble (PyFloat_AsDouble (obj)); 145*273c26a3SBaptiste Daroussin } 146*273c26a3SBaptiste Daroussin else if (PyUnicode_Check (obj)) { 147*273c26a3SBaptiste Daroussin ucl_object_t *ucl_str; 148*273c26a3SBaptiste Daroussin PyObject *str = PyUnicode_AsASCIIString(obj); 149*273c26a3SBaptiste Daroussin ucl_str = ucl_object_fromstring (PyBytes_AsString (str)); 150*273c26a3SBaptiste Daroussin Py_DECREF(str); 151*273c26a3SBaptiste Daroussin return ucl_str; 152*273c26a3SBaptiste Daroussin } 153*273c26a3SBaptiste Daroussin #if PY_MAJOR_VERSION < 3 154*273c26a3SBaptiste Daroussin else if (PyString_Check (obj)) { 155*273c26a3SBaptiste Daroussin return ucl_object_fromstring (PyString_AsString (obj)); 156*273c26a3SBaptiste Daroussin } 157*273c26a3SBaptiste Daroussin #endif 158d9f0ce31SBaptiste Daroussin else if (PyDict_Check(obj)) { 159d9f0ce31SBaptiste Daroussin PyObject *key, *value; 160d9f0ce31SBaptiste Daroussin Py_ssize_t pos = 0; 161d9f0ce31SBaptiste Daroussin ucl_object_t *top, *elm; 162*273c26a3SBaptiste Daroussin char *keystr = NULL; 163d9f0ce31SBaptiste Daroussin 164d9f0ce31SBaptiste Daroussin top = ucl_object_typed_new (UCL_OBJECT); 165d9f0ce31SBaptiste Daroussin 166d9f0ce31SBaptiste Daroussin while (PyDict_Next(obj, &pos, &key, &value)) { 167d9f0ce31SBaptiste Daroussin elm = _iterate_python(value); 168*273c26a3SBaptiste Daroussin 169*273c26a3SBaptiste Daroussin if (PyUnicode_Check(key)) { 170*273c26a3SBaptiste Daroussin PyObject *keyascii = PyUnicode_AsASCIIString(key); 171*273c26a3SBaptiste Daroussin keystr = PyBytes_AsString(keyascii); 172*273c26a3SBaptiste Daroussin Py_DECREF(keyascii); 173*273c26a3SBaptiste Daroussin } 174*273c26a3SBaptiste Daroussin #if PY_MAJOR_VERSION < 3 175*273c26a3SBaptiste Daroussin else if (PyString_Check(key)) { 176*273c26a3SBaptiste Daroussin keystr = PyString_AsString(key); 177*273c26a3SBaptiste Daroussin } 178*273c26a3SBaptiste Daroussin #endif 179*273c26a3SBaptiste Daroussin else { 180*273c26a3SBaptiste Daroussin PyErr_SetString(PyExc_TypeError, "Unknown key type"); 181*273c26a3SBaptiste Daroussin return NULL; 182*273c26a3SBaptiste Daroussin } 183*273c26a3SBaptiste Daroussin 184*273c26a3SBaptiste Daroussin ucl_object_insert_key (top, elm, keystr, 0, true); 185d9f0ce31SBaptiste Daroussin } 186d9f0ce31SBaptiste Daroussin 187d9f0ce31SBaptiste Daroussin return top; 188d9f0ce31SBaptiste Daroussin } 189d9f0ce31SBaptiste Daroussin else if (PySequence_Check(obj)) { 190d9f0ce31SBaptiste Daroussin PyObject *value; 191d9f0ce31SBaptiste Daroussin Py_ssize_t len, pos; 192d9f0ce31SBaptiste Daroussin ucl_object_t *top, *elm; 193d9f0ce31SBaptiste Daroussin 194d9f0ce31SBaptiste Daroussin len = PySequence_Length(obj); 195d9f0ce31SBaptiste Daroussin top = ucl_object_typed_new (UCL_ARRAY); 196d9f0ce31SBaptiste Daroussin 197d9f0ce31SBaptiste Daroussin for (pos = 0; pos < len; pos++) { 198d9f0ce31SBaptiste Daroussin value = PySequence_GetItem(obj, pos); 199d9f0ce31SBaptiste Daroussin elm = _iterate_python(value); 200d9f0ce31SBaptiste Daroussin ucl_array_append(top, elm); 201d9f0ce31SBaptiste Daroussin } 202d9f0ce31SBaptiste Daroussin 203d9f0ce31SBaptiste Daroussin return top; 204d9f0ce31SBaptiste Daroussin } 205d9f0ce31SBaptiste Daroussin else { 206d9f0ce31SBaptiste Daroussin PyErr_SetString(PyExc_TypeError, "Unhandled object type"); 207d9f0ce31SBaptiste Daroussin return NULL; 208d9f0ce31SBaptiste Daroussin } 209d9f0ce31SBaptiste Daroussin 21039ee7a7aSBaptiste Daroussin return NULL; 21139ee7a7aSBaptiste Daroussin } 21239ee7a7aSBaptiste Daroussin 21339ee7a7aSBaptiste Daroussin static PyObject * 214d9f0ce31SBaptiste Daroussin ucl_dump (PyObject *self, PyObject *args) 215d9f0ce31SBaptiste Daroussin { 216d9f0ce31SBaptiste Daroussin PyObject *obj; 217d9f0ce31SBaptiste Daroussin ucl_emitter_t emitter; 218d9f0ce31SBaptiste Daroussin ucl_object_t *root = NULL; 219d9f0ce31SBaptiste Daroussin 220d9f0ce31SBaptiste Daroussin emitter = UCL_EMIT_CONFIG; 221d9f0ce31SBaptiste Daroussin 222d9f0ce31SBaptiste Daroussin if (!PyArg_ParseTuple(args, "O|i", &obj, &emitter)) { 223d9f0ce31SBaptiste Daroussin PyErr_SetString(PyExc_TypeError, "Unhandled object type"); 224d9f0ce31SBaptiste Daroussin return NULL; 225d9f0ce31SBaptiste Daroussin } 226d9f0ce31SBaptiste Daroussin 227d9f0ce31SBaptiste Daroussin if (emitter >= UCL_EMIT_MAX) { 228d9f0ce31SBaptiste Daroussin PyErr_SetString(PyExc_TypeError, "Invalid emitter type"); 229d9f0ce31SBaptiste Daroussin return NULL; 230d9f0ce31SBaptiste Daroussin } 231d9f0ce31SBaptiste Daroussin 232d9f0ce31SBaptiste Daroussin if (obj == Py_None) { 233d9f0ce31SBaptiste Daroussin Py_RETURN_NONE; 234d9f0ce31SBaptiste Daroussin } 235d9f0ce31SBaptiste Daroussin 236d9f0ce31SBaptiste Daroussin root = _iterate_python(obj); 237d9f0ce31SBaptiste Daroussin if (root) { 238d9f0ce31SBaptiste Daroussin PyObject *ret; 239d9f0ce31SBaptiste Daroussin char *buf; 240d9f0ce31SBaptiste Daroussin 241d9f0ce31SBaptiste Daroussin buf = (char *) ucl_object_emit (root, emitter); 242d9f0ce31SBaptiste Daroussin ucl_object_unref (root); 243*273c26a3SBaptiste Daroussin #if PY_MAJOR_VERSION < 3 244d9f0ce31SBaptiste Daroussin ret = PyString_FromString (buf); 245*273c26a3SBaptiste Daroussin #else 246*273c26a3SBaptiste Daroussin ret = PyUnicode_FromString (buf); 247*273c26a3SBaptiste Daroussin #endif 248d9f0ce31SBaptiste Daroussin free(buf); 249d9f0ce31SBaptiste Daroussin 250d9f0ce31SBaptiste Daroussin return ret; 251d9f0ce31SBaptiste Daroussin } 252d9f0ce31SBaptiste Daroussin 253d9f0ce31SBaptiste Daroussin return NULL; 254d9f0ce31SBaptiste Daroussin } 255d9f0ce31SBaptiste Daroussin 256d9f0ce31SBaptiste Daroussin static PyObject * 257d9f0ce31SBaptiste Daroussin ucl_validate (PyObject *self, PyObject *args) 258d9f0ce31SBaptiste Daroussin { 259*273c26a3SBaptiste Daroussin PyObject *dataobj, *schemaobj; 260*273c26a3SBaptiste Daroussin ucl_object_t *data, *schema; 261*273c26a3SBaptiste Daroussin bool r; 262*273c26a3SBaptiste Daroussin struct ucl_schema_error err; 263d9f0ce31SBaptiste Daroussin 264*273c26a3SBaptiste Daroussin if (!PyArg_ParseTuple (args, "OO", &schemaobj, &dataobj)) { 265*273c26a3SBaptiste Daroussin PyErr_SetString (PyExc_TypeError, "Unhandled object type"); 26639ee7a7aSBaptiste Daroussin return NULL; 26739ee7a7aSBaptiste Daroussin } 26839ee7a7aSBaptiste Daroussin 269*273c26a3SBaptiste Daroussin schema = _iterate_python(schemaobj); 270*273c26a3SBaptiste Daroussin if (!schema) 271*273c26a3SBaptiste Daroussin return NULL; 272*273c26a3SBaptiste Daroussin 273*273c26a3SBaptiste Daroussin data = _iterate_python(dataobj); 274*273c26a3SBaptiste Daroussin if (!data) 275*273c26a3SBaptiste Daroussin return NULL; 276*273c26a3SBaptiste Daroussin 277*273c26a3SBaptiste Daroussin // validation 278*273c26a3SBaptiste Daroussin r = ucl_object_validate (schema, data, &err); 279*273c26a3SBaptiste Daroussin ucl_object_unref (schema); 280*273c26a3SBaptiste Daroussin ucl_object_unref (data); 281*273c26a3SBaptiste Daroussin 282*273c26a3SBaptiste Daroussin if (!r) { 283*273c26a3SBaptiste Daroussin PyErr_SetString (SchemaError, err.msg); 284*273c26a3SBaptiste Daroussin return NULL; 285*273c26a3SBaptiste Daroussin } 286*273c26a3SBaptiste Daroussin 287*273c26a3SBaptiste Daroussin Py_RETURN_TRUE; 288*273c26a3SBaptiste Daroussin } 289*273c26a3SBaptiste Daroussin 29039ee7a7aSBaptiste Daroussin static PyMethodDef uclMethods[] = { 29139ee7a7aSBaptiste Daroussin {"load", ucl_load, METH_VARARGS, "Load UCL from stream"}, 292d9f0ce31SBaptiste Daroussin {"dump", ucl_dump, METH_VARARGS, "Dump UCL to stream"}, 29339ee7a7aSBaptiste Daroussin {"validate", ucl_validate, METH_VARARGS, "Validate ucl stream against schema"}, 29439ee7a7aSBaptiste Daroussin {NULL, NULL, 0, NULL} 29539ee7a7aSBaptiste Daroussin }; 29639ee7a7aSBaptiste Daroussin 297d9f0ce31SBaptiste Daroussin static void 298d9f0ce31SBaptiste Daroussin init_macros(PyObject *mod) 299d9f0ce31SBaptiste Daroussin { 300d9f0ce31SBaptiste Daroussin PyModule_AddIntMacro(mod, UCL_EMIT_JSON); 301d9f0ce31SBaptiste Daroussin PyModule_AddIntMacro(mod, UCL_EMIT_JSON_COMPACT); 302d9f0ce31SBaptiste Daroussin PyModule_AddIntMacro(mod, UCL_EMIT_CONFIG); 303d9f0ce31SBaptiste Daroussin PyModule_AddIntMacro(mod, UCL_EMIT_YAML); 304d9f0ce31SBaptiste Daroussin PyModule_AddIntMacro(mod, UCL_EMIT_MSGPACK); 305*273c26a3SBaptiste Daroussin 306*273c26a3SBaptiste Daroussin SchemaError = PyErr_NewException("ucl.SchemaError", NULL, NULL); 307*273c26a3SBaptiste Daroussin Py_INCREF(SchemaError); 308*273c26a3SBaptiste Daroussin PyModule_AddObject(mod, "SchemaError", SchemaError); 309d9f0ce31SBaptiste Daroussin } 310d9f0ce31SBaptiste Daroussin 31139ee7a7aSBaptiste Daroussin #if PY_MAJOR_VERSION >= 3 31239ee7a7aSBaptiste Daroussin static struct PyModuleDef uclmodule = { 31339ee7a7aSBaptiste Daroussin PyModuleDef_HEAD_INIT, 31439ee7a7aSBaptiste Daroussin "ucl", 31539ee7a7aSBaptiste Daroussin NULL, 31639ee7a7aSBaptiste Daroussin -1, 31739ee7a7aSBaptiste Daroussin uclMethods 31839ee7a7aSBaptiste Daroussin }; 31939ee7a7aSBaptiste Daroussin 32039ee7a7aSBaptiste Daroussin PyMODINIT_FUNC 321d9f0ce31SBaptiste Daroussin PyInit_ucl (void) 322d9f0ce31SBaptiste Daroussin { 323d9f0ce31SBaptiste Daroussin PyObject *mod = PyModule_Create (&uclmodule); 324d9f0ce31SBaptiste Daroussin init_macros (mod); 325d9f0ce31SBaptiste Daroussin 326d9f0ce31SBaptiste Daroussin return mod; 32739ee7a7aSBaptiste Daroussin } 32839ee7a7aSBaptiste Daroussin #else 329d9f0ce31SBaptiste Daroussin void initucl (void) 330d9f0ce31SBaptiste Daroussin { 331d9f0ce31SBaptiste Daroussin PyObject *mod = Py_InitModule ("ucl", uclMethods); 332d9f0ce31SBaptiste Daroussin init_macros (mod); 33339ee7a7aSBaptiste Daroussin } 33439ee7a7aSBaptiste Daroussin #endif 335