root/masterdriverz/use-expand/src/atom.c @ ferringb%2540gmail.com-20070115225237-b4qrzjp2ogcxxorh

Revision ferringb%2540gmail.com-20070115225237-b4qrzjp2ogcxxorh, 31.5 kB (checked in by Brian Harring <ferringb@…>, 2 years ago)

increment the idx after adding a slot restrict...

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