diff options
Diffstat (limited to 'common.c')
-rw-r--r-- | common.c | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/common.c b/common.c new file mode 100644 index 0000000..a55f99c --- /dev/null +++ b/common.c @@ -0,0 +1,100 @@ +#include "Python.h" +#include "structmember.h" + +#include "common.h" + +#include <stdlib.h> + +key_t +get_random_key(void) { + int key; + + /* ****************************************************************** + The inability to know the range of a key_t requires careful code here. + Remember that KEY_MIN and KEY_MAX refer only to the limits inherent in the + variable type I use internally when turning a key into a Python object and + vice versa. Those limits may exceed the operating system's limits of key_t. + + For instance, if key_t is typedef-ed as uint, I should generate a key + where 0 <= key <= UINT_MAX. + + Since I can't know what key_t is typedef-ed as, I take a conservative + approach and generate only keys where + 1 <= key <= SHRT_MAX. + + Such values will work if key_t is typedef-ed as a short, int, uint, + long or ulong. + ****************************************************************** */ + do { + // ref: http://www.c-faq.com/lib/randrange.html + key = ((int)((double)rand() / ((double)RAND_MAX + 1) * (SHRT_MAX - 1))) + 1; + } while (key == IPC_PRIVATE); + + return (key_t)key; +} + +#if PY_MAJOR_VERSION < 3 +PyObject * +py_int_or_long_from_ulong(unsigned long value) { + // Python ints are guaranteed to accept up to LONG_MAX. Anything + // larger needs to be a Python long. + if (value > LONG_MAX) + return PyLong_FromUnsignedLong(value); + else + return PyInt_FromLong(value); +} +#endif + + +int +convert_key_param(PyObject *py_key, void *converted_key) { + // Converts a PyObject into a key if possible. Returns 0 on failure. + // The converted_key param should point to a NoneableKey type. + // None is an acceptable key, in which case converted_key->is_none + // is non-zero and converted_key->value is undefined. + int rc = 0; + long key = 0; + + ((NoneableKey *)converted_key)->is_none = 0; + + if (py_key == Py_None) { + rc = 1; + ((NoneableKey *)converted_key)->is_none = 1; + } +#if PY_MAJOR_VERSION < 3 + else if (PyInt_Check(py_key)) { + rc = 1; + key = PyInt_AsLong(py_key); + } +#endif + else if (PyLong_Check(py_key)) { + rc = 1; + key = PyLong_AsLong(py_key); + if (PyErr_Occurred()) { + // This happens when the Python long is too big for a C long. + rc = 0; + PyErr_Format(PyExc_ValueError, + "Key must be between %ld (KEY_MIN) and %ld (KEY_MAX)", + KEY_MIN, KEY_MAX); + } + } + + if (rc) { + // Param is OK + if (! ((NoneableKey *)converted_key)->is_none) { + // It's not None; ensure it is in range + if ((key >= KEY_MIN) && (key <= KEY_MAX)) + ((NoneableKey *)converted_key)->value = (key_t)key; + else { + rc = 0; + PyErr_Format(PyExc_ValueError, + "Key must be between %ld (KEY_MIN) and %ld (KEY_MAX)", + KEY_MIN, KEY_MAX); + } + } + } + else + PyErr_SetString(PyExc_TypeError, "Key must be an integer or None"); + + return rc; +} |