1 // Attempts to load a UCL structure from a string 2 #include <ucl.h> 3 #include <Python.h> 4 5 static PyObject * 6 _basic_ucl_type (ucl_object_t const *obj) 7 { 8 switch (obj->type) { 9 case UCL_INT: 10 return Py_BuildValue ("L", (long long)ucl_object_toint (obj)); 11 case UCL_FLOAT: 12 return Py_BuildValue ("d", ucl_object_todouble (obj)); 13 case UCL_STRING: 14 return Py_BuildValue ("s", ucl_object_tostring (obj)); 15 case UCL_BOOLEAN: 16 return ucl_object_toboolean (obj) ? Py_True : Py_False; 17 case UCL_TIME: 18 return Py_BuildValue ("d", ucl_object_todouble (obj)); 19 } 20 return NULL; 21 } 22 23 static PyObject * 24 _iterate_valid_ucl (ucl_object_t const *obj) 25 { 26 const ucl_object_t *tmp; 27 ucl_object_iter_t it = NULL; 28 29 tmp = obj; 30 31 while ((obj = ucl_object_iterate (tmp, &it, false))) { 32 PyObject *val; 33 34 val = _basic_ucl_type(obj); 35 if (!val) { 36 PyObject *key = NULL; 37 38 if (obj->key != NULL) { 39 key = Py_BuildValue("s", ucl_object_key(obj)); 40 } 41 42 if (obj->type == UCL_OBJECT) { 43 const ucl_object_t *cur; 44 ucl_object_iter_t it_obj = NULL; 45 46 val = PyDict_New(); 47 48 while ((cur = ucl_object_iterate (obj, &it_obj, true))) { 49 PyObject *keyobj = Py_BuildValue("s",ucl_object_key(cur)); 50 PyDict_SetItem(val, keyobj, _iterate_valid_ucl(cur)); 51 } 52 } else if (obj->type == UCL_ARRAY) { 53 const ucl_object_t *cur; 54 ucl_object_iter_t it_obj = NULL; 55 56 val = PyList_New(0); 57 58 while ((cur = ucl_object_iterate (obj, &it_obj, true))) { 59 PyList_Append(val, _iterate_valid_ucl(cur)); 60 } 61 } else if (obj->type == UCL_USERDATA) { 62 // XXX: this should be 63 // PyBytes_FromStringAndSize; where is the 64 // length from? 65 val = PyBytes_FromString(obj->value.ud); 66 } 67 } 68 return val; 69 } 70 71 PyErr_SetString(PyExc_SystemError, "unhandled type"); 72 return NULL; 73 } 74 75 static PyObject * 76 _internal_load_ucl (char *uclstr) 77 { 78 PyObject *ret; 79 struct ucl_parser *parser = ucl_parser_new (UCL_PARSER_NO_TIME); 80 bool r = ucl_parser_add_string(parser, uclstr, 0); 81 82 if (r) { 83 if (ucl_parser_get_error (parser)) { 84 PyErr_SetString(PyExc_ValueError, ucl_parser_get_error(parser)); 85 ucl_parser_free(parser); 86 ret = NULL; 87 goto return_with_parser; 88 } else { 89 ucl_object_t *uclobj = ucl_parser_get_object(parser); 90 ret = _iterate_valid_ucl(uclobj); 91 ucl_object_unref(uclobj); 92 goto return_with_parser; 93 } 94 } 95 else { 96 PyErr_SetString(PyExc_ValueError, ucl_parser_get_error (parser)); 97 ret = NULL; 98 goto return_with_parser; 99 } 100 101 return_with_parser: 102 ucl_parser_free(parser); 103 return ret; 104 } 105 106 static PyObject* 107 ucl_load (PyObject *self, PyObject *args) 108 { 109 char *uclstr; 110 111 if (PyArg_ParseTuple(args, "z", &uclstr)) { 112 if (!uclstr) { 113 Py_RETURN_NONE; 114 } 115 116 return _internal_load_ucl(uclstr); 117 } 118 119 return NULL; 120 } 121 122 static ucl_object_t * 123 _iterate_python (PyObject *obj) 124 { 125 if (obj == Py_None) { 126 return ucl_object_new(); 127 } else if (PyBool_Check (obj)) { 128 return ucl_object_frombool (obj == Py_True); 129 } else if (PyInt_Check (obj)) { 130 return ucl_object_fromint (PyInt_AsLong (obj)); 131 } else if (PyFloat_Check (obj)) { 132 return ucl_object_fromdouble (PyFloat_AsDouble (obj)); 133 } else if (PyString_Check (obj)) { 134 return ucl_object_fromstring (PyString_AsString (obj)); 135 // } else if (PyDateTime_Check (obj)) { 136 } 137 else if (PyDict_Check(obj)) { 138 PyObject *key, *value; 139 Py_ssize_t pos = 0; 140 ucl_object_t *top, *elm; 141 142 top = ucl_object_typed_new (UCL_OBJECT); 143 144 while (PyDict_Next(obj, &pos, &key, &value)) { 145 elm = _iterate_python(value); 146 ucl_object_insert_key (top, elm, PyString_AsString(key), 0, true); 147 } 148 149 return top; 150 } 151 else if (PySequence_Check(obj)) { 152 PyObject *value; 153 Py_ssize_t len, pos; 154 ucl_object_t *top, *elm; 155 156 len = PySequence_Length(obj); 157 top = ucl_object_typed_new (UCL_ARRAY); 158 159 for (pos = 0; pos < len; pos++) { 160 value = PySequence_GetItem(obj, pos); 161 elm = _iterate_python(value); 162 ucl_array_append(top, elm); 163 } 164 165 return top; 166 } 167 else { 168 PyErr_SetString(PyExc_TypeError, "Unhandled object type"); 169 return NULL; 170 } 171 172 return NULL; 173 } 174 175 static PyObject * 176 ucl_dump (PyObject *self, PyObject *args) 177 { 178 PyObject *obj; 179 ucl_emitter_t emitter; 180 ucl_object_t *root = NULL; 181 182 emitter = UCL_EMIT_CONFIG; 183 184 if (!PyArg_ParseTuple(args, "O|i", &obj, &emitter)) { 185 PyErr_SetString(PyExc_TypeError, "Unhandled object type"); 186 return NULL; 187 } 188 189 if (emitter >= UCL_EMIT_MAX) { 190 PyErr_SetString(PyExc_TypeError, "Invalid emitter type"); 191 return NULL; 192 } 193 194 if (obj == Py_None) { 195 Py_RETURN_NONE; 196 } 197 198 if (!PyDict_Check(obj)) { 199 PyErr_SetString(PyExc_TypeError, "Argument must be dict"); 200 return NULL; 201 } 202 203 root = _iterate_python(obj); 204 if (root) { 205 PyObject *ret; 206 char *buf; 207 208 buf = (char *) ucl_object_emit (root, emitter); 209 ucl_object_unref (root); 210 ret = PyString_FromString (buf); 211 free(buf); 212 213 return ret; 214 } 215 216 return NULL; 217 } 218 219 static PyObject * 220 ucl_validate (PyObject *self, PyObject *args) 221 { 222 char *uclstr, *schema; 223 224 if (PyArg_ParseTuple(args, "zz", &uclstr, &schema)) { 225 if (!uclstr || !schema) { 226 Py_RETURN_NONE; 227 } 228 229 PyErr_SetString(PyExc_NotImplementedError, "schema validation is not yet supported"); 230 } 231 232 return NULL; 233 } 234 235 static PyMethodDef uclMethods[] = { 236 {"load", ucl_load, METH_VARARGS, "Load UCL from stream"}, 237 {"dump", ucl_dump, METH_VARARGS, "Dump UCL to stream"}, 238 {"validate", ucl_validate, METH_VARARGS, "Validate ucl stream against schema"}, 239 {NULL, NULL, 0, NULL} 240 }; 241 242 static void 243 init_macros(PyObject *mod) 244 { 245 PyModule_AddIntMacro(mod, UCL_EMIT_JSON); 246 PyModule_AddIntMacro(mod, UCL_EMIT_JSON_COMPACT); 247 PyModule_AddIntMacro(mod, UCL_EMIT_CONFIG); 248 PyModule_AddIntMacro(mod, UCL_EMIT_YAML); 249 PyModule_AddIntMacro(mod, UCL_EMIT_MSGPACK); 250 } 251 252 #if PY_MAJOR_VERSION >= 3 253 static struct PyModuleDef uclmodule = { 254 PyModuleDef_HEAD_INIT, 255 "ucl", 256 NULL, 257 -1, 258 uclMethods 259 }; 260 261 PyMODINIT_FUNC 262 PyInit_ucl (void) 263 { 264 PyObject *mod = PyModule_Create (&uclmodule); 265 init_macros (mod); 266 267 return mod; 268 } 269 #else 270 void initucl (void) 271 { 272 PyObject *mod = Py_InitModule ("ucl", uclMethods); 273 init_macros (mod); 274 } 275 #endif 276