xref: /freebsd-src/contrib/libucl/python/src/uclmodule.c (revision d9f0ce31900a48d1a2bfc1c8c86f79d1e831451a)
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