forked from mruffalo/sysv_ipc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcommon.c
101 lines (86 loc) · 3.09 KB
/
common.c
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#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;
}
#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;
}