File: | rrdtoolmodule.c |
Warning: | line 459, column 9 Calling function 'PyTuple_SetItem' with a PyObject argument whose ownership has been released (with stolen reference) |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * python-rrdtool, Python bindings for rrdtool. | |||
3 | * Based on the rrdtool Python bindings for Python 2 from | |||
4 | * Hye-Shik Chang <perky@fallin.lv>. | |||
5 | * | |||
6 | * Copyright 2012 Christian Kroeger <commx@commx.ws> | |||
7 | * | |||
8 | * This program is free software; you can redistribute it and/or modify | |||
9 | * it under the terms of the GNU Lesser General Public License as | |||
10 | * published by the Free Software Foundation; either version 2.1 of the | |||
11 | * License, or (at your option) any later version. | |||
12 | * | |||
13 | * This program is distributed in the hope that it will be useful, | |||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
16 | * GNU General Public License for more details. | |||
17 | * | |||
18 | * You should have received a copy of the GNU Lesser General Public License | |||
19 | * along with this program; if not, write to the Free Software | |||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | |||
21 | * MA 02110-1301, USA. | |||
22 | * | |||
23 | */ | |||
24 | ||||
25 | #include <Python.h> | |||
26 | #include <datetime.h> | |||
27 | #include "rrdtoolmodule.h" | |||
28 | ||||
29 | /* Some macros to maintain compatibility between Python 2.x and 3.x */ | |||
30 | #if PY_MAJOR_VERSION3 >= 3 | |||
31 | #define HAVE_PY3K | |||
32 | #define PyRRD_String_Check(x)((((((PyObject*)(x))->ob_type))->tp_flags & ((1UL << 28))) != 0) PyUnicode_Check(x)((((((PyObject*)(x))->ob_type))->tp_flags & ((1UL << 28))) != 0) | |||
33 | #define PyRRD_String_FromString(x)PyUnicode_FromString(x) PyUnicode_FromString(x) | |||
34 | #define PyRRD_String_AS_STRING(x)PyUnicode_AsUTF8(x) PyUnicode_AsUTF8(x) | |||
35 | #define PyRRD_String_FromStringAndSize(x, y)PyBytes_FromStringAndSize(x, y) PyBytes_FromStringAndSize(x, y) | |||
36 | #define PyRRD_String_Size(x)PyUnicode_Size(x) PyUnicode_Size(x) | |||
37 | #define PyRRD_Int_FromLong(x)PyLong_FromLong(x) PyLong_FromLong(x) | |||
38 | #define PyRRD_Int_FromString(x, y, z)PyLong_FromString(x,y,z) PyLong_FromString(x,y,z) | |||
39 | #define PyRRD_Long_Check(x)((((((PyObject*)(x))->ob_type))->tp_flags & ((1UL << 24))) != 0) PyLong_Check(x)((((((PyObject*)(x))->ob_type))->tp_flags & ((1UL << 24))) != 0) | |||
40 | #else | |||
41 | #define PyRRD_String_Check(x)((((((PyObject*)(x))->ob_type))->tp_flags & ((1UL << 28))) != 0) PyString_Check(x) | |||
42 | #define PyRRD_String_FromString(x)PyUnicode_FromString(x) PyString_FromString(x) | |||
43 | #define PyRRD_String_AS_STRING(x)PyUnicode_AsUTF8(x) PyString_AS_STRING(x) | |||
44 | #define PyRRD_String_FromStringAndSize(x, y)PyBytes_FromStringAndSize(x, y) PyString_FromStringAndSize(x, y) | |||
45 | #define PyRRD_String_Size(x)PyUnicode_Size(x) PyString_Size(x) | |||
46 | #define PyRRD_Int_FromLong(x)PyLong_FromLong(x) PyInt_FromLong(x) | |||
47 | #define PyRRD_Int_FromString(x, y, z)PyLong_FromString(x,y,z) PyInt_FromString(x,y,z) | |||
48 | #define PyRRD_Long_Check(x)((((((PyObject*)(x))->ob_type))->tp_flags & ((1UL << 24))) != 0) (PyInt_Check(x) || PyLong_Check(x)((((((PyObject*)(x))->ob_type))->tp_flags & ((1UL << 24))) != 0)) | |||
49 | #endif | |||
50 | ||||
51 | #ifndef Py_UNUSED | |||
52 | #ifdef __GNUC__4 | |||
53 | #define Py_UNUSED(name)_unused_name __attribute__((unused)) _unused_ ## name __attribute__((unused)) | |||
54 | #else | |||
55 | #define Py_UNUSED(name)_unused_name __attribute__((unused)) _unused_ ## -name | |||
56 | #endif | |||
57 | #endif | |||
58 | ||||
59 | #ifndef DS_NAM_SIZE20 | |||
60 | #define DS_NAM_SIZE20 20 | |||
61 | #endif | |||
62 | ||||
63 | /** Binding version. */ | |||
64 | static const char *_version = PACKAGE_VERSION"0.1.15"; | |||
65 | ||||
66 | /** Exception types. */ | |||
67 | static PyObject *rrdtool_OperationalError; | |||
68 | static PyObject *rrdtool_ProgrammingError; | |||
69 | ||||
70 | /** | |||
71 | * PyRRD_DateTime_FromTS: convert UNIX timestamp (time_t) | |||
72 | * to Python datetime object. | |||
73 | * | |||
74 | * @param ts UNIX timestamp (time_t) | |||
75 | * @return Pointer to new PyObject (New Reference) | |||
76 | */ | |||
77 | static PyObject * | |||
78 | PyRRD_DateTime_FromTS(time_t ts) | |||
79 | { | |||
80 | PyObject *ret; | |||
81 | struct tm lt; | |||
82 | ||||
83 | localtime_r(&ts, <); | |||
84 | ||||
85 | ret = PyDateTime_FromDateAndTime(PyDateTimeAPI->DateTime_FromDateAndTime(lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday, lt.tm_hour, lt.tm_min, lt.tm_sec, 0, (&_Py_NoneStruct), PyDateTimeAPI->DateTimeType) | |||
86 | lt.tm_year + 1900,PyDateTimeAPI->DateTime_FromDateAndTime(lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday, lt.tm_hour, lt.tm_min, lt.tm_sec, 0, (&_Py_NoneStruct), PyDateTimeAPI->DateTimeType) | |||
87 | lt.tm_mon + 1,PyDateTimeAPI->DateTime_FromDateAndTime(lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday, lt.tm_hour, lt.tm_min, lt.tm_sec, 0, (&_Py_NoneStruct), PyDateTimeAPI->DateTimeType) | |||
88 | lt.tm_mday,PyDateTimeAPI->DateTime_FromDateAndTime(lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday, lt.tm_hour, lt.tm_min, lt.tm_sec, 0, (&_Py_NoneStruct), PyDateTimeAPI->DateTimeType) | |||
89 | lt.tm_hour,PyDateTimeAPI->DateTime_FromDateAndTime(lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday, lt.tm_hour, lt.tm_min, lt.tm_sec, 0, (&_Py_NoneStruct), PyDateTimeAPI->DateTimeType) | |||
90 | lt.tm_min,PyDateTimeAPI->DateTime_FromDateAndTime(lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday, lt.tm_hour, lt.tm_min, lt.tm_sec, 0, (&_Py_NoneStruct), PyDateTimeAPI->DateTimeType) | |||
91 | lt.tm_sec,PyDateTimeAPI->DateTime_FromDateAndTime(lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday, lt.tm_hour, lt.tm_min, lt.tm_sec, 0, (&_Py_NoneStruct), PyDateTimeAPI->DateTimeType) | |||
92 | 0)PyDateTimeAPI->DateTime_FromDateAndTime(lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday, lt.tm_hour, lt.tm_min, lt.tm_sec, 0, (&_Py_NoneStruct), PyDateTimeAPI->DateTimeType); | |||
93 | ||||
94 | return ret; | |||
95 | } | |||
96 | ||||
97 | /** | |||
98 | * PyRRD_String_FromCF: get string representation of CF enum index | |||
99 | * | |||
100 | * @param cf enum cf_en | |||
101 | * @return Null-terminated string | |||
102 | */ | |||
103 | const char * | |||
104 | PyRRD_String_FromCF(enum cf_en cf) | |||
105 | { | |||
106 | switch (cf) { | |||
107 | case CF_AVERAGE: | |||
108 | return "AVERAGE"; | |||
109 | case CF_MINIMUM: | |||
110 | return "MIN"; | |||
111 | case CF_MAXIMUM: | |||
112 | return "MAX"; | |||
113 | case CF_LAST: | |||
114 | return "LAST"; | |||
115 | default: | |||
116 | return "INVALID"; | |||
117 | } | |||
118 | } | |||
119 | ||||
120 | /** | |||
121 | * Helper function to convert Python objects into a representation that the | |||
122 | * rrdtool functions can work with. | |||
123 | * | |||
124 | * @param command RRDtool command name | |||
125 | * @param args Command arguments | |||
126 | * @return Zero if the function succeeds, otherwise -1 | |||
127 | */ | |||
128 | static int | |||
129 | convert_args(char *command, PyObject *args, char ***rrdtool_argv, int *rrdtool_argc) | |||
130 | { | |||
131 | PyObject *o, *lo; | |||
132 | int i, j, args_count, argv_count, element_count; | |||
133 | ||||
134 | argv_count = element_count = 0; | |||
135 | args_count = PyTuple_Size(args); | |||
136 | ||||
137 | for (i = 0; i < args_count; i++) { | |||
138 | o = PyTuple_GET_ITEM(args, i)((((void) (0)), (PyTupleObject *)(args))->ob_item[i]); | |||
139 | ||||
140 | if (PyRRD_String_Check(o)((((((PyObject*)(o))->ob_type))->tp_flags & ((1UL << 28))) != 0)) | |||
141 | element_count++; | |||
142 | else if (PyList_CheckExact(o)((((PyObject*)(o))->ob_type) == &PyList_Type)) | |||
143 | element_count += PyList_Size(o); | |||
144 | else { | |||
145 | PyErr_Format(PyExc_TypeError, | |||
146 | "Argument %d must be str or a list of str", i); | |||
147 | return -1; | |||
148 | } | |||
149 | } | |||
150 | ||||
151 | *rrdtool_argv = PyMem_New(char *, element_count + 1)( ((size_t)(element_count + 1) > ((Py_ssize_t)(((size_t)-1 )>>1)) / sizeof(char *)) ? ((void*)0) : ( (char * *) PyMem_Malloc ((element_count + 1) * sizeof(char *)) ) ); | |||
152 | ||||
153 | if (*rrdtool_argv == NULL((void*)0)) | |||
154 | return -1; | |||
155 | ||||
156 | for (i = 0; i < args_count; i++) { | |||
157 | o = PyTuple_GET_ITEM(args, i)((((void) (0)), (PyTupleObject *)(args))->ob_item[i]); | |||
158 | ||||
159 | if (PyRRD_String_Check(o)((((((PyObject*)(o))->ob_type))->tp_flags & ((1UL << 28))) != 0)) | |||
160 | (*rrdtool_argv)[++argv_count] = (char *)PyRRD_String_AS_STRING(o)PyUnicode_AsUTF8(o); | |||
161 | else if (PyList_CheckExact(o)((((PyObject*)(o))->ob_type) == &PyList_Type)) { | |||
162 | for (j = 0; j < PyList_Size(o); j++) { | |||
163 | lo = PyList_GetItem(o, j); | |||
164 | ||||
165 | if (PyRRD_String_Check(lo)((((((PyObject*)(lo))->ob_type))->tp_flags & ((1UL << 28))) != 0)) | |||
166 | (*rrdtool_argv)[++argv_count] = (char *)PyRRD_String_AS_STRING(lo)PyUnicode_AsUTF8(lo); | |||
167 | else { | |||
168 | PyMem_DelPyMem_Free(*rrdtool_argv); | |||
169 | PyErr_Format(PyExc_TypeError, | |||
170 | "Element %d in argument %d must be str", j, i); | |||
171 | return -1; | |||
172 | } | |||
173 | } | |||
174 | } else { | |||
175 | PyMem_DelPyMem_Free(*rrdtool_argv); | |||
176 | PyErr_Format(rrdtool_ProgrammingError, | |||
177 | "Argument %d must be str or list of str", i); | |||
178 | return -1; | |||
179 | } | |||
180 | } | |||
181 | ||||
182 | (*rrdtool_argv)[0] = command; | |||
183 | *rrdtool_argc = element_count + 1; | |||
184 | ||||
185 | return 0; | |||
186 | } | |||
187 | ||||
188 | /** | |||
189 | * Destroy argument vector. | |||
190 | */ | |||
191 | static void | |||
192 | destroy_args(char ***rrdtool_argv) | |||
193 | { | |||
194 | PyMem_DelPyMem_Free(*rrdtool_argv); | |||
195 | *rrdtool_argv = NULL((void*)0); | |||
196 | } | |||
197 | ||||
198 | /** | |||
199 | * Convert RRDtool info to dict. | |||
200 | * | |||
201 | * @param data RRDtool info object | |||
202 | * @return Python dict object | |||
203 | */ | |||
204 | static PyObject * | |||
205 | _rrdtool_util_info2dict(const rrd_info_t *data) | |||
206 | { | |||
207 | PyObject *dict, *val; | |||
208 | ||||
209 | dict = PyDict_New(); | |||
210 | ||||
211 | while (data) { | |||
212 | val = NULL((void*)0); | |||
213 | ||||
214 | switch (data->type) { | |||
215 | case RD_I_VAL: | |||
216 | if (isnan(data->value.u_val)__builtin_isnan (data->value.u_val)) { | |||
217 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | |||
218 | val = Py_None(&_Py_NoneStruct); | |||
219 | } else | |||
220 | val = PyFloat_FromDouble(data->value.u_val); | |||
221 | break; | |||
222 | ||||
223 | case RD_I_CNT: | |||
224 | val = PyLong_FromUnsignedLong(data->value.u_cnt); | |||
225 | break; | |||
226 | ||||
227 | case RD_I_INT: | |||
228 | val = PyLong_FromLong(data->value.u_int); | |||
229 | break; | |||
230 | ||||
231 | case RD_I_STR: | |||
232 | val = PyRRD_String_FromString(data->value.u_str)PyUnicode_FromString(data->value.u_str); | |||
233 | break; | |||
234 | ||||
235 | case RD_I_BLO: | |||
236 | val = PyRRD_String_FromStringAndSize(PyBytes_FromStringAndSize((char *)data->value.u_blo.ptr, data ->value.u_blo.size) | |||
237 | (char *)data->value.u_blo.ptr,PyBytes_FromStringAndSize((char *)data->value.u_blo.ptr, data ->value.u_blo.size) | |||
238 | data->value.u_blo.size)PyBytes_FromStringAndSize((char *)data->value.u_blo.ptr, data ->value.u_blo.size); | |||
239 | break; | |||
240 | default: | |||
241 | break; | |||
242 | } | |||
243 | ||||
244 | if (val != NULL((void*)0)) { | |||
245 | PyDict_SetItemString(dict, data->key, val); | |||
246 | Py_DECREF(val)_Py_DECREF(((PyObject*)(val))); | |||
247 | } | |||
248 | ||||
249 | data = data->next; | |||
250 | } | |||
251 | ||||
252 | return dict; | |||
253 | } | |||
254 | ||||
255 | static char _rrdtool_create__doc__[] = "Create a new Round Robin Database.\n\n\ | |||
256 | Usage: create(args...)\n\ | |||
257 | Arguments:\n\n\ | |||
258 | filename\n\ | |||
259 | [-b|--start start time]\n\ | |||
260 | [-s|--step step]\n\ | |||
261 | [-t|--template template-file]\n\ | |||
262 | [-r|--source source-file]\n\ | |||
263 | [-O|--no-overwrite]\n\ | |||
264 | [-d|--daemon address]\n\ | |||
265 | [DS:ds-name[=mapped-ds-name[source-index]]:DST:heartbeat:min:max]\n\ | |||
266 | [RRA:CF:xff:steps:rows]\n\n\ | |||
267 | Full documentation can be found at:\n\ | |||
268 | https://oss.oetiker.ch/rrdtool/doc/rrdcreate.en.html"; | |||
269 | ||||
270 | static PyObject * | |||
271 | _rrdtool_create(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
272 | { | |||
273 | char **rrdtool_argv = NULL((void*)0); | |||
274 | int rrdtool_argc = 0; | |||
275 | PyObject *ret; | |||
276 | int status; | |||
277 | ||||
278 | if (convert_args("create", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
279 | return NULL((void*)0); | |||
280 | ||||
281 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
282 | status = rrd_create(rrdtool_argc, rrdtool_argv); | |||
283 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
284 | ||||
285 | if (status == -1) { | |||
286 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
287 | rrd_clear_error(); | |||
288 | ret = NULL((void*)0); | |||
289 | } else { | |||
290 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | |||
291 | ret = Py_None(&_Py_NoneStruct); | |||
292 | } | |||
293 | ||||
294 | destroy_args(&rrdtool_argv); | |||
295 | return ret; | |||
296 | } | |||
297 | ||||
298 | static char _rrdtool_dump__doc__[] = "Dump an RRD to XML.\n\n\ | |||
299 | Usage: dump(args..)\n\ | |||
300 | Arguments:\n\n\ | |||
301 | [-h|--header {none,xsd,dtd}\n\ | |||
302 | [-n|--no-header]\n\ | |||
303 | [-d|--daemon address]\n\ | |||
304 | file.rrd\n\ | |||
305 | [file.xml]\n\n\ | |||
306 | Full documentation can be found at:\n\ | |||
307 | https://oss.oetiker.ch/rrdtool/doc/rrddump.en.html"; | |||
308 | ||||
309 | static PyObject * | |||
310 | _rrdtool_dump(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
311 | { | |||
312 | char **rrdtool_argv = NULL((void*)0); | |||
313 | int rrdtool_argc = 0; | |||
314 | PyObject *ret; | |||
315 | int status; | |||
316 | ||||
317 | if (convert_args("dump", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
318 | return NULL((void*)0); | |||
319 | ||||
320 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
321 | status = rrd_dump(rrdtool_argc, rrdtool_argv); | |||
322 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
323 | ||||
324 | if (status != 0) { | |||
325 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
326 | rrd_clear_error(); | |||
327 | ret = NULL((void*)0); | |||
328 | } else { | |||
329 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | |||
330 | ret = Py_None(&_Py_NoneStruct); | |||
331 | } | |||
332 | ||||
333 | destroy_args(&rrdtool_argv); | |||
334 | return ret; | |||
335 | } | |||
336 | ||||
337 | static char _rrdtool_update__doc__[] = "Store a new set of values into\ | |||
338 | the RRD.\n\n\ | |||
339 | Usage: update(args..)\n\ | |||
340 | Arguments:\n\n\ | |||
341 | filename\n\ | |||
342 | [--template|-t ds-name[:ds-name]...]\n\ | |||
343 | N|timestamp:value[:value...]\n\ | |||
344 | [timestamp:value[:value...] ...]\n\n\ | |||
345 | Full documentation can be found at:\n\ | |||
346 | https://oss.oetiker.ch/rrdtool/doc/rrdupdate.en.html"; | |||
347 | ||||
348 | static PyObject * | |||
349 | _rrdtool_update(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
350 | { | |||
351 | char **rrdtool_argv = NULL((void*)0); | |||
352 | int rrdtool_argc = 0; | |||
353 | PyObject *ret; | |||
354 | int status; | |||
355 | ||||
356 | if (convert_args("update", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
357 | return NULL((void*)0); | |||
358 | ||||
359 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
360 | status = rrd_update(rrdtool_argc, rrdtool_argv); | |||
361 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
362 | ||||
363 | if (status == -1) { | |||
364 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
365 | rrd_clear_error(); | |||
366 | ret = NULL((void*)0); | |||
367 | } else { | |||
368 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | |||
369 | ret = Py_None(&_Py_NoneStruct); | |||
370 | } | |||
371 | ||||
372 | destroy_args(&rrdtool_argv); | |||
373 | return ret; | |||
374 | } | |||
375 | ||||
376 | static char _rrdtool_updatev__doc__[] = "Store a new set of values into "\ | |||
377 | "the Round Robin Database and return an info dictionary.\n\n\ | |||
378 | This function works in the same manner as 'update', but will return an\n\ | |||
379 | info dictionary instead of None."; | |||
380 | ||||
381 | static PyObject * | |||
382 | _rrdtool_updatev(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
383 | { | |||
384 | char **rrdtool_argv = NULL((void*)0); | |||
385 | int rrdtool_argc = 0; | |||
386 | PyObject *ret; | |||
387 | rrd_info_t *data; | |||
388 | ||||
389 | if (convert_args("updatev", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
390 | return NULL((void*)0); | |||
391 | ||||
392 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
393 | data = rrd_update_v(rrdtool_argc, rrdtool_argv); | |||
394 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
395 | ||||
396 | if (data == NULL((void*)0)) { | |||
397 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
398 | rrd_clear_error(); | |||
399 | ret = NULL((void*)0); | |||
400 | } else { | |||
401 | ret = _rrdtool_util_info2dict(data); | |||
402 | rrd_info_free(data); | |||
403 | } | |||
404 | ||||
405 | destroy_args(&rrdtool_argv); | |||
406 | return ret; | |||
407 | } | |||
408 | ||||
409 | static char _rrdtool_fetch__doc__[] = "Fetch data from an RRD.\n\n\ | |||
410 | Usage: fetch(args..)\n\ | |||
411 | Arguments:\n\n\ | |||
412 | filename\n\ | |||
413 | CF\n\ | |||
414 | [-r|--resolution resolution]\n\ | |||
415 | [-s|--start start]\n\ | |||
416 | [-e|--end end]\n\ | |||
417 | [-a|--align-start]\n\ | |||
418 | [-d|--daemon address]\n\n\ | |||
419 | Full documentation can be found at:\n\ | |||
420 | https://oss.oetiker.ch/rrdtool/doc/rrdfetch.en.html"; | |||
421 | ||||
422 | static PyObject * | |||
423 | _rrdtool_fetch(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
424 | { | |||
425 | char **rrdtool_argv = NULL((void*)0); | |||
426 | int rrdtool_argc = 0; | |||
427 | PyObject *ret, *range_tup, *dsnam_tup, *data_list, *t; | |||
428 | rrd_value_t *data, *datai, dv; | |||
429 | unsigned long step, ds_cnt, i, j, row; | |||
430 | time_t start, end; | |||
431 | char **ds_namv; | |||
432 | int status; | |||
433 | ||||
434 | if (convert_args("fetch", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
| ||||
435 | return NULL((void*)0); | |||
436 | ||||
437 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
438 | status = rrd_fetch(rrdtool_argc, rrdtool_argv, &start, &end, &step, | |||
439 | &ds_cnt, &ds_namv, &data); | |||
440 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
441 | ||||
442 | if (status == -1) { | |||
443 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
444 | rrd_clear_error(); | |||
445 | ret = NULL((void*)0); | |||
446 | } else { | |||
447 | row = (end - start) / step; | |||
448 | ret = PyTuple_New(3); | |||
449 | range_tup = PyTuple_New(3); | |||
450 | dsnam_tup = PyTuple_New(ds_cnt); | |||
451 | data_list = PyList_New(row); | |||
452 | ||||
453 | PyTuple_SET_ITEM(ret, 0, range_tup)PyTuple_SetItem(ret, 0, range_tup); | |||
454 | PyTuple_SET_ITEM(ret, 1, dsnam_tup)PyTuple_SetItem(ret, 1, dsnam_tup); | |||
455 | PyTuple_SET_ITEM(ret, 2, data_list)PyTuple_SetItem(ret, 2, data_list); | |||
456 | ||||
457 | datai = data; | |||
458 | ||||
459 | PyTuple_SET_ITEM(range_tup, 0, PyRRD_Int_FromLong((long) start))PyTuple_SetItem(range_tup, 0, PyLong_FromLong((long) start)); | |||
| ||||
460 | PyTuple_SET_ITEM(range_tup, 1, PyRRD_Int_FromLong((long) end))PyTuple_SetItem(range_tup, 1, PyLong_FromLong((long) end)); | |||
461 | PyTuple_SET_ITEM(range_tup, 2, PyRRD_Int_FromLong((long) step))PyTuple_SetItem(range_tup, 2, PyLong_FromLong((long) step)); | |||
462 | ||||
463 | for (i = 0; i < ds_cnt; i++) | |||
464 | PyTuple_SET_ITEM(dsnam_tup, i, PyRRD_String_FromString(ds_namv[i]))PyTuple_SetItem(dsnam_tup, i, PyUnicode_FromString(ds_namv[i] )); | |||
465 | ||||
466 | for (i = 0; i < row; i++) { | |||
467 | t = PyTuple_New(ds_cnt); | |||
468 | PyList_SET_ITEM(data_list, i, t)PyList_SetItem(data_list, i, t); | |||
469 | ||||
470 | for (j = 0; j < ds_cnt; j++) { | |||
471 | dv = *(datai++); | |||
472 | if (isnan(dv)__builtin_isnan (dv)) { | |||
473 | PyTuple_SET_ITEM(t, j, Py_None)PyTuple_SetItem(t, j, (&_Py_NoneStruct)); | |||
474 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | |||
475 | } else | |||
476 | PyTuple_SET_ITEM(t, j, PyFloat_FromDouble((double) dv))PyTuple_SetItem(t, j, PyFloat_FromDouble((double) dv)); | |||
477 | } | |||
478 | } | |||
479 | ||||
480 | for (i = 0; i < ds_cnt; i++) | |||
481 | rrd_freemem(ds_namv[i]); | |||
482 | ||||
483 | rrd_freemem(ds_namv); | |||
484 | rrd_freemem(data); | |||
485 | } | |||
486 | ||||
487 | destroy_args(&rrdtool_argv); | |||
488 | return ret; | |||
489 | } | |||
490 | ||||
491 | static char _rrdtool_flushcached__doc__[] = "Flush RRD files from memory.\n\n\ | |||
492 | Usage: flushcached(args..)\n\ | |||
493 | Arguments:\n\n\ | |||
494 | [-d|--daemon address]\n\ | |||
495 | filename\n\ | |||
496 | [filename ...]\n\n\ | |||
497 | Full documentation can be found at:\n\ | |||
498 | https://oss.oetiker.ch/rrdtool/doc/rrdflushcached.en.html"; | |||
499 | ||||
500 | static PyObject * | |||
501 | _rrdtool_flushcached(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
502 | { | |||
503 | char **rrdtool_argv = NULL((void*)0); | |||
504 | int rrdtool_argc = 0; | |||
505 | PyObject *ret; | |||
506 | int status; | |||
507 | ||||
508 | if (convert_args("flushcached", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
509 | return NULL((void*)0); | |||
510 | ||||
511 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
512 | status = rrd_flushcached(rrdtool_argc, rrdtool_argv); | |||
513 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
514 | ||||
515 | if (status != 0) { | |||
516 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
517 | rrd_clear_error(); | |||
518 | ret = NULL((void*)0); | |||
519 | } else { | |||
520 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | |||
521 | ret = Py_None(&_Py_NoneStruct); | |||
522 | } | |||
523 | ||||
524 | destroy_args(&rrdtool_argv); | |||
525 | return ret; | |||
526 | } | |||
527 | ||||
528 | static char _rrdtool_graph__doc__[] = "Create a graph based on one or more " \ | |||
529 | "RRDs.\n\n\ | |||
530 | Usage: graph(args..)\n\ | |||
531 | Arguments:\n\n\ | |||
532 | filename | -\n\ | |||
533 | [-s|--start start]\n\ | |||
534 | [-e|--end end]\n\ | |||
535 | [-S|--step step]\n\ | |||
536 | [-t|--title string]\n\ | |||
537 | [-v|--vertical-label string]\n\ | |||
538 | [-w|--width pixels]\n\ | |||
539 | [-h|--height pixels]\n\ | |||
540 | [-j|--only-graph]\n\ | |||
541 | [-D|--full-size-mode]\n\ | |||
542 | [-u|--upper-limit value]\n\ | |||
543 | [-l|--lower-limit value]\n\ | |||
544 | [-r|--rigid]\n\ | |||
545 | [-A|--alt-autoscale]\n\ | |||
546 | [-J|--alt-autoscale-min]\n\ | |||
547 | [-M|--alt-autoscale-max]\n\ | |||
548 | [-N|--no-gridfit]\n\ | |||
549 | [-x|--x-grid (GTM:GST:MTM:MST:LTM:LST:LPR:LFM|none)]\n\ | |||
550 | [-y|--y-grid (grid step:label factor|none)]\n\ | |||
551 | [--week-fmt strftime format string]\n\ | |||
552 | [--left-axis-formatter formatter-name]\n\ | |||
553 | [--left-axis-format format-string]\n\ | |||
554 | [-Y|--alt-y-grid]\n\ | |||
555 | [-o|--logarithmic]\n\ | |||
556 | [-X|--units-exponent value]\n\ | |||
557 | [-L|--units-length value]\n\ | |||
558 | [--units=si]\n\ | |||
559 | [--right-axis scale:shift]\n\ | |||
560 | [--right-axis-label label]\n\ | |||
561 | [--right-axis-format format-string]\n\ | |||
562 | [-g|--no-legend]\n\ | |||
563 | [-F|--force-rules-legend]\n\ | |||
564 | [--legend-position=(north|south|west|east)]\n\ | |||
565 | [--legend-direction=(topdown|bottomup)]\n\ | |||
566 | [-z|--lazy]\n\ | |||
567 | [-d|--daemon address]\n\ | |||
568 | [-f|--imginfo printfstr]\n\ | |||
569 | [-c|--color COLORTAG#rrggbb[aa]]\n\ | |||
570 | [--grid-dash on:off]\n\ | |||
571 | [--border width]\n\ | |||
572 | [--dynamic-labels]\n\ | |||
573 | [-m|--zoom factor]\n\ | |||
574 | [-n|--font FONTTAG:size:[font]]\n\ | |||
575 | [-R|--font-render-mode {normal,light,mono}]\n\ | |||
576 | [-B|--font-smoothing-threshold size]\n\ | |||
577 | [-P|--pango-markup]\n\ | |||
578 | [-G|--graph-render-mode {normal,mono}]\n\ | |||
579 | [-E|--slope-mode]\n\ | |||
580 | [-a|--imgformat {PNG,SVG,EPS,PDF,XML,XMLENUM,JSON,JSONTIME,CSV,TSV,SSV}]\n\ | |||
581 | [-i|--interlaced]\n\ | |||
582 | [-T|--tabwidth value]\n\ | |||
583 | [-b|--base value]\n\ | |||
584 | [-W|--watermark string]\n\ | |||
585 | [-Z|--use-nan-for-all-missing-data]\n\ | |||
586 | DEF:vname=rrdfile:ds-name:CF[:step=step][:start=time][:end=time]\n\ | |||
587 | CDEF:vname=RPN expression\n\ | |||
588 | VDEF=vname:RPN expression\n\n\ | |||
589 | Full documentation can be found at:\n\ | |||
590 | https://oss.oetiker.ch/rrdtool/doc/rrdgraph.en.html"; | |||
591 | ||||
592 | static PyObject * | |||
593 | _rrdtool_graph(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
594 | { | |||
595 | char **rrdtool_argv = NULL((void*)0); | |||
596 | int rrdtool_argc = 0; | |||
597 | PyObject *ret; | |||
598 | int xsize, ysize, i, status; | |||
599 | double ymin, ymax; | |||
600 | char **calcpr = NULL((void*)0); | |||
601 | ||||
602 | if (convert_args("graph", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
603 | return NULL((void*)0); | |||
604 | ||||
605 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
606 | status = rrd_graph(rrdtool_argc, rrdtool_argv, &calcpr, &xsize, &ysize, | |||
607 | NULL((void*)0), &ymin, &ymax); | |||
608 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
609 | ||||
610 | if (status == -1) { | |||
611 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
612 | rrd_clear_error(); | |||
613 | ret = NULL((void*)0); | |||
614 | } else { | |||
615 | ret = PyTuple_New(3); | |||
616 | ||||
617 | PyTuple_SET_ITEM(ret, 0, PyRRD_Int_FromLong((long) xsize))PyTuple_SetItem(ret, 0, PyLong_FromLong((long) xsize)); | |||
618 | PyTuple_SET_ITEM(ret, 1, PyRRD_Int_FromLong((long) ysize))PyTuple_SetItem(ret, 1, PyLong_FromLong((long) ysize)); | |||
619 | ||||
620 | if (calcpr) { | |||
621 | PyObject *e, *t; | |||
622 | ||||
623 | e = PyList_New(0); | |||
624 | PyTuple_SET_ITEM(ret, 2, e)PyTuple_SetItem(ret, 2, e); | |||
625 | ||||
626 | for (i = 0; calcpr[i]; i++) { | |||
627 | t = PyRRD_String_FromString(calcpr[i])PyUnicode_FromString(calcpr[i]); | |||
628 | PyList_Append(e, t); | |||
629 | Py_DECREF(t)_Py_DECREF(((PyObject*)(t))); | |||
630 | rrd_freemem(calcpr[i]); | |||
631 | } | |||
632 | } else { | |||
633 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | |||
634 | PyTuple_SET_ITEM(ret, 2, Py_None)PyTuple_SetItem(ret, 2, (&_Py_NoneStruct)); | |||
635 | } | |||
636 | } | |||
637 | ||||
638 | destroy_args(&rrdtool_argv); | |||
639 | return ret; | |||
640 | } | |||
641 | ||||
642 | static char _rrdtool_graphv__doc__[] = "Create a graph based on one or more " \ | |||
643 | "RRDs and return data in RRDtool info format.\n\n\ | |||
644 | This function works the same way as 'graph', but will return a info\n\ | |||
645 | dictionary instead of None.\n\n\ | |||
646 | Full documentation can be found at (graphv section):\n\ | |||
647 | https://oss.oetiker.ch/rrdtool/doc/rrdgraph.en.html"; | |||
648 | ||||
649 | static PyObject * | |||
650 | _rrdtool_graphv(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
651 | { | |||
652 | char **rrdtool_argv = NULL((void*)0); | |||
653 | int rrdtool_argc = 0; | |||
654 | PyObject *ret; | |||
655 | rrd_info_t *data; | |||
656 | ||||
657 | if (convert_args("graphv", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
658 | return NULL((void*)0); | |||
659 | ||||
660 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
661 | data = rrd_graph_v(rrdtool_argc, rrdtool_argv); | |||
662 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
663 | ||||
664 | if (data == NULL((void*)0)) { | |||
665 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
666 | rrd_clear_error(); | |||
667 | ret = NULL((void*)0); | |||
668 | } else { | |||
669 | ret = _rrdtool_util_info2dict(data); | |||
670 | rrd_info_free(data); | |||
671 | } | |||
672 | ||||
673 | destroy_args(&rrdtool_argv); | |||
674 | return ret; | |||
675 | } | |||
676 | ||||
677 | static char _rrdtool_xport__doc__[] = "Dictionary representation of data " \ | |||
678 | "stored in RRDs.\n\n\ | |||
679 | Usage: xport(args..)\n\ | |||
680 | Arguments:\n\n\ | |||
681 | [-s[--start seconds]\n\ | |||
682 | [-e|--end seconds]\n\ | |||
683 | [-m|--maxrows rows]\n\ | |||
684 | [--step value]\n\ | |||
685 | [--json]\n\ | |||
686 | [--enumds]\n\ | |||
687 | [--daemon address]\n\ | |||
688 | [DEF:vname=rrd:ds-name:CF]\n\ | |||
689 | [CDEF:vname=rpn-expression]\n\ | |||
690 | [XPORT:vname[:legend]]\n\n\ | |||
691 | Full documentation can be found at:\n\ | |||
692 | https://oss.oetiker.ch/rrdtool/doc/rrdxport.en.html"; | |||
693 | ||||
694 | static PyObject * | |||
695 | _rrdtool_xport(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
696 | { | |||
697 | char **rrdtool_argv = NULL((void*)0); | |||
698 | int rrdtool_argc = 0; | |||
699 | PyObject *ret; | |||
700 | int xsize, status; | |||
701 | char **legend_v; | |||
702 | time_t start, end; | |||
703 | unsigned long step, col_cnt; | |||
704 | rrd_value_t *data, *datai; | |||
705 | ||||
706 | if (convert_args("xport", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
707 | return NULL((void*)0); | |||
708 | ||||
709 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
710 | status = rrd_xport(rrdtool_argc, rrdtool_argv, &xsize, &start, &end, &step, | |||
711 | &col_cnt, &legend_v, &data); | |||
712 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
713 | ||||
714 | if (status == -1) { | |||
715 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
716 | rrd_clear_error(); | |||
717 | ret = NULL((void*)0); | |||
718 | } else { | |||
719 | PyObject *meta_dict, *data_list, *legend_list, *t; | |||
720 | rrd_value_t dv; | |||
721 | unsigned long i, j, row_cnt = (end - start) / step; | |||
722 | ||||
723 | ret = PyDict_New(); | |||
724 | meta_dict = PyDict_New(); | |||
725 | legend_list = PyList_New(col_cnt); | |||
726 | data_list = PyList_New(row_cnt); | |||
727 | ||||
728 | PyDict_SetItem(ret, PyRRD_String_FromString("meta")PyUnicode_FromString("meta"), meta_dict); | |||
729 | PyDict_SetItem(ret, PyRRD_String_FromString("data")PyUnicode_FromString("data"), data_list); | |||
730 | ||||
731 | datai = data; | |||
732 | ||||
733 | PyDict_SetItem(meta_dict, | |||
734 | PyRRD_String_FromString("start")PyUnicode_FromString("start"), | |||
735 | PyRRD_Int_FromLong((long) start)PyLong_FromLong((long) start)); | |||
736 | PyDict_SetItem(meta_dict, | |||
737 | PyRRD_String_FromString("end")PyUnicode_FromString("end"), | |||
738 | PyRRD_Int_FromLong((long) end)PyLong_FromLong((long) end)); | |||
739 | PyDict_SetItem(meta_dict, | |||
740 | PyRRD_String_FromString("step")PyUnicode_FromString("step"), | |||
741 | PyRRD_Int_FromLong((long) step)PyLong_FromLong((long) step)); | |||
742 | PyDict_SetItem(meta_dict, | |||
743 | PyRRD_String_FromString("rows")PyUnicode_FromString("rows"), | |||
744 | PyRRD_Int_FromLong((long) row_cnt)PyLong_FromLong((long) row_cnt)); | |||
745 | PyDict_SetItem(meta_dict, | |||
746 | PyRRD_String_FromString("columns")PyUnicode_FromString("columns"), | |||
747 | PyRRD_Int_FromLong((long) col_cnt)PyLong_FromLong((long) col_cnt)); | |||
748 | PyDict_SetItem(meta_dict, | |||
749 | PyRRD_String_FromString("legend")PyUnicode_FromString("legend"), | |||
750 | legend_list); | |||
751 | ||||
752 | for (i = 0; i < col_cnt; i++) | |||
753 | PyList_SET_ITEM(legend_list, i, PyRRD_String_FromString(legend_v[i]))PyList_SetItem(legend_list, i, PyUnicode_FromString(legend_v[ i])); | |||
754 | ||||
755 | for (i = 0; i < row_cnt; i++) { | |||
756 | t = PyTuple_New(col_cnt); | |||
757 | PyList_SET_ITEM(data_list, i, t)PyList_SetItem(data_list, i, t); | |||
758 | ||||
759 | for (j = 0; j < col_cnt; j++) { | |||
760 | dv = *(datai++); | |||
761 | ||||
762 | if (isnan(dv)__builtin_isnan (dv)) { | |||
763 | PyTuple_SET_ITEM(t, j, Py_None)PyTuple_SetItem(t, j, (&_Py_NoneStruct)); | |||
764 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | |||
765 | } else { | |||
766 | PyTuple_SET_ITEM(t, j, PyFloat_FromDouble((double) dv))PyTuple_SetItem(t, j, PyFloat_FromDouble((double) dv)); | |||
767 | } | |||
768 | } | |||
769 | } | |||
770 | ||||
771 | for (i = 0; i < col_cnt; i++) | |||
772 | rrd_freemem(legend_v[i]); | |||
773 | ||||
774 | rrd_freemem(legend_v); | |||
775 | rrd_freemem(data); | |||
776 | } | |||
777 | ||||
778 | destroy_args(&rrdtool_argv); | |||
779 | ||||
780 | return ret; | |||
781 | } | |||
782 | ||||
783 | static char _rrdtool_tune__doc__[] = "Modify some basic properties of a " \ | |||
784 | "Round Robin Database.\n\n\ | |||
785 | Usage: tune(args..)\n\ | |||
786 | Arguments:\n\n\ | |||
787 | filename\n\ | |||
788 | [-h|--heartbeat ds-name:heartbeat]\n\ | |||
789 | [-i|--minimum ds-name:min]\n\ | |||
790 | [-a|--maximum ds-name:max]\n\ | |||
791 | [-d|--data-source-type ds-name:DST]\n\ | |||
792 | [-r|--data-source-rename old-name:new-name]\n\n\ | |||
793 | Full documentation can be found at:\n\ | |||
794 | https://oss.oetiker.ch/rrdtool/doc/rrdtune.en.html"; | |||
795 | ||||
796 | static PyObject * | |||
797 | _rrdtool_tune(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
798 | { | |||
799 | char **rrdtool_argv = NULL((void*)0); | |||
800 | int rrdtool_argc = 0; | |||
801 | PyObject *ret; | |||
802 | int status; | |||
803 | ||||
804 | if (convert_args("tune", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
805 | return NULL((void*)0); | |||
806 | ||||
807 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
808 | status = rrd_tune(rrdtool_argc, rrdtool_argv); | |||
809 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
810 | ||||
811 | if (status == -1) { | |||
812 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
813 | rrd_clear_error(); | |||
814 | ret = NULL((void*)0); | |||
815 | } else { | |||
816 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | |||
817 | ret = Py_None(&_Py_NoneStruct); | |||
818 | } | |||
819 | ||||
820 | destroy_args(&rrdtool_argv); | |||
821 | return ret; | |||
822 | } | |||
823 | ||||
824 | static char _rrdtool_first__doc__[] = "Get the first UNIX timestamp of the "\ | |||
825 | "first data sample in an Round Robin Database.\n\n\ | |||
826 | Usage: first(args..)\n\ | |||
827 | Arguments:\n\n\ | |||
828 | filename\n\ | |||
829 | [--rraindex number]\n\ | |||
830 | [-d|--daemon address]\n\n\ | |||
831 | Full documentation can be found at:\n\ | |||
832 | https://oss.oetiker.ch/rrdtool/doc/rrdfirst.en.html"; | |||
833 | ||||
834 | static PyObject * | |||
835 | _rrdtool_first(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
836 | { | |||
837 | char **rrdtool_argv = NULL((void*)0); | |||
838 | int rrdtool_argc = 0; | |||
839 | PyObject *ret; | |||
840 | int ts; | |||
841 | ||||
842 | if (convert_args("first", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
843 | return NULL((void*)0); | |||
844 | ||||
845 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
846 | ts = rrd_first(rrdtool_argc, rrdtool_argv); | |||
847 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
848 | ||||
849 | if (ts == -1) { | |||
850 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
851 | rrd_clear_error(); | |||
852 | ret = NULL((void*)0); | |||
853 | } else | |||
854 | ret = PyRRD_Int_FromLong((long) ts)PyLong_FromLong((long) ts); | |||
855 | ||||
856 | destroy_args(&rrdtool_argv); | |||
857 | return ret; | |||
858 | } | |||
859 | ||||
860 | static char _rrdtool_last__doc__[] = "Get the UNIX timestamp of the most "\ | |||
861 | "recent data sample in an Round Robin Database.\n\n\ | |||
862 | Usage: last(args..)\n\ | |||
863 | Arguments:\n\n\ | |||
864 | filename\n\ | |||
865 | [-d|--daemon address]\n\n\ | |||
866 | Full documentation can be found at:\n\ | |||
867 | https://oss.oetiker.ch/rrdtool/doc/rrdlast.en.html"; | |||
868 | ||||
869 | static PyObject * | |||
870 | _rrdtool_last(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
871 | { | |||
872 | char **rrdtool_argv = NULL((void*)0); | |||
873 | int rrdtool_argc = 0; | |||
874 | PyObject *ret; | |||
875 | int ts; | |||
876 | ||||
877 | if (convert_args("last", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
878 | return NULL((void*)0); | |||
879 | ||||
880 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
881 | ts = rrd_last(rrdtool_argc, rrdtool_argv); | |||
882 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
883 | ||||
884 | if (ts == -1) { | |||
885 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
886 | rrd_clear_error(); | |||
887 | ret = NULL((void*)0); | |||
888 | } else | |||
889 | ret = PyRRD_Int_FromLong((long) ts)PyLong_FromLong((long) ts); | |||
890 | ||||
891 | destroy_args(&rrdtool_argv); | |||
892 | return ret; | |||
893 | } | |||
894 | ||||
895 | static char _rrdtool_resize__doc__[] = "Modify the number of rows in a "\ | |||
896 | "Round Robin Database.\n\n\ | |||
897 | Usage: resize(args..)\n\ | |||
898 | Arguments:\n\n\ | |||
899 | filename\n\ | |||
900 | rra-num\n\ | |||
901 | GROW|SHRINK\n\ | |||
902 | rows\n\n\ | |||
903 | Full documentation can be found at:\n\ | |||
904 | https://oss.oetiker.ch/rrdtool/doc/rrdlast.en.html"; | |||
905 | ||||
906 | static PyObject * | |||
907 | _rrdtool_resize(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
908 | { | |||
909 | char **rrdtool_argv = NULL((void*)0); | |||
910 | int rrdtool_argc = 0; | |||
911 | PyObject *ret; | |||
912 | int status; | |||
913 | ||||
914 | if (convert_args("resize", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
915 | return NULL((void*)0); | |||
916 | ||||
917 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
918 | status = rrd_resize(rrdtool_argc, rrdtool_argv); | |||
919 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
920 | ||||
921 | if (status == -1) { | |||
922 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
923 | rrd_clear_error(); | |||
924 | ret = NULL((void*)0); | |||
925 | } else { | |||
926 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | |||
927 | ret = Py_None(&_Py_NoneStruct); | |||
928 | } | |||
929 | ||||
930 | destroy_args(&rrdtool_argv); | |||
931 | return ret; | |||
932 | } | |||
933 | ||||
934 | static char _rrdtool_info__doc__[] = "Extract header information from an "\ | |||
935 | "Round Robin Database.\n\n\ | |||
936 | Usage: info(filename, ...)\n\ | |||
937 | Arguments:\n\n\ | |||
938 | filename\n\ | |||
939 | [-d|--daemon address]\n\ | |||
940 | [-F|--noflush]\n\n\ | |||
941 | Full documentation can be found at:\n\ | |||
942 | https://oss.oetiker.ch/rrdtool/doc/rrdinfo.en.html"; | |||
943 | ||||
944 | static PyObject * | |||
945 | _rrdtool_info(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
946 | { | |||
947 | char **rrdtool_argv = NULL((void*)0); | |||
948 | int rrdtool_argc = 0; | |||
949 | PyObject *ret; | |||
950 | rrd_info_t *data; | |||
951 | ||||
952 | if (convert_args("info", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
953 | return NULL((void*)0); | |||
954 | ||||
955 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
956 | data = rrd_info(rrdtool_argc, rrdtool_argv); | |||
957 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
958 | ||||
959 | if (data == NULL((void*)0)) { | |||
960 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
961 | rrd_clear_error(); | |||
962 | ret = NULL((void*)0); | |||
963 | } else { | |||
964 | ret = _rrdtool_util_info2dict(data); | |||
965 | rrd_info_free(data); | |||
966 | } | |||
967 | ||||
968 | destroy_args(&rrdtool_argv); | |||
969 | return ret; | |||
970 | } | |||
971 | ||||
972 | static char _rrdtool_lastupdate__doc__[] = "Returns datetime and value stored "\ | |||
973 | "for each datum in the most recent update of an RRD.\n\n\ | |||
974 | Usage: lastupdate(filename, ...)\n\ | |||
975 | Arguments:\n\n\ | |||
976 | filename\n\ | |||
977 | [-d|--daemon address]\n\n\ | |||
978 | Full documentation can be found at:\n\ | |||
979 | https://oss.oetiker.ch/rrdtool/doc/rrdlastupdate.en.html"; | |||
980 | ||||
981 | static PyObject * | |||
982 | _rrdtool_lastupdate(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
983 | { | |||
984 | char **rrdtool_argv = NULL((void*)0); | |||
985 | int rrdtool_argc = 0; | |||
986 | PyObject *ret, *ds_dict, *lastupd; | |||
987 | int status; | |||
988 | time_t last_update; | |||
989 | char **ds_names, **last_ds; | |||
990 | unsigned long ds_cnt, i; | |||
991 | ||||
992 | if (convert_args("lastupdate", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
993 | return NULL((void*)0); | |||
994 | else if (rrdtool_argc < 2) { | |||
995 | PyErr_SetString(rrdtool_ProgrammingError, "Missing filename argument"); | |||
996 | return NULL((void*)0); | |||
997 | } | |||
998 | ||||
999 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
1000 | status = rrd_lastupdate_r(rrdtool_argv[1], | |||
1001 | &last_update, | |||
1002 | &ds_cnt, | |||
1003 | &ds_names, | |||
1004 | &last_ds); | |||
1005 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
1006 | ||||
1007 | if (status != 0) { | |||
1008 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
1009 | rrd_clear_error(); | |||
1010 | ret = NULL((void*)0); | |||
1011 | } else { | |||
1012 | /* convert last_update to Python datetime object */ | |||
1013 | ret = PyDict_New(); | |||
1014 | ds_dict = PyDict_New(); | |||
1015 | lastupd = PyRRD_DateTime_FromTS(last_update); | |||
1016 | ||||
1017 | PyDict_SetItemString(ret, "date", lastupd); | |||
1018 | PyDict_SetItemString(ret, "ds", ds_dict); | |||
1019 | ||||
1020 | Py_DECREF(lastupd)_Py_DECREF(((PyObject*)(lastupd))); | |||
1021 | Py_DECREF(ds_dict)_Py_DECREF(((PyObject*)(ds_dict))); | |||
1022 | ||||
1023 | for (i = 0; i < ds_cnt; i++) { | |||
1024 | PyObject* val = Py_None(&_Py_NoneStruct); | |||
1025 | ||||
1026 | double num; | |||
1027 | if (sscanf(last_ds[i], "%lf", &num) == 1) { | |||
1028 | val = PyFloat_FromDouble(num); | |||
1029 | } | |||
1030 | ||||
1031 | if (!val) | |||
1032 | return NULL((void*)0); | |||
1033 | ||||
1034 | PyDict_SetItemString(ds_dict, ds_names[i], val); | |||
1035 | ||||
1036 | if (val != Py_None(&_Py_NoneStruct)) | |||
1037 | Py_DECREF(val)_Py_DECREF(((PyObject*)(val))); | |||
1038 | ||||
1039 | free(last_ds[i]); | |||
1040 | free(ds_names[i]); | |||
1041 | } | |||
1042 | ||||
1043 | free(last_ds); | |||
1044 | free(ds_names); | |||
1045 | ||||
1046 | } | |||
1047 | ||||
1048 | destroy_args(&rrdtool_argv); | |||
1049 | ||||
1050 | return ret; | |||
1051 | } | |||
1052 | ||||
1053 | #ifdef WITH_FETCH_CB1 | |||
1054 | ||||
1055 | /** A Python object which will hold a callable for fetch callbacks */ | |||
1056 | static PyObject *_rrdtool_fetch_callable = NULL((void*)0); | |||
1057 | ||||
1058 | static int | |||
1059 | _rrdtool_fetch_cb_wrapper( | |||
1060 | const char *filename, | |||
1061 | enum cf_en cf_idx, | |||
1062 | time_t *start, | |||
1063 | time_t *end, | |||
1064 | unsigned long *step, | |||
1065 | unsigned long *ds_cnt, | |||
1066 | char ***ds_namv, | |||
1067 | rrd_value_t **data) | |||
1068 | { | |||
1069 | PyObject *args; | |||
1070 | PyObject *kwargs; | |||
1071 | PyObject *ret = NULL((void*)0); | |||
1072 | PyObject *tmp; | |||
1073 | PyObject *tmp_min_ts; | |||
1074 | PyGILState_STATE gstate; | |||
1075 | Py_ssize_t rowcount = 0; | |||
1076 | int rc = -1; | |||
1077 | unsigned int i, ii; | |||
1078 | ||||
1079 | gstate = PyGILState_Ensure(); | |||
1080 | ||||
1081 | if (_rrdtool_fetch_callable == NULL((void*)0)) { | |||
1082 | rrd_set_error("use rrdtool.register_fetch_cb to register a fetch callback"); | |||
1083 | goto gil_release_err; | |||
1084 | } | |||
1085 | ||||
1086 | args = PyTuple_New(0); | |||
1087 | kwargs = PyDict_New(); | |||
1088 | ||||
1089 | /* minimum possible UNIX datetime */ | |||
1090 | tmp_min_ts = PyLong_FromLong(0); | |||
1091 | ||||
1092 | PyObject *po_filename = PyRRD_String_FromString(filename)PyUnicode_FromString(filename); | |||
1093 | PyDict_SetItemString(kwargs, "filename", po_filename); | |||
1094 | Py_DECREF(po_filename)_Py_DECREF(((PyObject*)(po_filename))); | |||
1095 | ||||
1096 | PyObject *po_cfstr = PyRRD_String_FromString(PyRRD_String_FromCF(cf_idx))PyUnicode_FromString(PyRRD_String_FromCF(cf_idx)); | |||
1097 | PyDict_SetItemString(kwargs, "cf", po_cfstr); | |||
1098 | Py_DECREF(po_cfstr)_Py_DECREF(((PyObject*)(po_cfstr))); | |||
1099 | ||||
1100 | PyObject *po_start = PyLong_FromLong(*start); | |||
1101 | PyDict_SetItemString(kwargs, "start", po_start); | |||
1102 | Py_DECREF(po_start)_Py_DECREF(((PyObject*)(po_start))); | |||
1103 | ||||
1104 | PyObject *po_end = PyLong_FromLong(*end); | |||
1105 | PyDict_SetItemString(kwargs, "end", po_end); | |||
1106 | Py_DECREF(po_end)_Py_DECREF(((PyObject*)(po_end))); | |||
1107 | ||||
1108 | PyObject *po_step = PyLong_FromUnsignedLong(*step); | |||
1109 | PyDict_SetItemString(kwargs, "step", po_step); | |||
1110 | Py_DECREF(po_step)_Py_DECREF(((PyObject*)(po_step))); | |||
1111 | ||||
1112 | /* execute Python callback method */ | |||
1113 | ret = PyObject_Call(_rrdtool_fetch_callable, args, kwargs); | |||
1114 | Py_DECREF(args)_Py_DECREF(((PyObject*)(args))); | |||
1115 | Py_DECREF(kwargs)_Py_DECREF(((PyObject*)(kwargs))); | |||
1116 | ||||
1117 | if (ret == NULL((void*)0)) { | |||
1118 | rrd_set_error("calling python callback failed"); | |||
1119 | goto gil_release_err; | |||
1120 | } | |||
1121 | ||||
1122 | /* handle return value of callback */ | |||
1123 | if (!PyDict_Check(ret)((((((PyObject*)(ret))->ob_type))->tp_flags & ((1UL << 29))) != 0)) { | |||
1124 | rrd_set_error("expected callback method to be a dict"); | |||
1125 | goto gil_release_err; | |||
1126 | } | |||
1127 | ||||
1128 | tmp = PyDict_GetItemString(ret, "step"); | |||
1129 | if (tmp == NULL((void*)0)) { | |||
1130 | rrd_set_error("expected 'step' key in callback return value"); | |||
1131 | goto gil_release_err; | |||
1132 | } else if (!PyRRD_Long_Check(tmp)((((((PyObject*)(tmp))->ob_type))->tp_flags & ((1UL << 24))) != 0)) { | |||
1133 | rrd_set_error("the 'step' key in callback return value must be int"); | |||
1134 | goto gil_release_err; | |||
1135 | } else | |||
1136 | *step = PyLong_AsLong(tmp); | |||
1137 | ||||
1138 | tmp = PyDict_GetItemString(ret, "start"); | |||
1139 | if (tmp == NULL((void*)0)) { | |||
1140 | rrd_set_error("expected 'start' key in callback return value"); | |||
1141 | goto gil_release_err; | |||
1142 | } else if (!PyRRD_Long_Check(tmp)((((((PyObject*)(tmp))->ob_type))->tp_flags & ((1UL << 24))) != 0)) { | |||
1143 | rrd_set_error("expected 'start' key in callback return value to be " | |||
1144 | "of type int"); | |||
1145 | goto gil_release_err; | |||
1146 | } else if (PyObject_RichCompareBool(tmp, tmp_min_ts, Py_EQ2) || | |||
1147 | PyObject_RichCompareBool(tmp, po_start, Py_LT0)) { | |||
1148 | rrd_set_error("expected 'start' value in callback return dict to be " | |||
1149 | "equal or earlier than passed start timestamp"); | |||
1150 | goto gil_release_err; | |||
1151 | } else { | |||
1152 | *start = PyLong_AsLong(po_start); | |||
1153 | ||||
1154 | if (*start == -1) { | |||
1155 | rrd_set_error("expected 'start' value in callback return value to" | |||
1156 | " not exceed LONG_MAX"); | |||
1157 | goto gil_release_err; | |||
1158 | } | |||
1159 | } | |||
1160 | ||||
1161 | tmp = PyDict_GetItemString(ret, "data"); | |||
1162 | if (tmp == NULL((void*)0)) { | |||
1163 | rrd_set_error("expected 'data' key in callback return value"); | |||
1164 | goto gil_release_err; | |||
1165 | } else if (!PyDict_Check(tmp)((((((PyObject*)(tmp))->ob_type))->tp_flags & ((1UL << 29))) != 0)) { | |||
1166 | rrd_set_error("expected 'data' key in callback return value of type " | |||
1167 | "dict"); | |||
1168 | goto gil_release_err; | |||
1169 | } else { | |||
1170 | *ds_cnt = (unsigned long)PyDict_Size(tmp); | |||
1171 | *ds_namv = (char **)calloc(*ds_cnt, sizeof(char *)); | |||
1172 | ||||
1173 | if (*ds_namv == NULL((void*)0)) { | |||
1174 | rrd_set_error("an error occurred while allocating memory for " | |||
1175 | "ds_namv when allocating memory for python callback"); | |||
1176 | goto gil_release_err; | |||
1177 | } | |||
1178 | ||||
1179 | PyObject *key, *value; | |||
1180 | Py_ssize_t pos = 0; /* don't use pos for indexing */ | |||
1181 | unsigned int x = 0; | |||
1182 | ||||
1183 | while (PyDict_Next(tmp, &pos, &key, &value)) { | |||
1184 | const char *key_str = PyRRD_String_AS_STRING(key)PyUnicode_AsUTF8(key); | |||
1185 | ||||
1186 | if (key_str == NULL((void*)0)) { | |||
1187 | rrd_set_error("key of 'data' element from callback return " | |||
1188 | "value is not a string"); | |||
1189 | goto gil_release_free_dsnamv_err; | |||
1190 | } else if (strlen(key_str) > DS_NAM_SIZE20) { | |||
1191 | rrd_set_error("key '%s' longer than the allowed maximum of %d " | |||
1192 | "byte", key_str, DS_NAM_SIZE20 - 1); | |||
1193 | goto gil_release_free_dsnamv_err; | |||
1194 | } | |||
1195 | ||||
1196 | if ((((*ds_namv)[x]) = (char *)malloc(sizeof(char) * DS_NAM_SIZE20)) == NULL((void*)0)) { | |||
1197 | rrd_set_error("malloc fetch ds_namv entry"); | |||
1198 | goto gil_release_free_dsnamv_err; | |||
1199 | } | |||
1200 | ||||
1201 | strncpy((*ds_namv)[x], key_str, DS_NAM_SIZE20 - 1); | |||
1202 | (*ds_namv)[x][DS_NAM_SIZE20 - 1] = '\0'; | |||
1203 | ||||
1204 | if (!PyList_Check(value)((((((PyObject*)(value))->ob_type))->tp_flags & ((1UL << 25))) != 0)) { | |||
1205 | rrd_set_error("expected 'data' dict values in callback return " | |||
1206 | "value of type list"); | |||
1207 | goto gil_release_free_dsnamv_err; | |||
1208 | } else if (PyList_Size(value) > rowcount) | |||
1209 | rowcount = PyList_Size(value); | |||
1210 | ||||
1211 | ++x; | |||
1212 | } | |||
1213 | ||||
1214 | *end = *start + *step * rowcount; | |||
1215 | ||||
1216 | if (((*data) = (rrd_value_t *)malloc(*ds_cnt * rowcount * sizeof(rrd_value_t))) == NULL((void*)0)) { | |||
1217 | rrd_set_error("malloc fetch data area"); | |||
1218 | goto gil_release_free_dsnamv_err; | |||
1219 | } | |||
1220 | ||||
1221 | for (i = 0; i < *ds_cnt; i++) { | |||
1222 | for (ii = 0; ii < (unsigned int)rowcount; ii++) { | |||
1223 | char *ds_namv_i = (*ds_namv)[i]; | |||
1224 | double va; | |||
1225 | PyObject *lstv = PyList_GetItem(PyDict_GetItemString(tmp, ds_namv_i), ii); | |||
1226 | ||||
1227 | /* lstv may be NULL here in case an IndexError has been raised; | |||
1228 | in such case the rowcount is higher than the number of elements for | |||
1229 | the list of that ds. use DNAN as value for these then */ | |||
1230 | if (lstv == NULL((void*)0) || lstv == Py_None(&_Py_NoneStruct)) { | |||
1231 | if (lstv == NULL((void*)0)) | |||
1232 | PyErr_Clear(); | |||
1233 | va = DNANrrd_set_to_DNAN(); | |||
1234 | } | |||
1235 | else { | |||
1236 | va = PyFloat_AsDouble(lstv); | |||
1237 | if (va == -1.0 && PyErr_Occurred()) { | |||
1238 | PyObject *exc_type, *exc_value, *exc_value_str = NULL((void*)0), *exc_tb; | |||
1239 | PyErr_Fetch(&exc_type, &exc_value, &exc_tb); | |||
1240 | ||||
1241 | if (exc_value != NULL((void*)0)) { | |||
1242 | exc_value_str = PyObject_Str(exc_value); | |||
1243 | rrd_set_error((char *)PyRRD_String_AS_STRING(exc_value_str)PyUnicode_AsUTF8(exc_value_str)); | |||
1244 | Py_DECREF(exc_value)_Py_DECREF(((PyObject*)(exc_value))); | |||
1245 | } | |||
1246 | ||||
1247 | Py_DECREF(exc_type)_Py_DECREF(((PyObject*)(exc_type))); | |||
1248 | Py_DECREF(exc_value_str)_Py_DECREF(((PyObject*)(exc_value_str))); | |||
1249 | if (exc_tb != NULL((void*)0)) | |||
1250 | Py_DECREF(exc_tb)_Py_DECREF(((PyObject*)(exc_tb))); | |||
1251 | goto gil_release_free_dsnamv_err; | |||
1252 | } | |||
1253 | } | |||
1254 | ||||
1255 | (*data)[i + ii * (*ds_cnt)] = va; | |||
1256 | } | |||
1257 | } | |||
1258 | } | |||
1259 | ||||
1260 | /* success */ | |||
1261 | rc = 1; | |||
1262 | goto gil_release; | |||
1263 | ||||
1264 | gil_release_free_dsnamv_err: | |||
1265 | for (i = 0; i < *ds_cnt; i++) { | |||
1266 | if ((*ds_namv)[i]) { | |||
1267 | free((*ds_namv)[i]); | |||
1268 | } | |||
1269 | } | |||
1270 | ||||
1271 | free(*ds_namv); | |||
1272 | ||||
1273 | gil_release_err: | |||
1274 | rc = -1; | |||
1275 | ||||
1276 | gil_release: | |||
1277 | if (ret != NULL((void*)0)) | |||
1278 | Py_DECREF(ret)_Py_DECREF(((PyObject*)(ret))); | |||
1279 | PyGILState_Release(gstate); | |||
1280 | return rc; | |||
1281 | } | |||
1282 | ||||
1283 | static char _rrdtool_register_fetch_cb__doc__[] = "Register callback for " | |||
1284 | "fetching data"; | |||
1285 | ||||
1286 | static PyObject * | |||
1287 | _rrdtool_register_fetch_cb(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
1288 | { | |||
1289 | PyObject *callable; | |||
1290 | ||||
1291 | if (!PyArg_ParseTuple(args, "O", &callable)) | |||
1292 | return NULL((void*)0); | |||
1293 | else if (!PyCallable_Check(callable)) { | |||
1294 | PyErr_SetString(rrdtool_ProgrammingError, "first argument must be callable"); | |||
1295 | return NULL((void*)0); | |||
1296 | } else { | |||
1297 | _rrdtool_fetch_callable = callable; | |||
1298 | rrd_fetch_cb_register(_rrdtool_fetch_cb_wrapper); | |||
1299 | Py_RETURN_NONEreturn _Py_INCREF(((PyObject*)((&_Py_NoneStruct)))), (& _Py_NoneStruct); | |||
1300 | } | |||
1301 | } | |||
1302 | ||||
1303 | static char _rrdtool_clear_fetch_cb__doc__[] = "Clear callback for " | |||
1304 | "fetching data"; | |||
1305 | ||||
1306 | static PyObject * | |||
1307 | _rrdtool_clear_fetch_cb(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *Py_UNUSED(args)_unused_args __attribute__((unused))) | |||
1308 | { | |||
1309 | if (_rrdtool_fetch_callable == NULL((void*)0)) { | |||
1310 | PyErr_SetString(rrdtool_ProgrammingError, "no callback has been set previously"); | |||
1311 | return NULL((void*)0); | |||
1312 | } | |||
1313 | ||||
1314 | _rrdtool_fetch_callable = NULL((void*)0); | |||
1315 | rrd_fetch_cb_register(NULL((void*)0)); | |||
1316 | Py_RETURN_NONEreturn _Py_INCREF(((PyObject*)((&_Py_NoneStruct)))), (& _Py_NoneStruct); | |||
1317 | } | |||
1318 | ||||
1319 | #endif /* WITH_FETCH_CB */ | |||
1320 | ||||
1321 | static char _rrdtool_lib_version__doc__[] = "Get the version this binding "\ | |||
1322 | "was compiled against."; | |||
1323 | ||||
1324 | /** | |||
1325 | * Returns a str object that contains the librrd version. | |||
1326 | * | |||
1327 | * @return librrd version (Python str object) | |||
1328 | */ | |||
1329 | static PyObject * | |||
1330 | _rrdtool_lib_version(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *Py_UNUSED(args)_unused_args __attribute__((unused))) | |||
1331 | { | |||
1332 | return PyRRD_String_FromString(rrd_strversion())PyUnicode_FromString(rrd_strversion()); | |||
1333 | } | |||
1334 | ||||
1335 | /** Method table. */ | |||
1336 | static PyMethodDef rrdtool_methods[] = { | |||
1337 | {"create", (PyCFunction)_rrdtool_create, | |||
1338 | METH_VARARGS0x0001, _rrdtool_create__doc__}, | |||
1339 | {"dump", (PyCFunction)_rrdtool_dump, | |||
1340 | METH_VARARGS0x0001, _rrdtool_dump__doc__}, | |||
1341 | {"update", (PyCFunction)_rrdtool_update, | |||
1342 | METH_VARARGS0x0001, _rrdtool_update__doc__}, | |||
1343 | {"updatev", (PyCFunction)_rrdtool_updatev, | |||
1344 | METH_VARARGS0x0001, _rrdtool_updatev__doc__}, | |||
1345 | {"fetch", (PyCFunction)_rrdtool_fetch, | |||
1346 | METH_VARARGS0x0001, _rrdtool_fetch__doc__}, | |||
1347 | {"flushcached", (PyCFunction)_rrdtool_flushcached, | |||
1348 | METH_VARARGS0x0001, _rrdtool_flushcached__doc__}, | |||
1349 | {"graph", (PyCFunction)_rrdtool_graph, | |||
1350 | METH_VARARGS0x0001, _rrdtool_graph__doc__}, | |||
1351 | {"graphv", (PyCFunction)_rrdtool_graphv, | |||
1352 | METH_VARARGS0x0001, _rrdtool_graphv__doc__}, | |||
1353 | {"xport", (PyCFunction)_rrdtool_xport, | |||
1354 | METH_VARARGS0x0001, _rrdtool_xport__doc__}, | |||
1355 | {"tune", (PyCFunction)_rrdtool_tune, | |||
1356 | METH_VARARGS0x0001, _rrdtool_tune__doc__}, | |||
1357 | {"first", (PyCFunction)_rrdtool_first, | |||
1358 | METH_VARARGS0x0001, _rrdtool_first__doc__}, | |||
1359 | {"last", (PyCFunction)_rrdtool_last, | |||
1360 | METH_VARARGS0x0001, _rrdtool_last__doc__}, | |||
1361 | {"resize", (PyCFunction)_rrdtool_resize, | |||
1362 | METH_VARARGS0x0001, _rrdtool_resize__doc__}, | |||
1363 | {"info", (PyCFunction)_rrdtool_info, | |||
1364 | METH_VARARGS0x0001, _rrdtool_info__doc__}, | |||
1365 | {"lastupdate", (PyCFunction)_rrdtool_lastupdate, | |||
1366 | METH_VARARGS0x0001, _rrdtool_lastupdate__doc__}, | |||
1367 | #ifdef WITH_FETCH_CB1 | |||
1368 | {"register_fetch_cb", (PyCFunction)_rrdtool_register_fetch_cb, | |||
1369 | METH_VARARGS0x0001, _rrdtool_register_fetch_cb__doc__}, | |||
1370 | {"clear_fetch_cb", (PyCFunction)_rrdtool_clear_fetch_cb, | |||
1371 | METH_NOARGS0x0004, _rrdtool_clear_fetch_cb__doc__}, | |||
1372 | #endif /* WITH_FETCH_CB */ | |||
1373 | {"lib_version", (PyCFunction)_rrdtool_lib_version, | |||
1374 | METH_NOARGS0x0004, _rrdtool_lib_version__doc__}, | |||
1375 | {NULL((void*)0), NULL((void*)0), 0, NULL((void*)0)} | |||
1376 | }; | |||
1377 | ||||
1378 | /** Library init function. */ | |||
1379 | #ifdef HAVE_PY3K | |||
1380 | static struct PyModuleDef rrdtoolmodule = { | |||
1381 | .m_base = PyModuleDef_HEAD_INIT{ { 1, ((void*)0) }, ((void*)0), 0, ((void*)0), }, | |||
1382 | .m_name = "rrdtool", | |||
1383 | .m_doc = "Python bindings for rrdtool", | |||
1384 | .m_size = -1, | |||
1385 | .m_methods = rrdtool_methods | |||
1386 | }; | |||
1387 | ||||
1388 | #endif | |||
1389 | ||||
1390 | #ifdef HAVE_PY3K | |||
1391 | PyMODINIT_FUNCPyObject* | |||
1392 | PyInit_rrdtool(void) | |||
1393 | #else | |||
1394 | void | |||
1395 | initrrdtool(void) | |||
1396 | #endif | |||
1397 | { | |||
1398 | PyObject *m; | |||
1399 | ||||
1400 | PyDateTime_IMPORTPyDateTimeAPI = (PyDateTime_CAPI *)PyCapsule_Import("datetime.datetime_CAPI" , 0); /* initialize PyDateTime_ functions */ | |||
1401 | ||||
1402 | /* make sure that the GIL has been created as we need to aquire it */ | |||
1403 | if (!PyEval_ThreadsInitialized()) | |||
1404 | PyEval_InitThreads(); | |||
1405 | ||||
1406 | #ifdef HAVE_PY3K | |||
1407 | m = PyModule_Create(&rrdtoolmodule)PyModule_Create2(&rrdtoolmodule, 1013); | |||
1408 | #else | |||
1409 | m = Py_InitModule3("rrdtool", | |||
1410 | rrdtool_methods, | |||
1411 | "Python bindings for rrdtool"); | |||
1412 | #endif | |||
1413 | ||||
1414 | if (m == NULL((void*)0)) | |||
1415 | #ifdef HAVE_PY3K | |||
1416 | return NULL((void*)0); | |||
1417 | #else | |||
1418 | return; | |||
1419 | #endif | |||
1420 | ||||
1421 | rrdtool_ProgrammingError = PyErr_NewException("rrdtool.ProgrammingError", | |||
1422 | NULL((void*)0), NULL((void*)0)); | |||
1423 | Py_INCREF(rrdtool_ProgrammingError)_Py_INCREF(((PyObject*)(rrdtool_ProgrammingError))); | |||
1424 | PyModule_AddObject(m, "ProgrammingError", rrdtool_ProgrammingError); | |||
1425 | ||||
1426 | rrdtool_OperationalError = PyErr_NewException("rrdtool.OperationalError", | |||
1427 | NULL((void*)0), NULL((void*)0)); | |||
1428 | Py_INCREF(rrdtool_OperationalError)_Py_INCREF(((PyObject*)(rrdtool_OperationalError))); | |||
1429 | PyModule_AddObject(m, "OperationalError", rrdtool_OperationalError); | |||
1430 | PyModule_AddStringConstant(m, "__version__", _version); | |||
1431 | ||||
1432 | #ifdef HAVE_PY3K | |||
1433 | return m; | |||
1434 | #endif | |||
1435 | } |
1 | #ifndef PyTuple_New |
2 | struct _object; |
3 | typedef struct _object PyObject; |
4 | PyObject* clang_analyzer_PyObject_New_Reference(); |
5 | PyObject* PyTuple_New(Py_ssize_t len) { |
6 | return clang_analyzer_PyObject_New_Reference(); |
7 | } |
8 | #else |
9 | #warning "API PyTuple_New is defined as a macro." |
10 | #endif |
1 | #ifndef PyTuple_SetItem |
2 | struct _object; |
3 | typedef struct _object PyObject; |
4 | void clang_analyzer_PyObject_Steal_Reference(const void *); |
5 | int clang_analyzer_noimpl_conjure_int(); |
6 | int PyTuple_SetItem(PyObject *p, Py_ssize_t pos, PyObject *o) { |
7 | clang_analyzer_PyObject_Steal_Reference(o); |
8 | return clang_analyzer_noimpl_conjure_int(); |
9 | } |
10 | #else |
11 | #warning "API PyTuple_SetItem is defined as a macro." |
12 | #endif |