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