]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libucl/python/src/uclmodule.c
ssh: Update to OpenSSH 9.4p1
[FreeBSD/FreeBSD.git] / contrib / libucl / python / src / uclmodule.c
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