139ee7a7aSBaptiste Daroussin // Attempts to load a UCL structure from a string 239ee7a7aSBaptiste Daroussin #include <ucl.h> 339ee7a7aSBaptiste Daroussin #include <Python.h> 439ee7a7aSBaptiste Daroussin 539ee7a7aSBaptiste Daroussin static PyObject * 6*d9f0ce31SBaptiste Daroussin _basic_ucl_type (ucl_object_t const *obj) 7*d9f0ce31SBaptiste Daroussin { 8*d9f0ce31SBaptiste Daroussin switch (obj->type) { 9*d9f0ce31SBaptiste Daroussin case UCL_INT: 1039ee7a7aSBaptiste Daroussin return Py_BuildValue ("L", (long long)ucl_object_toint (obj)); 11*d9f0ce31SBaptiste Daroussin case UCL_FLOAT: 1239ee7a7aSBaptiste Daroussin return Py_BuildValue ("d", ucl_object_todouble (obj)); 13*d9f0ce31SBaptiste Daroussin case UCL_STRING: 1439ee7a7aSBaptiste Daroussin return Py_BuildValue ("s", ucl_object_tostring (obj)); 15*d9f0ce31SBaptiste Daroussin case UCL_BOOLEAN: 16*d9f0ce31SBaptiste Daroussin return ucl_object_toboolean (obj) ? Py_True : Py_False; 17*d9f0ce31SBaptiste Daroussin case UCL_TIME: 1839ee7a7aSBaptiste Daroussin return Py_BuildValue ("d", ucl_object_todouble (obj)); 1939ee7a7aSBaptiste Daroussin } 2039ee7a7aSBaptiste Daroussin return NULL; 2139ee7a7aSBaptiste Daroussin } 2239ee7a7aSBaptiste Daroussin 2339ee7a7aSBaptiste Daroussin static PyObject * 24*d9f0ce31SBaptiste Daroussin _iterate_valid_ucl (ucl_object_t const *obj) 25*d9f0ce31SBaptiste Daroussin { 2639ee7a7aSBaptiste Daroussin const ucl_object_t *tmp; 2739ee7a7aSBaptiste Daroussin ucl_object_iter_t it = NULL; 2839ee7a7aSBaptiste Daroussin 2939ee7a7aSBaptiste Daroussin tmp = obj; 3039ee7a7aSBaptiste Daroussin 31*d9f0ce31SBaptiste Daroussin while ((obj = ucl_object_iterate (tmp, &it, false))) { 3239ee7a7aSBaptiste Daroussin PyObject *val; 3339ee7a7aSBaptiste Daroussin 3439ee7a7aSBaptiste Daroussin val = _basic_ucl_type(obj); 3539ee7a7aSBaptiste Daroussin if (!val) { 3639ee7a7aSBaptiste Daroussin PyObject *key = NULL; 37*d9f0ce31SBaptiste Daroussin 3839ee7a7aSBaptiste Daroussin if (obj->key != NULL) { 3939ee7a7aSBaptiste Daroussin key = Py_BuildValue("s", ucl_object_key(obj)); 4039ee7a7aSBaptiste Daroussin } 4139ee7a7aSBaptiste Daroussin 4239ee7a7aSBaptiste Daroussin if (obj->type == UCL_OBJECT) { 4339ee7a7aSBaptiste Daroussin const ucl_object_t *cur; 4439ee7a7aSBaptiste Daroussin ucl_object_iter_t it_obj = NULL; 45*d9f0ce31SBaptiste Daroussin 46*d9f0ce31SBaptiste Daroussin val = PyDict_New(); 47*d9f0ce31SBaptiste Daroussin 48*d9f0ce31SBaptiste Daroussin while ((cur = ucl_object_iterate (obj, &it_obj, true))) { 4939ee7a7aSBaptiste Daroussin PyObject *keyobj = Py_BuildValue("s",ucl_object_key(cur)); 5039ee7a7aSBaptiste Daroussin PyDict_SetItem(val, keyobj, _iterate_valid_ucl(cur)); 5139ee7a7aSBaptiste Daroussin } 52*d9f0ce31SBaptiste Daroussin } else if (obj->type == UCL_ARRAY) { 5339ee7a7aSBaptiste Daroussin const ucl_object_t *cur; 5439ee7a7aSBaptiste Daroussin ucl_object_iter_t it_obj = NULL; 55*d9f0ce31SBaptiste Daroussin 56*d9f0ce31SBaptiste Daroussin val = PyList_New(0); 57*d9f0ce31SBaptiste Daroussin 58*d9f0ce31SBaptiste Daroussin while ((cur = ucl_object_iterate (obj, &it_obj, true))) { 5939ee7a7aSBaptiste Daroussin PyList_Append(val, _iterate_valid_ucl(cur)); 6039ee7a7aSBaptiste Daroussin } 61*d9f0ce31SBaptiste Daroussin } else if (obj->type == UCL_USERDATA) { 6239ee7a7aSBaptiste Daroussin // XXX: this should be 6339ee7a7aSBaptiste Daroussin // PyBytes_FromStringAndSize; where is the 6439ee7a7aSBaptiste Daroussin // length from? 6539ee7a7aSBaptiste Daroussin val = PyBytes_FromString(obj->value.ud); 6639ee7a7aSBaptiste Daroussin } 6739ee7a7aSBaptiste Daroussin } 6839ee7a7aSBaptiste Daroussin return val; 6939ee7a7aSBaptiste Daroussin } 7039ee7a7aSBaptiste Daroussin 7139ee7a7aSBaptiste Daroussin PyErr_SetString(PyExc_SystemError, "unhandled type"); 7239ee7a7aSBaptiste Daroussin return NULL; 7339ee7a7aSBaptiste Daroussin } 7439ee7a7aSBaptiste Daroussin 7539ee7a7aSBaptiste Daroussin static PyObject * 76*d9f0ce31SBaptiste Daroussin _internal_load_ucl (char *uclstr) 77*d9f0ce31SBaptiste Daroussin { 7839ee7a7aSBaptiste Daroussin PyObject *ret; 7939ee7a7aSBaptiste Daroussin struct ucl_parser *parser = ucl_parser_new (UCL_PARSER_NO_TIME); 8039ee7a7aSBaptiste Daroussin bool r = ucl_parser_add_string(parser, uclstr, 0); 81*d9f0ce31SBaptiste Daroussin 8239ee7a7aSBaptiste Daroussin if (r) { 8339ee7a7aSBaptiste Daroussin if (ucl_parser_get_error (parser)) { 8439ee7a7aSBaptiste Daroussin PyErr_SetString(PyExc_ValueError, ucl_parser_get_error(parser)); 8539ee7a7aSBaptiste Daroussin ucl_parser_free(parser); 8639ee7a7aSBaptiste Daroussin ret = NULL; 8739ee7a7aSBaptiste Daroussin goto return_with_parser; 8839ee7a7aSBaptiste Daroussin } else { 8939ee7a7aSBaptiste Daroussin ucl_object_t *uclobj = ucl_parser_get_object(parser); 9039ee7a7aSBaptiste Daroussin ret = _iterate_valid_ucl(uclobj); 9139ee7a7aSBaptiste Daroussin ucl_object_unref(uclobj); 9239ee7a7aSBaptiste Daroussin goto return_with_parser; 9339ee7a7aSBaptiste Daroussin } 94*d9f0ce31SBaptiste Daroussin } 95*d9f0ce31SBaptiste Daroussin else { 9639ee7a7aSBaptiste Daroussin PyErr_SetString(PyExc_ValueError, ucl_parser_get_error (parser)); 9739ee7a7aSBaptiste Daroussin ret = NULL; 9839ee7a7aSBaptiste Daroussin goto return_with_parser; 9939ee7a7aSBaptiste Daroussin } 10039ee7a7aSBaptiste Daroussin 10139ee7a7aSBaptiste Daroussin return_with_parser: 10239ee7a7aSBaptiste Daroussin ucl_parser_free(parser); 10339ee7a7aSBaptiste Daroussin return ret; 10439ee7a7aSBaptiste Daroussin } 10539ee7a7aSBaptiste Daroussin 10639ee7a7aSBaptiste Daroussin static PyObject* 107*d9f0ce31SBaptiste Daroussin ucl_load (PyObject *self, PyObject *args) 108*d9f0ce31SBaptiste Daroussin { 10939ee7a7aSBaptiste Daroussin char *uclstr; 110*d9f0ce31SBaptiste Daroussin 11139ee7a7aSBaptiste Daroussin if (PyArg_ParseTuple(args, "z", &uclstr)) { 11239ee7a7aSBaptiste Daroussin if (!uclstr) { 11339ee7a7aSBaptiste Daroussin Py_RETURN_NONE; 11439ee7a7aSBaptiste Daroussin } 115*d9f0ce31SBaptiste Daroussin 11639ee7a7aSBaptiste Daroussin return _internal_load_ucl(uclstr); 11739ee7a7aSBaptiste Daroussin } 118*d9f0ce31SBaptiste Daroussin 119*d9f0ce31SBaptiste Daroussin return NULL; 120*d9f0ce31SBaptiste Daroussin } 121*d9f0ce31SBaptiste Daroussin 122*d9f0ce31SBaptiste Daroussin static ucl_object_t * 123*d9f0ce31SBaptiste Daroussin _iterate_python (PyObject *obj) 124*d9f0ce31SBaptiste Daroussin { 125*d9f0ce31SBaptiste Daroussin if (obj == Py_None) { 126*d9f0ce31SBaptiste Daroussin return ucl_object_new(); 127*d9f0ce31SBaptiste Daroussin } else if (PyBool_Check (obj)) { 128*d9f0ce31SBaptiste Daroussin return ucl_object_frombool (obj == Py_True); 129*d9f0ce31SBaptiste Daroussin } else if (PyInt_Check (obj)) { 130*d9f0ce31SBaptiste Daroussin return ucl_object_fromint (PyInt_AsLong (obj)); 131*d9f0ce31SBaptiste Daroussin } else if (PyFloat_Check (obj)) { 132*d9f0ce31SBaptiste Daroussin return ucl_object_fromdouble (PyFloat_AsDouble (obj)); 133*d9f0ce31SBaptiste Daroussin } else if (PyString_Check (obj)) { 134*d9f0ce31SBaptiste Daroussin return ucl_object_fromstring (PyString_AsString (obj)); 135*d9f0ce31SBaptiste Daroussin // } else if (PyDateTime_Check (obj)) { 136*d9f0ce31SBaptiste Daroussin } 137*d9f0ce31SBaptiste Daroussin else if (PyDict_Check(obj)) { 138*d9f0ce31SBaptiste Daroussin PyObject *key, *value; 139*d9f0ce31SBaptiste Daroussin Py_ssize_t pos = 0; 140*d9f0ce31SBaptiste Daroussin ucl_object_t *top, *elm; 141*d9f0ce31SBaptiste Daroussin 142*d9f0ce31SBaptiste Daroussin top = ucl_object_typed_new (UCL_OBJECT); 143*d9f0ce31SBaptiste Daroussin 144*d9f0ce31SBaptiste Daroussin while (PyDict_Next(obj, &pos, &key, &value)) { 145*d9f0ce31SBaptiste Daroussin elm = _iterate_python(value); 146*d9f0ce31SBaptiste Daroussin ucl_object_insert_key (top, elm, PyString_AsString(key), 0, true); 147*d9f0ce31SBaptiste Daroussin } 148*d9f0ce31SBaptiste Daroussin 149*d9f0ce31SBaptiste Daroussin return top; 150*d9f0ce31SBaptiste Daroussin } 151*d9f0ce31SBaptiste Daroussin else if (PySequence_Check(obj)) { 152*d9f0ce31SBaptiste Daroussin PyObject *value; 153*d9f0ce31SBaptiste Daroussin Py_ssize_t len, pos; 154*d9f0ce31SBaptiste Daroussin ucl_object_t *top, *elm; 155*d9f0ce31SBaptiste Daroussin 156*d9f0ce31SBaptiste Daroussin len = PySequence_Length(obj); 157*d9f0ce31SBaptiste Daroussin top = ucl_object_typed_new (UCL_ARRAY); 158*d9f0ce31SBaptiste Daroussin 159*d9f0ce31SBaptiste Daroussin for (pos = 0; pos < len; pos++) { 160*d9f0ce31SBaptiste Daroussin value = PySequence_GetItem(obj, pos); 161*d9f0ce31SBaptiste Daroussin elm = _iterate_python(value); 162*d9f0ce31SBaptiste Daroussin ucl_array_append(top, elm); 163*d9f0ce31SBaptiste Daroussin } 164*d9f0ce31SBaptiste Daroussin 165*d9f0ce31SBaptiste Daroussin return top; 166*d9f0ce31SBaptiste Daroussin } 167*d9f0ce31SBaptiste Daroussin else { 168*d9f0ce31SBaptiste Daroussin PyErr_SetString(PyExc_TypeError, "Unhandled object type"); 169*d9f0ce31SBaptiste Daroussin return NULL; 170*d9f0ce31SBaptiste Daroussin } 171*d9f0ce31SBaptiste Daroussin 17239ee7a7aSBaptiste Daroussin return NULL; 17339ee7a7aSBaptiste Daroussin } 17439ee7a7aSBaptiste Daroussin 17539ee7a7aSBaptiste Daroussin static PyObject * 176*d9f0ce31SBaptiste Daroussin ucl_dump (PyObject *self, PyObject *args) 177*d9f0ce31SBaptiste Daroussin { 178*d9f0ce31SBaptiste Daroussin PyObject *obj; 179*d9f0ce31SBaptiste Daroussin ucl_emitter_t emitter; 180*d9f0ce31SBaptiste Daroussin ucl_object_t *root = NULL; 181*d9f0ce31SBaptiste Daroussin 182*d9f0ce31SBaptiste Daroussin emitter = UCL_EMIT_CONFIG; 183*d9f0ce31SBaptiste Daroussin 184*d9f0ce31SBaptiste Daroussin if (!PyArg_ParseTuple(args, "O|i", &obj, &emitter)) { 185*d9f0ce31SBaptiste Daroussin PyErr_SetString(PyExc_TypeError, "Unhandled object type"); 186*d9f0ce31SBaptiste Daroussin return NULL; 187*d9f0ce31SBaptiste Daroussin } 188*d9f0ce31SBaptiste Daroussin 189*d9f0ce31SBaptiste Daroussin if (emitter >= UCL_EMIT_MAX) { 190*d9f0ce31SBaptiste Daroussin PyErr_SetString(PyExc_TypeError, "Invalid emitter type"); 191*d9f0ce31SBaptiste Daroussin return NULL; 192*d9f0ce31SBaptiste Daroussin } 193*d9f0ce31SBaptiste Daroussin 194*d9f0ce31SBaptiste Daroussin if (obj == Py_None) { 195*d9f0ce31SBaptiste Daroussin Py_RETURN_NONE; 196*d9f0ce31SBaptiste Daroussin } 197*d9f0ce31SBaptiste Daroussin 198*d9f0ce31SBaptiste Daroussin if (!PyDict_Check(obj)) { 199*d9f0ce31SBaptiste Daroussin PyErr_SetString(PyExc_TypeError, "Argument must be dict"); 200*d9f0ce31SBaptiste Daroussin return NULL; 201*d9f0ce31SBaptiste Daroussin } 202*d9f0ce31SBaptiste Daroussin 203*d9f0ce31SBaptiste Daroussin root = _iterate_python(obj); 204*d9f0ce31SBaptiste Daroussin if (root) { 205*d9f0ce31SBaptiste Daroussin PyObject *ret; 206*d9f0ce31SBaptiste Daroussin char *buf; 207*d9f0ce31SBaptiste Daroussin 208*d9f0ce31SBaptiste Daroussin buf = (char *) ucl_object_emit (root, emitter); 209*d9f0ce31SBaptiste Daroussin ucl_object_unref (root); 210*d9f0ce31SBaptiste Daroussin ret = PyString_FromString (buf); 211*d9f0ce31SBaptiste Daroussin free(buf); 212*d9f0ce31SBaptiste Daroussin 213*d9f0ce31SBaptiste Daroussin return ret; 214*d9f0ce31SBaptiste Daroussin } 215*d9f0ce31SBaptiste Daroussin 216*d9f0ce31SBaptiste Daroussin return NULL; 217*d9f0ce31SBaptiste Daroussin } 218*d9f0ce31SBaptiste Daroussin 219*d9f0ce31SBaptiste Daroussin static PyObject * 220*d9f0ce31SBaptiste Daroussin ucl_validate (PyObject *self, PyObject *args) 221*d9f0ce31SBaptiste Daroussin { 22239ee7a7aSBaptiste Daroussin char *uclstr, *schema; 223*d9f0ce31SBaptiste Daroussin 22439ee7a7aSBaptiste Daroussin if (PyArg_ParseTuple(args, "zz", &uclstr, &schema)) { 22539ee7a7aSBaptiste Daroussin if (!uclstr || !schema) { 22639ee7a7aSBaptiste Daroussin Py_RETURN_NONE; 22739ee7a7aSBaptiste Daroussin } 228*d9f0ce31SBaptiste Daroussin 22939ee7a7aSBaptiste Daroussin PyErr_SetString(PyExc_NotImplementedError, "schema validation is not yet supported"); 23039ee7a7aSBaptiste Daroussin } 231*d9f0ce31SBaptiste Daroussin 23239ee7a7aSBaptiste Daroussin return NULL; 23339ee7a7aSBaptiste Daroussin } 23439ee7a7aSBaptiste Daroussin 23539ee7a7aSBaptiste Daroussin static PyMethodDef uclMethods[] = { 23639ee7a7aSBaptiste Daroussin {"load", ucl_load, METH_VARARGS, "Load UCL from stream"}, 237*d9f0ce31SBaptiste Daroussin {"dump", ucl_dump, METH_VARARGS, "Dump UCL to stream"}, 23839ee7a7aSBaptiste Daroussin {"validate", ucl_validate, METH_VARARGS, "Validate ucl stream against schema"}, 23939ee7a7aSBaptiste Daroussin {NULL, NULL, 0, NULL} 24039ee7a7aSBaptiste Daroussin }; 24139ee7a7aSBaptiste Daroussin 242*d9f0ce31SBaptiste Daroussin static void 243*d9f0ce31SBaptiste Daroussin init_macros(PyObject *mod) 244*d9f0ce31SBaptiste Daroussin { 245*d9f0ce31SBaptiste Daroussin PyModule_AddIntMacro(mod, UCL_EMIT_JSON); 246*d9f0ce31SBaptiste Daroussin PyModule_AddIntMacro(mod, UCL_EMIT_JSON_COMPACT); 247*d9f0ce31SBaptiste Daroussin PyModule_AddIntMacro(mod, UCL_EMIT_CONFIG); 248*d9f0ce31SBaptiste Daroussin PyModule_AddIntMacro(mod, UCL_EMIT_YAML); 249*d9f0ce31SBaptiste Daroussin PyModule_AddIntMacro(mod, UCL_EMIT_MSGPACK); 250*d9f0ce31SBaptiste Daroussin } 251*d9f0ce31SBaptiste Daroussin 25239ee7a7aSBaptiste Daroussin #if PY_MAJOR_VERSION >= 3 25339ee7a7aSBaptiste Daroussin static struct PyModuleDef uclmodule = { 25439ee7a7aSBaptiste Daroussin PyModuleDef_HEAD_INIT, 25539ee7a7aSBaptiste Daroussin "ucl", 25639ee7a7aSBaptiste Daroussin NULL, 25739ee7a7aSBaptiste Daroussin -1, 25839ee7a7aSBaptiste Daroussin uclMethods 25939ee7a7aSBaptiste Daroussin }; 26039ee7a7aSBaptiste Daroussin 26139ee7a7aSBaptiste Daroussin PyMODINIT_FUNC 262*d9f0ce31SBaptiste Daroussin PyInit_ucl (void) 263*d9f0ce31SBaptiste Daroussin { 264*d9f0ce31SBaptiste Daroussin PyObject *mod = PyModule_Create (&uclmodule); 265*d9f0ce31SBaptiste Daroussin init_macros (mod); 266*d9f0ce31SBaptiste Daroussin 267*d9f0ce31SBaptiste Daroussin return mod; 26839ee7a7aSBaptiste Daroussin } 26939ee7a7aSBaptiste Daroussin #else 270*d9f0ce31SBaptiste Daroussin void initucl (void) 271*d9f0ce31SBaptiste Daroussin { 272*d9f0ce31SBaptiste Daroussin PyObject *mod = Py_InitModule ("ucl", uclMethods); 273*d9f0ce31SBaptiste Daroussin init_macros (mod); 27439ee7a7aSBaptiste Daroussin } 27539ee7a7aSBaptiste Daroussin #endif 276