1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
|
#define PY_SSIZE_T_CLEAN
#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;
}
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;
}
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;
}
|