xref: /freebsd/contrib/libucl/python/src/uclmodule.c (revision 11b249f99e4d4891bd2a21ef796d40073ee15508)
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 * const obj) {
7 	if (obj->type == UCL_INT) {
8 		return Py_BuildValue("L", (long long)ucl_object_toint (obj));
9 	}
10 	else if (obj->type == UCL_FLOAT) {
11 		return Py_BuildValue("d", ucl_object_todouble (obj));
12 	}
13 	else if (obj->type == UCL_STRING) {
14 		return Py_BuildValue("s", ucl_object_tostring (obj));
15 	}
16 	else if (obj->type == UCL_BOOLEAN) {
17 		// maybe used 'p' here?
18 		return Py_BuildValue("s", ucl_object_tostring_forced (obj));
19 	}
20 	else if (obj->type == UCL_TIME) {
21 		return Py_BuildValue("d", ucl_object_todouble (obj));
22 	}
23 	return NULL;
24 }
25 
26 static PyObject*
27 _iterate_valid_ucl(ucl_object_t const * obj) {
28 	const ucl_object_t *tmp;
29 	ucl_object_iter_t it = NULL;
30 
31 	tmp = obj;
32 
33 	while ((obj = ucl_iterate_object (tmp, &it, false))) {
34 
35 		PyObject* val;
36 
37 		val = _basic_ucl_type(obj);
38 		if (!val) {
39 			PyObject* key = NULL;
40 			if (obj->key != NULL) {
41 				key = Py_BuildValue("s", ucl_object_key(obj));
42 			}
43 
44 			PyObject* ret;
45 			ret = PyDict_New();
46 			if (obj->type == UCL_OBJECT) {
47 				val = PyDict_New();
48 				const ucl_object_t *cur;
49 				ucl_object_iter_t it_obj = NULL;
50 				while ((cur = ucl_iterate_object (obj, &it_obj, true))) {
51 					PyObject* keyobj = Py_BuildValue("s",ucl_object_key(cur));
52 					PyDict_SetItem(val, keyobj, _iterate_valid_ucl(cur));
53 				}
54 			}
55 			else if (obj->type == UCL_ARRAY) {
56 				val = PyList_New(0);
57 				const ucl_object_t *cur;
58 				ucl_object_iter_t it_obj = NULL;
59 				while ((cur = ucl_iterate_object (obj, &it_obj, true))) {
60 					PyList_Append(val, _iterate_valid_ucl(cur));
61 				}
62 			}
63 			else if (obj->type == UCL_USERDATA) {
64 				// XXX: this should be
65 				// PyBytes_FromStringAndSize; where is the
66 				// length from?
67 				val = PyBytes_FromString(obj->value.ud);
68 			}
69 		}
70 		return val;
71 	}
72 
73 	PyErr_SetString(PyExc_SystemError, "unhandled type");
74 	return NULL;
75 }
76 
77 static PyObject*
78 _internal_load_ucl(char* uclstr) {
79 	PyObject* ret;
80 
81 	struct ucl_parser *parser = ucl_parser_new (UCL_PARSER_NO_TIME);
82 
83 	bool r = ucl_parser_add_string(parser, uclstr, 0);
84 	if (r) {
85 		if (ucl_parser_get_error (parser)) {
86 			PyErr_SetString(PyExc_ValueError, ucl_parser_get_error(parser));
87 			ucl_parser_free(parser);
88 			ret = NULL;
89 			goto return_with_parser;
90 		} else {
91 			ucl_object_t* uclobj = ucl_parser_get_object(parser);
92 			ret = _iterate_valid_ucl(uclobj);
93 			ucl_object_unref(uclobj);
94 			goto return_with_parser;
95 		}
96 
97 	} else {
98 		PyErr_SetString(PyExc_ValueError, ucl_parser_get_error (parser));
99 		ret = NULL;
100 		goto return_with_parser;
101 	}
102 
103 return_with_parser:
104 	ucl_parser_free(parser);
105 	return ret;
106 }
107 
108 static PyObject*
109 ucl_load(PyObject *self, PyObject *args) {
110 	char* uclstr;
111 	if (PyArg_ParseTuple(args, "z", &uclstr)) {
112 		if (!uclstr) {
113 			Py_RETURN_NONE;
114 		}
115 		return _internal_load_ucl(uclstr);
116 	}
117 	return NULL;
118 }
119 
120 static PyObject*
121 ucl_validate(PyObject *self, PyObject *args) {
122 	char  *uclstr, *schema;
123 	if (PyArg_ParseTuple(args, "zz", &uclstr, &schema)) {
124 		if (!uclstr || !schema) {
125 			Py_RETURN_NONE;
126 		}
127 		PyErr_SetString(PyExc_NotImplementedError, "schema validation is not yet supported");
128 		return NULL;
129 	}
130 	return NULL;
131 }
132 
133 static PyMethodDef uclMethods[] = {
134 	{"load", ucl_load, METH_VARARGS, "Load UCL from stream"},
135 	{"validate", ucl_validate, METH_VARARGS, "Validate ucl stream against schema"},
136 	{NULL, NULL, 0, NULL}
137 };
138 
139 #if PY_MAJOR_VERSION >= 3
140 static struct PyModuleDef uclmodule = {
141 	PyModuleDef_HEAD_INIT,
142 	"ucl",
143 	NULL,
144 	-1,
145 	uclMethods
146 };
147 
148 PyMODINIT_FUNC
149 PyInit_ucl(void) {
150 	return PyModule_Create(&uclmodule);
151 }
152 #else
153 void initucl(void) {
154 	Py_InitModule("ucl", uclMethods);
155 }
156 #endif
157