root/releases/pkgcore/0.2.10/src/atom.c @ masterdriverz%2540gentoo.org-20070309225812-15j6j9wmp0pek3vw

Revision masterdriverz%2540gentoo.org-20070309225812-15j6j9wmp0pek3vw, 32.3 KB (checked in by Charlie Shepherd <masterdriverz@…>, 22 months ago)

Even more killing of trailing whitespace

Line 
1/*
2 * Copyright: 2006-2007 Brian Harring <ferringb@gmail.com>
3 * License: GPL2
4 *
5 * C version of some of pkgcore (for extra speed).
6 */
7
8/* This does not really do anything since we do not use the "#"
9 * specifier in a PyArg_Parse or similar call, but hey, not using it
10 * means we are Py_ssize_t-clean too!
11 */
12
13#define PY_SSIZE_T_CLEAN
14
15#include "common.h"
16
17// exceptions, loaded during initialization.
18static PyObject *pkgcore_atom_MalformedAtom_Exc = NULL;
19static PyObject *pkgcore_atom_InvalidCPV_Exc = NULL;
20
21// restricts.
22static PyObject *pkgcore_atom_VersionMatch = NULL;
23static PyObject *pkgcore_atom_PackageRestrict = NULL;
24static PyObject *pkgcore_atom_StrExactMatch = NULL;
25static PyObject *pkgcore_atom_StrGlobMatch = NULL;
26static PyObject *pkgcore_atom_ContainmentMatch = NULL;
27static PyObject *pkgcore_atom_ValOr = NULL;
28static PyObject *pkgcore_atom_ValAnd = NULL;
29
30// ops.
31static PyObject *pkgcore_atom_op_gt = NULL;
32static PyObject *pkgcore_atom_op_ge = NULL;
33static PyObject *pkgcore_atom_op_lt = NULL;
34static PyObject *pkgcore_atom_op_le = NULL;
35static PyObject *pkgcore_atom_op_eq = NULL;
36static PyObject *pkgcore_atom_op_droprev = NULL;
37static PyObject *pkgcore_atom_op_none = NULL;
38static PyObject *pkgcore_atom_op_glob = NULL;
39static PyObject *pkgcore_atom_cpv_parse = NULL;
40// every attr it sets...
41static PyObject *pkgcore_atom_cpvstr = NULL;
42static PyObject *pkgcore_atom_key = NULL;
43static PyObject *pkgcore_atom_category = NULL;
44static PyObject *pkgcore_atom_package = NULL;
45static PyObject *pkgcore_atom_version = NULL;
46static PyObject *pkgcore_atom_revision = NULL;
47static PyObject *pkgcore_atom_fullver = NULL;
48static PyObject *pkgcore_atom_hash = NULL;
49static PyObject *pkgcore_atom_use = NULL;
50static PyObject *pkgcore_atom_slot = NULL;
51static PyObject *pkgcore_atom_repo_id = NULL;
52static PyObject *pkgcore_atom_restrict_repo_id = NULL;
53static PyObject *pkgcore_atom_blocks = NULL;
54static PyObject *pkgcore_atom_op = NULL;
55static PyObject *pkgcore_atom_negate_vers = NULL;
56static PyObject *pkgcore_atom_restrictions = NULL;
57
58#define ISDIGIT(c) ('0' <= (c) && '9' >= (c))
59#define ISALPHA(c) (('a' <= (c) && 'z' >= (c)) || ('A' <= (c) && 'Z' >= (c)))
60#define ISLOWER(c) ('a' <= (c) && 'z' >= (c))
61#define ISALNUM(c) (ISALPHA(c) || ISDIGIT(c))
62
63#define VALID_USE_CHAR(c) (ISALNUM(c) || '-' == (c) \
64    || '_' == (c) || '.' == (c) || '+' == (c))
65
66static void
67Err_SetMalformedAtom(PyObject *atom_str, char *raw_msg)
68{
69    PyObject *msg = PyString_FromString(raw_msg);
70    if(!msg)
71        return;
72    PyObject *err = PyObject_CallFunction(pkgcore_atom_MalformedAtom_Exc,
73        "OO", atom_str, msg);
74    Py_DECREF(msg);
75    if(err) {
76        PyErr_SetObject(pkgcore_atom_MalformedAtom_Exc, err);
77        Py_DECREF(err);
78    }
79}
80
81static int
82parse_use_deps(PyObject *atom_str, char **p_ptr, PyObject **use_ptr)
83{
84    char *p = *p_ptr;
85    char *start = p;
86    Py_ssize_t len = 1;
87    PyObject *use = NULL;
88    while('\0' != *p && ']' != *p) {
89        if (',' == *p)
90            len++;
91        else if(!VALID_USE_CHAR(*p)) {
92            Err_SetMalformedAtom(atom_str,
93                "invalid char in use dep; each flag must be a-Z0-9_.-+");
94            return 1;
95        }
96        p++;
97    }
98    if('\0' == *p) {
99        Err_SetMalformedAtom(atom_str,
100            "use dep isn't closed");
101        return 1;
102    }
103    char *end = p;
104    if(len == 1)
105        use = PyTuple_New(len);
106    else
107        use = PyList_New(len);
108    if(!use)
109        return 1;
110    Py_ssize_t idx = 0;
111    PyObject *s;
112    p = len > 1 ? start : p;
113    while(end != p) {
114        if(',' == *p) {
115            // flag...
116            if(start == p) {
117                Err_SetMalformedAtom(atom_str,
118                    "invalid use flag; must be non empty");
119                goto cleanup_use_processing;
120            } else if('-' == start[1] && start + 1 == p) {
121                Err_SetMalformedAtom(atom_str,
122                    "invalid use flag; must be non empty, got just a negation");
123                goto cleanup_use_processing;
124            }
125            s = PyString_FromStringAndSize(start, p - start);
126            if(!s)
127                goto cleanup_use_processing;
128            // steals the ref.
129            if(PyList_SetItem(use, idx, s))
130                goto cleanup_use_processing;
131            idx++;
132            start = p + 1;
133        }
134        p++;
135    }
136    // one more to add...
137    if(start == p) {
138        Err_SetMalformedAtom(atom_str,
139            "invalid use flag; must be non empty");
140        goto cleanup_use_processing;
141    } else if('-' == start[1] && start + 1 == p) {
142        Err_SetMalformedAtom(atom_str,
143            "invalid use flag; must be non empty, got just a negation");
144        goto cleanup_use_processing;
145    }
146    s = PyString_FromStringAndSize(start, end - start);
147    if(!s) {
148        goto cleanup_use_processing;
149    } else {
150        if(len == 1)
151            PyTuple_SET_ITEM(use, idx, s);
152        else if (PyList_SetItem(use, idx, s)) {
153            goto cleanup_use_processing;
154        }
155    }
156    if(len > 1) {
157        // weak...
158        if(PyList_Sort(use) < 0)
159            goto cleanup_use_processing;
160        PyObject *t = PyTuple_New(len);
161        if(!t)
162            goto cleanup_use_processing;
163        register PyObject *x;
164        for(idx=0; idx < len; idx++) {
165            x = PyList_GET_ITEM(use, idx);
166            Py_INCREF(x);
167            PyTuple_SET_ITEM(t, idx, x);
168        }
169        Py_DECREF(use);
170        use = t;
171    }
172    *use_ptr = use;
173    *p_ptr = p + 1;
174    return 0;
175    cleanup_use_processing:
176    Py_CLEAR(use);
177    return 1;
178}
179
180static int
181parse_slot_deps(PyObject *atom_str, char **p_ptr, PyObject **slots_ptr)
182{
183    char *p = *p_ptr;
184    char *start = p;
185    Py_ssize_t len = 1;
186    PyObject *slots = NULL;
187    while('\0' != *p && ':' != *p && '[' != *p) {
188        if (',' == *p)
189            len++;
190        else if(!VALID_USE_CHAR(*p)) {
191            Err_SetMalformedAtom(atom_str,
192                "invalid char in slot dep; each flag must be a-Z0-9_.-+");
193            goto cleanup_slot_processing;
194        }
195        p++;
196    }
197    char *end = p;
198    if(NULL == (slots = PyTuple_New(len)))
199        return 1;
200
201    Py_ssize_t idx = 0;
202    PyObject *s;
203    p = len > 1 ? start : p;
204    while(end != p) {
205        if(',' == *p) {
206            // flag...
207            if(start == p) {
208                Err_SetMalformedAtom(atom_str,
209                    "invalid slot dep; all slots must be non empty");
210                goto cleanup_slot_processing;
211            }
212            s = PyString_FromStringAndSize(start, p - start);
213            if(!s)
214                goto cleanup_slot_processing;
215            PyTuple_SET_ITEM(slots, idx, s);
216            idx++;
217            start = p + 1;
218        }
219        p++;
220    }
221    // one more to add...
222    if(start == p) {
223        Err_SetMalformedAtom(atom_str,
224            "invalid slot flag; all slots must be non empty");
225        goto cleanup_slot_processing;
226    }
227    s = PyString_FromStringAndSize(start, end - start);
228    if(s) {
229        PyTuple_SET_ITEM(slots, idx, s);
230        if(len > 1) {
231            // bugger. need a list :/
232            PyObject *tmp = PyList_New(len);
233            if(!tmp)
234                goto cleanup_slot_processing;
235            if(PyList_SetSlice(tmp, 0, len, slots)) {
236                Py_DECREF(tmp);
237                goto cleanup_slot_processing;
238            } else if (PyList_Sort(tmp)) {
239                Py_DECREF(tmp);
240                goto cleanup_slot_processing;
241            }
242            for(idx=0; idx < len; idx++) {
243                PyTuple_SET_ITEM(slots, idx, PyList_GET_ITEM(tmp, idx));
244            }
245            Py_DECREF(tmp);
246        }
247        *slots_ptr = slots;
248        *p_ptr = p;
249        return 0;
250    }
251    cleanup_slot_processing:
252    Py_CLEAR(slots);
253    return 1;
254}
255
256static int
257parse_repo_id(PyObject *atom_str, char *p, PyObject **repo_id)
258{
259    char *start = p;
260    while('\0' != *p) {
261        if(!VALID_USE_CHAR(*p) && '/' != *p) {
262            Err_SetMalformedAtom(atom_str,
263                "invalid character in repo_id: "
264                "valid characters are [a-Z0-9_.-+/]");
265            return 1;
266        }
267        p++;
268    }
269
270    if(start == p) {
271        Err_SetMalformedAtom(atom_str,
272            "repo_id must not be empty");
273        return 1;
274    }
275    *repo_id = PyString_FromStringAndSize(start, p - start);
276    return *repo_id ? 0 : 1;
277}
278
279static int
280parse_cpv(PyObject *atom_str, PyObject *cpv_str, PyObject *self,
281    int *has_version)
282{
283    PyObject *tmp;
284    PyObject *cpv = PyObject_CallFunction(pkgcore_atom_cpv_parse,
285        "O", cpv_str);
286    if(!cpv) {
287        PyObject *type, *tb;
288        PyErr_Fetch(&type, &tmp, &tb);
289        PyObject *res = PyObject_CallFunction(type, "O", tmp);
290        Py_XDECREF(tmp);
291        Py_XDECREF(type);
292        Py_XDECREF(tb);
293        if(!res)
294            return 1;
295        tmp = PyObject_Str(res);
296        if(!tmp)
297            return 1;
298        Py_DECREF(res);
299        Err_SetMalformedAtom(atom_str, PyString_AsString(tmp));
300        Py_DECREF(tmp);
301        return 1;
302    }
303
304    #define STORE_ATTR(attr_name)                                   \
305        if(NULL == (tmp = PyObject_GetAttr(cpv, attr_name))){ \
306            goto parse_cpv_error;                                   \
307        }                                                           \
308        if(PyObject_GenericSetAttr(self, attr_name, tmp)) {          \
309            Py_DECREF(tmp);                                         \
310            goto parse_cpv_error;                                   \
311        }                                                           \
312        Py_DECREF(tmp);
313
314    STORE_ATTR(pkgcore_atom_cpvstr);
315    STORE_ATTR(pkgcore_atom_category);
316    STORE_ATTR(pkgcore_atom_package);
317    STORE_ATTR(pkgcore_atom_key);
318    tmp = PyObject_GetAttr(cpv, pkgcore_atom_fullver);
319    if(!tmp)
320        goto parse_cpv_error;
321    *has_version = PyObject_IsTrue(tmp);
322    if(PyErr_Occurred()) {
323        Py_DECREF(tmp);
324        goto parse_cpv_error;
325    }
326    if(PyObject_GenericSetAttr(self, pkgcore_atom_fullver, tmp)) {
327        Py_DECREF(tmp);
328        goto parse_cpv_error;
329    }
330    Py_DECREF(tmp);
331    if(*has_version) {
332        STORE_ATTR(pkgcore_atom_version);
333        STORE_ATTR(pkgcore_atom_revision);
334    } else {
335        if(PyObject_GenericSetAttr(self, pkgcore_atom_version, Py_None))
336            goto parse_cpv_error;
337        if(PyObject_GenericSetAttr(self, pkgcore_atom_revision, Py_None))
338            goto parse_cpv_error;
339    }
340
341    #undef STORE_ATTR
342    Py_DECREF(cpv);
343    return 0;
344
345    parse_cpv_error:
346    Py_DECREF(cpv);
347    return 1;
348}
349
350static PyObject *
351pkgcore_atom_init(PyObject *self, PyObject *args, PyObject *kwds)
352{
353    PyObject *atom_str, *negate_vers = NULL;
354    static char *kwlist[] = {"atom_str", "negate_vers", NULL};
355    if(!PyArg_ParseTupleAndKeywords(args, kwds, "S|O:atom_init", kwlist,
356        &atom_str, &negate_vers))
357        return NULL;
358
359    if(!negate_vers) {
360        negate_vers = Py_False;
361    } else {
362        int ret = PyObject_IsTrue(negate_vers);
363        if (ret == -1)
364            return NULL;
365        negate_vers = ret ? Py_True : Py_False;
366    }
367    Py_INCREF(negate_vers);
368    char blocks = 0;
369    char *p, *atom_start;
370    atom_start = p = PyString_AsString(atom_str);
371
372    if('!' == *p) {
373        blocks++;
374        p++;
375    }
376
377    // handle op...
378
379    PyObject *op = pkgcore_atom_op_none;
380    if('<' == *p) {
381        if('=' == p[1]) {
382            op = pkgcore_atom_op_le;
383            p += 2;
384        } else {
385            op = pkgcore_atom_op_lt;
386            p++;
387        }
388    } else if('>' == *p) {
389        if('=' == p[1]) {
390            op = pkgcore_atom_op_ge;
391            p += 2;
392        } else {
393            op = pkgcore_atom_op_gt;
394            p++;
395        }
396    } else if ('=' == *p) {
397        op = pkgcore_atom_op_eq;
398        p++;
399    } else if ('~' == *p) {
400        op = pkgcore_atom_op_droprev;
401        p++;
402    } else
403        op = pkgcore_atom_op_none;
404
405    Py_INCREF(op);
406
407    // look for : or [
408    atom_start = p;
409    char *cpv_end = NULL;
410    PyObject *slot = NULL, *use = NULL, *repo_id = NULL;
411    char slot_seen = 0;
412    while('\0' != *p) {
413        if('[' == *p) {
414            if(!cpv_end)
415                cpv_end = p;
416            if(use) {
417                Err_SetMalformedAtom(atom_str,
418                    "multiple use blocks aren't allowed");
419                goto pkgcore_atom_parse_error;
420            }
421            p++;
422            if(parse_use_deps(atom_str, &p, &use))
423                goto pkgcore_atom_parse_error;
424        } else if(':' == *p) {
425            if(!cpv_end)
426                cpv_end = p;
427            p++;
428            if(slot_seen) {
429                // repo_id.
430                if(parse_repo_id(atom_str, p, &repo_id))
431                    goto pkgcore_atom_parse_error;
432                break;
433            } else if(repo_id) {
434                printf("foo");
435                Err_SetMalformedAtom(atom_str,
436                    "multiple slot/repo blocks aren't allowed, use ',' to specify "
437                    "multiple slots, multiple repos aren't allowed yet");
438                goto pkgcore_atom_parse_error;
439            } else {
440                slot_seen = 1;
441                if (':' != *p && '[' != *p) {
442                    if(parse_slot_deps(atom_str, &p, &slot)) {
443                        goto pkgcore_atom_parse_error;
444                    }
445                }
446            }
447        } else if(cpv_end) {
448            // char in between chunks...
449            Err_SetMalformedAtom(atom_str,
450                "interstitial characters between use/slot/repo_id blocks "
451                "aren't allowed");
452            goto pkgcore_atom_parse_error;
453        } else {
454            p++;
455        }
456    }
457
458    PyObject *cpv_str = NULL;
459    if(!cpv_end)
460        cpv_end = p;
461    if (!cpv_end && op == pkgcore_atom_op_none) {
462        Py_INCREF(atom_str);
463        cpv_str = atom_str;
464    } else {
465        if(op == pkgcore_atom_op_eq && atom_start + 1 < cpv_end &&
466            '*' == cpv_end[-1]) {
467            Py_DECREF(op);
468            Py_INCREF(pkgcore_atom_op_glob);
469            op = pkgcore_atom_op_glob;
470            cpv_str = PyString_FromStringAndSize(atom_start,
471                cpv_end - atom_start -1);
472        } else {
473            cpv_str = PyString_FromStringAndSize(atom_start,
474                cpv_end - atom_start);
475        }
476        if(!cpv_str)
477            goto pkgcore_atom_parse_error;
478    }
479    int has_version;
480    if(parse_cpv(atom_str, cpv_str, self, &has_version)) {
481        Py_DECREF(cpv_str);
482        goto pkgcore_atom_parse_error;
483    }
484    Py_DECREF(cpv_str);
485
486    // ok... everythings parsed... sanity checks on the atom.
487    if(op != pkgcore_atom_op_none) {
488        if (!has_version) {
489            Err_SetMalformedAtom(atom_str,
490                "operator requires a version");
491            goto pkgcore_atom_parse_error;
492        }
493    } else if(has_version) {
494        Err_SetMalformedAtom(atom_str,
495            "versioned atom requires an operator");
496        goto pkgcore_atom_parse_error;
497    }
498
499    if(!use) {
500        Py_INCREF(Py_None);
501        use = Py_None;
502    }
503    if(!slot) {
504        Py_INCREF(Py_None);
505        slot = Py_None;
506    }
507    if(!repo_id) {
508        Py_INCREF(Py_None);
509        repo_id = Py_None;
510    }
511
512    // store remaining attributes...
513
514    long hash_val = PyObject_Hash(atom_str);
515    PyObject *tmp;
516    if(hash_val == -1 || !(tmp = PyLong_FromLong(hash_val)))
517        goto pkgcore_atom_parse_error;
518    if(PyObject_GenericSetAttr(self, pkgcore_atom_hash, tmp)) {
519        Py_DECREF(tmp);
520        goto pkgcore_atom_parse_error;
521    }
522    Py_DECREF(tmp);
523
524    #define STORE_ATTR(attr_name, val)              \
525    if(PyObject_GenericSetAttr(self, (attr_name), (val)))  \
526        goto pkgcore_atom_parse_error;
527
528    STORE_ATTR(pkgcore_atom_blocks, blocks ? Py_True : Py_False);
529    STORE_ATTR(pkgcore_atom_op, op);
530    STORE_ATTR(pkgcore_atom_use, use);
531    STORE_ATTR(pkgcore_atom_slot, slot);
532    STORE_ATTR(pkgcore_atom_repo_id, repo_id);
533    STORE_ATTR(pkgcore_atom_negate_vers, negate_vers);
534    #undef STORE_ATTR
535
536    Py_RETURN_NONE;
537
538    pkgcore_atom_parse_error:
539    Py_DECREF(op);
540    Py_CLEAR(use);
541    Py_CLEAR(slot);
542    Py_CLEAR(repo_id);
543    Py_CLEAR(negate_vers);
544    return NULL;
545}
546
547static inline PyObject *
548make_simple_restrict(PyObject *attr, PyObject *str, PyObject *val_restrict)
549{
550    PyObject *tmp = PyObject_CallFunction(val_restrict, "O", str);
551    if(tmp) {
552        PyObject *tmp2 = PyObject_CallFunction(pkgcore_atom_PackageRestrict,
553            "OO", attr, tmp);
554        Py_DECREF(tmp);
555        if(tmp2) {
556            return tmp2;
557        }
558    }
559    return NULL;
560}
561
562static inline int
563make_version_kwds(PyObject *inst, PyObject **kwds)
564{
565    PyObject *negated = PyObject_GetAttr(inst, pkgcore_atom_negate_vers);
566    if(!negated)
567        return 1;
568    if(negated != Py_False && negated != Py_None) {
569        if(negated != Py_True) {
570            int ret = PyObject_IsTrue(negated);
571            Py_DECREF(negated);
572            if(ret == -1)
573                return 1;
574            if(ret == 1) {
575                Py_INCREF(Py_True);
576                negated = Py_True;
577            } else {
578                negated = NULL;
579            }
580        }
581        if(negated) {
582            *kwds = PyDict_New();
583            if(!*kwds) {
584                Py_DECREF(negated);
585                return 1;
586            }
587            if(PyDict_SetItemString(*kwds, "negate", negated)) {
588                Py_DECREF(*kwds);
589                Py_DECREF(negated);
590                return 1;
591            }
592            Py_DECREF(negated);
593        } else {
594            *kwds = NULL;
595        }
596    } else {
597        Py_DECREF(negated);
598        *kwds = NULL;
599    }
600    return 0;
601}
602
603// handles complex version restricts, rather then glob matches
604static inline PyObject *
605make_version_restrict(PyObject *inst, PyObject *op)
606{
607    PyObject *ver = PyObject_GetAttr(inst, pkgcore_atom_version);
608    if(ver) {
609        PyObject *tup = PyTuple_New(3);
610        if(!tup)
611            return NULL;
612        Py_INCREF(op);
613        PyTuple_SET_ITEM(tup, 0, op);
614        PyTuple_SET_ITEM(tup, 1, ver);
615        PyObject *rev;
616        if(op == pkgcore_atom_op_droprev) {
617            Py_INCREF(Py_None);
618            rev = Py_None;
619        } else if(!(rev = PyObject_GetAttr(inst, pkgcore_atom_revision))) {
620            Py_DECREF(tup);
621            return NULL;
622        }
623        PyTuple_SET_ITEM(tup, 2, rev);
624        PyObject *kwds = NULL;
625        if(!make_version_kwds(inst, &kwds)) {
626            // got our args, and kwds...
627            PyObject *ret = PyObject_Call(pkgcore_atom_VersionMatch,
628                tup, kwds);
629            Py_DECREF(tup);
630            Py_XDECREF(kwds);
631            return ret;
632        }
633        // since we've been using SET_ITEM, and did _not_ incref op
634        // (stole temporarily), we have to wipe it now for the decref.
635        Py_DECREF(tup);
636        // since tup steals, that just wiped ver, and rev.
637    }
638    return NULL;
639}
640
641static inline PyObject *
642make_slot_restrict(PyObject *slot)
643{
644    PyObject *tup = PyTuple_New(PyTuple_GET_SIZE(slot));
645    if(!tup)
646        return NULL;
647
648    // whee;  convert 'em, basically a map statement.
649    // use args repeatedly to avoid allocation; the callee cannot modify it
650    // (they can technically, but that's massively broken behavior).
651
652    Py_ssize_t idx;
653    for(idx=0; idx < PyTuple_GET_SIZE(slot); idx++) {
654        PyObject *s = PyTuple_GET_ITEM(slot, idx);
655        PyObject *tmp = PyObject_CallFunction(pkgcore_atom_StrExactMatch,
656            "O", s);
657        if(!tmp) {
658            Py_DECREF(tup);
659            return NULL;
660        }
661        PyTuple_SET_ITEM(tup, idx, tmp);
662    }
663    PyObject *tmp = PyObject_Call(pkgcore_atom_ValOr, tup, NULL);
664    Py_DECREF(tup);
665    if(tmp) {
666        PyObject *tmp2 = PyObject_CallFunction(pkgcore_atom_PackageRestrict,
667            "OO", pkgcore_atom_slot, tmp);
668        Py_DECREF(tmp);
669        tmp = tmp2;
670    }
671    return tmp;
672}
673
674static PyObject *
675make_use_val_restrict(PyObject *use)
676{
677    if(!PyTuple_CheckExact(use)) {
678        PyErr_SetString(PyExc_TypeError, "use must be None, or a tuple");
679        return NULL;
680    }
681    // fun one.
682    Py_ssize_t idx;
683    Py_ssize_t false_len = 0;
684    for(idx = 0; idx < PyTuple_GET_SIZE(use); idx++) {
685        if(!PyString_CheckExact(PyTuple_GET_ITEM(use, idx))) {
686            PyErr_SetString(PyExc_TypeError, "flags must be strings");
687            return NULL;
688        }
689        if('-' == *PyString_AS_STRING(PyTuple_GET_ITEM(use, idx))) {
690            false_len++;
691        }
692    }
693    if(!false_len) {
694        // easy case.
695        if(PyTuple_GET_SIZE(use) == 1) {
696            return PyObject_Call(pkgcore_atom_ContainmentMatch, use, NULL);
697        }
698        // slightly less easy.
699        PyObject *kwds = Py_BuildValue("{sO}", "all", Py_True);
700        if(kwds) {
701            PyObject *ret = PyObject_Call(pkgcore_atom_ContainmentMatch, use,
702                kwds);
703            Py_DECREF(kwds);
704            return ret;
705        }
706        return NULL;
707    }
708    // not so easy case.  need to split false use out, and make true use.
709
710    PyObject *enabled = NULL;
711    if(PyTuple_GET_SIZE(use) != false_len) {
712        enabled = PyTuple_New(PyTuple_GET_SIZE(use) - false_len);
713        if(!enabled)
714            return NULL;
715    }
716    PyObject *disabled = PyTuple_New(false_len);
717    if(!disabled) {
718        Py_XDECREF(enabled);
719        return NULL;
720    }
721    Py_ssize_t en_idx = 0, dis_idx = 0;
722    for(idx = 0; idx < PyTuple_GET_SIZE(use); idx++) {
723        PyObject *p = PyTuple_GET_ITEM(use, idx);
724        if('-' == *PyString_AS_STRING(p)) {
725            PyObject *s = PyString_FromStringAndSize(
726                PyString_AS_STRING(p) + 1, PyString_GET_SIZE(p) - 1);
727            if(!s) {
728                Py_XDECREF(enabled);
729                Py_DECREF(disabled);
730                return NULL;
731            }
732            PyTuple_SET_ITEM(disabled, dis_idx, s);
733            dis_idx++;
734        } else {
735            Py_INCREF(p);
736            PyTuple_SET_ITEM(enabled, en_idx, p);
737            en_idx++;
738        }
739    }
740    PyObject *kwds = PyDict_New();
741    if(kwds && (
742        PyDict_SetItemString(kwds, "negate", Py_True) ||
743        PyDict_SetItemString(kwds, "all", Py_True))) {
744        Py_CLEAR(kwds);
745    }
746    if(!kwds) {
747        // crappy.
748        Py_XDECREF(enabled);
749        Py_DECREF(disabled);
750        return NULL;
751    }
752    PyObject *dis_val = PyObject_Call(pkgcore_atom_ContainmentMatch, disabled,
753        kwds);
754    Py_DECREF(kwds);
755    Py_DECREF(disabled);
756    if(!dis_val) {
757        Py_DECREF(enabled);
758        return NULL;
759    }
760    PyObject *tmp;
761    if(enabled) {
762        kwds = PyDict_New();
763        if(kwds && PyDict_SetItemString(kwds, "all", Py_True)) {
764            Py_CLEAR(kwds);
765        }
766        if(!kwds) {
767            Py_DECREF(dis_val);
768            Py_DECREF(enabled);
769            return NULL;
770        }
771
772        PyObject *en_val = PyObject_Call(pkgcore_atom_ContainmentMatch,
773            enabled, kwds);
774        Py_DECREF(enabled);
775        Py_DECREF(kwds);
776        if(!en_val) {
777            Py_DECREF(dis_val);
778            return NULL;
779        }
780        tmp = PyObject_CallFunction(pkgcore_atom_ValAnd,
781            "OO", dis_val, en_val);
782        Py_DECREF(dis_val);
783        Py_DECREF(en_val);
784        if(!tmp) {
785            return NULL;
786        }
787    } else {
788        tmp = dis_val;
789    }
790    return tmp;
791}
792
793static PyObject *
794pkgcore_atom_getattr(PyObject *getattr_inst, PyObject *args)
795{
796    int required = 2;
797    int failed = 1;
798
799    PyObject *self = NULL, *attr = NULL;
800    if(!PyArg_ParseTuple(args, "OO", &self, &attr))
801        return NULL;
802
803    PyObject *op = NULL, *package = NULL, *category = NULL;
804    PyObject *use = NULL, *slot = NULL, *repo_id = NULL;
805    PyObject *tup = NULL, *tmp = NULL;
806
807    // prefer Py_EQ since cpythons string optimizes that case.
808    if(1 != PyObject_RichCompareBool(attr, pkgcore_atom_restrictions, Py_EQ)) {
809        PyErr_SetObject(PyExc_AttributeError, attr);
810        return NULL;
811    }
812
813    #define MUST_LOAD(ptr, str)                     \
814    if(!((ptr) = PyObject_GetAttr(self, (str))))    \
815        return NULL;
816
817    MUST_LOAD(op, pkgcore_atom_op);
818    MUST_LOAD(package, pkgcore_atom_package);
819    MUST_LOAD(category, pkgcore_atom_category);
820    MUST_LOAD(use, pkgcore_atom_use);
821    MUST_LOAD(slot, pkgcore_atom_slot);
822    MUST_LOAD(repo_id, pkgcore_atom_repo_id);
823
824    #undef MUST_LOAD
825
826    if(op != pkgcore_atom_op_none)
827        required++;
828    if(use != Py_None)
829        required++;
830    if(slot != Py_None)
831        required++;
832    if(repo_id != Py_None)
833        required++;
834
835    tup = PyTuple_New(required);
836    if(!tup)
837        goto pkgcore_atom_getattr_error;
838
839    int idx = 0;
840    if(repo_id != Py_None) {
841        if(!(tmp = make_simple_restrict(pkgcore_atom_restrict_repo_id,
842            repo_id, pkgcore_atom_StrExactMatch)))
843            goto pkgcore_atom_getattr_error;
844        PyTuple_SET_ITEM(tup, 0, tmp);
845        idx++;
846    }
847
848    if(!(tmp = make_simple_restrict(pkgcore_atom_package, package,
849        pkgcore_atom_StrExactMatch)))
850        goto pkgcore_atom_getattr_error;
851    PyTuple_SET_ITEM(tup, idx, tmp);
852    idx++;
853
854    if(!(tmp = make_simple_restrict(pkgcore_atom_category, category,
855        pkgcore_atom_StrExactMatch)))
856        goto pkgcore_atom_getattr_error;
857    PyTuple_SET_ITEM(tup, idx, tmp);
858    idx++;
859
860    if(op != pkgcore_atom_op_none) {
861        if(op == pkgcore_atom_op_glob) {
862            PyObject *tmp2 = PyObject_GetAttr(self, pkgcore_atom_fullver);
863            if(!tmp2) {
864                goto pkgcore_atom_getattr_error;
865            }
866            tmp = make_simple_restrict(pkgcore_atom_fullver, tmp2,
867                pkgcore_atom_StrGlobMatch);
868            Py_DECREF(tmp2);
869        } else {
870            tmp = make_version_restrict(self, op);
871        }
872        if(!tmp)
873            goto pkgcore_atom_getattr_error;
874        PyTuple_SET_ITEM(tup, idx, tmp);
875        idx++;
876    }
877    if(slot != Py_None) {
878        tmp = NULL;
879        if(!PyTuple_CheckExact(slot)) {
880            PyErr_SetString(PyExc_TypeError, "slot must be tuple or None");
881            goto pkgcore_atom_getattr_error;
882        }
883        if(PyTuple_GET_SIZE(slot) == 0) {
884            if(_PyTuple_Resize(&tup, PyTuple_GET_SIZE(tup) - 1))
885                goto pkgcore_atom_getattr_error;
886        } else {
887            if(1 == PyTuple_GET_SIZE(slot)) {
888                tmp = make_simple_restrict(pkgcore_atom_slot, slot,
889                    pkgcore_atom_StrExactMatch);
890            } else {
891                tmp = make_slot_restrict(slot);
892            }
893            if(!tmp)
894                goto pkgcore_atom_getattr_error;
895            PyTuple_SET_ITEM(tup, idx, tmp);
896        }
897        idx++;
898    }
899    if(use != Py_None) {
900        tmp = make_use_val_restrict(use);
901        if(!tmp)
902            goto pkgcore_atom_getattr_error;
903        PyObject *tmp2 = PyObject_CallFunction(pkgcore_atom_PackageRestrict,
904            "OO", pkgcore_atom_use, tmp);
905        Py_DECREF(tmp);
906        if(!tmp2)
907            goto pkgcore_atom_getattr_error;
908        PyTuple_SET_ITEM(tup, idx, tmp2);
909        idx++;
910    }
911    failed = 0;
912    pkgcore_atom_getattr_error:
913    Py_XDECREF(op);
914    Py_XDECREF(category);
915    Py_XDECREF(package);
916    Py_XDECREF(use);
917    Py_XDECREF(slot);
918    Py_XDECREF(repo_id);
919    if(failed)
920        Py_CLEAR(tup);
921    else {
922        if(PyObject_GenericSetAttr(self, pkgcore_atom_restrictions, tup)) {
923            Py_CLEAR(tup);
924        }
925    }
926    return tup;
927}
928
929PKGCORE_FUNC_BINDING("__init__", "pkgcore.ebuild._atom.__init__",
930    pkgcore_atom_init, METH_VARARGS|METH_KEYWORDS)
931PKGCORE_FUNC_BINDING("__getattr__", "pkgcore.ebuild._atom.__getattr__",
932    pkgcore_atom_getattr, METH_O|METH_COEXIST)
933
934PyDoc_STRVAR(
935    pkgcore_atom_documentation,
936    "cpython atom parsing functionality");
937
938static int
939load_external_objects()
940{
941    PyObject *s, *m = NULL;
942    #define LOAD_MODULE(char_p)             \
943    if(!(s = PyString_FromString(char_p)))  \
944        return 1;                           \
945    m = PyImport_Import(s);                 \
946    Py_DECREF(s);                           \
947    if(!m)                                  \
948        return 1;
949
950    if(!pkgcore_atom_MalformedAtom_Exc) {
951        LOAD_MODULE("pkgcore.ebuild.errors");
952        pkgcore_atom_MalformedAtom_Exc = PyObject_GetAttrString(m,
953            "MalformedAtom");
954        Py_DECREF(m);
955        if(!pkgcore_atom_MalformedAtom_Exc) {
956            return 1;
957        }
958        m = NULL;
959    }
960
961    if(!pkgcore_atom_cpv_parse || !pkgcore_atom_InvalidCPV_Exc) {
962        LOAD_MODULE("pkgcore.ebuild.cpv");
963    }
964
965    if(!pkgcore_atom_cpv_parse) {
966        pkgcore_atom_cpv_parse = PyObject_GetAttrString(m, "base_CPV");
967        if(!pkgcore_atom_cpv_parse)
968            return 1;
969    }
970    if(!pkgcore_atom_InvalidCPV_Exc) {
971        pkgcore_atom_InvalidCPV_Exc = PyObject_GetAttrString(m, "InvalidCPV");
972        if(!pkgcore_atom_InvalidCPV_Exc)
973            return 1;
974    }
975    if(m) {
976        Py_DECREF(m);
977    }
978
979    if(!pkgcore_atom_VersionMatch) {
980        LOAD_MODULE("pkgcore.ebuild.atom_restricts");
981        pkgcore_atom_VersionMatch = PyObject_GetAttrString(m,
982            "VersionMatch");
983        Py_DECREF(m);
984    }
985    if(!pkgcore_atom_StrExactMatch || !pkgcore_atom_StrGlobMatch ||
986        !pkgcore_atom_ContainmentMatch || !pkgcore_atom_ValAnd) {
987        LOAD_MODULE("pkgcore.restrictions.values");
988    } else
989        m = NULL;
990
991    #define LOAD_ATTR(ptr, name)                        \
992    if(!(ptr) && !                                      \
993        ((ptr) = PyObject_GetAttrString(m, (name)))) {  \
994        Py_DECREF(m);                                   \
995        return 1;                                       \
996    }
997    LOAD_ATTR(pkgcore_atom_StrExactMatch, "StrExactMatch");
998    LOAD_ATTR(pkgcore_atom_StrGlobMatch, "StrGlobMatch");
999    LOAD_ATTR(pkgcore_atom_ContainmentMatch, "ContainmentMatch");
1000    LOAD_ATTR(pkgcore_atom_ValAnd, "AndRestriction");
1001    LOAD_ATTR(pkgcore_atom_ValOr, "OrRestriction");
1002    if(m) {
1003        Py_DECREF(m);
1004    }
1005    if(!pkgcore_atom_PackageRestrict) {
1006        LOAD_MODULE("pkgcore.restrictions.packages");
1007        LOAD_ATTR(pkgcore_atom_PackageRestrict, "PackageRestriction");
1008        Py_DECREF(m);
1009    }
1010    #undef LOAD_ATTR
1011    #undef LOAD_MODULE
1012    return 0;
1013}
1014
1015
1016PyMODINIT_FUNC
1017init_atom()
1018{
1019    PyObject *m = Py_InitModule3("_atom", NULL, pkgcore_atom_documentation);
1020    if (!m)
1021        return;
1022
1023    // first get the exceptions we use.
1024    if(load_external_objects())
1025        return;
1026
1027    if(PyType_Ready(&pkgcore_atom_init_type) < 0)
1028        return;
1029
1030    if(PyType_Ready(&pkgcore_atom_getattr_type) < 0)
1031        return;
1032
1033    #define load_string(ptr, str)                   \
1034        if (!(ptr)) {                               \
1035            (ptr) = PyString_FromString(str);       \
1036            if(!(ptr))                              \
1037                return;                             \
1038        }
1039
1040    load_string(pkgcore_atom_cpvstr,        "cpvstr");
1041    load_string(pkgcore_atom_key,           "key");
1042    load_string(pkgcore_atom_category,      "category");
1043    load_string(pkgcore_atom_package,       "package");
1044    load_string(pkgcore_atom_version,       "version");
1045    load_string(pkgcore_atom_revision,      "revision");
1046    load_string(pkgcore_atom_fullver,       "fullver");
1047    load_string(pkgcore_atom_hash,          "hash");
1048    load_string(pkgcore_atom_use,           "use");
1049    load_string(pkgcore_atom_slot,          "slot");
1050    load_string(pkgcore_atom_repo_id,       "repo_id");
1051    load_string(pkgcore_atom_restrict_repo_id,
1052                                            "repo.repo_id");
1053    load_string(pkgcore_atom_op_glob,       "=*");
1054    load_string(pkgcore_atom_blocks,        "blocks");
1055    load_string(pkgcore_atom_op,            "op");
1056    load_string(pkgcore_atom_negate_vers,   "negate_vers");
1057    load_string(pkgcore_atom_restrictions,  "restrictions");
1058
1059    load_string(pkgcore_atom_op_ge,         ">=");
1060    load_string(pkgcore_atom_op_gt,         ">");
1061    load_string(pkgcore_atom_op_le,         "<=");
1062    load_string(pkgcore_atom_op_lt,         "<");
1063    load_string(pkgcore_atom_op_eq,         "=");
1064    load_string(pkgcore_atom_op_droprev,    "~");
1065    load_string(pkgcore_atom_op_none,       "");
1066    #undef load_string
1067
1068    PyObject *d = PyDict_New();
1069    if(!d)
1070        return;
1071
1072    PyObject *overrides = PyDict_New();
1073    if(!overrides)
1074        return;
1075    PyObject *tmp = PyType_GenericNew(&pkgcore_atom_init_type, NULL, NULL);
1076    if(!tmp)
1077        return;
1078    if(PyDict_SetItemString(overrides, "__init__", tmp))
1079        return;
1080    tmp = PyType_GenericNew(&pkgcore_atom_getattr_type, NULL, NULL);
1081    if(!tmp)
1082        return;
1083    if(PyDict_SetItemString(overrides, "__getattr__", tmp))
1084        return;
1085    PyModule_AddObject(m, "overrides", overrides);
1086
1087    if (PyErr_Occurred()) {
1088        Py_FatalError("can't initialize module _atom");
1089    }
1090}
Note: See TracBrowser for help on using the browser.