File: common.c

package info (click to toggle)
python-sysv-ipc 1.1.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 540 kB
  • sloc: ansic: 3,140; python: 1,960; makefile: 8; sh: 4
file content (83 lines) | stat: -rw-r--r-- 2,716 bytes parent folder | download
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;
}