root/releases/pkgcore/0.2.4/src/atom.c @ ferringb%2540gmail.com-20070212033114-bnsgqv0v5n9y98kg

Revision ferringb%2540gmail.com-20070212033114-bnsgqv0v5n9y98kg, 31.7 KB (checked in by Brian Harring <ferringb@…>, 2 years ago)

bit of cleanup of the code; still needs a full walk since majority of it is quickies, but tiz a start.

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 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    char slot_seen = 0;
390    while('\0' != *p) {
391        if('[' == *p) {
392            if(!cpv_end)
393                cpv_end = p;
394            if(use) {
395                Err_SetMalformedAtom(atom_str,
396                    "multiple use blocks aren't allowed");
397                goto pkgcore_atom_parse_error;
398            }
399            p++;
400            if(parse_use_deps(atom_str, &p, &use))
401                goto pkgcore_atom_parse_error;
402        } else if(':' == *p) {
403            if(!cpv_end)
404                cpv_end = p;
405            p++;
406            if(slot_seen) {
407                // repo_id.
408                if(parse_repo_id(atom_str, p, &repo_id))
409                    goto pkgcore_atom_parse_error;
410                break;
411            } else if(repo_id) {
412                printf("foo");
413                Err_SetMalformedAtom(atom_str,
414                    "multiple slot/repo blocks aren't allowed, use ',' to specify "
415                    "multiple slots, multiple repos aren't allowed yet");
416                goto pkgcore_atom_parse_error;
417            } else {
418                slot_seen = 1;
419                if (':' != *p && '[' != *p) {
420                    if(parse_slot_deps(atom_str, &p, &slot)) {
421                        goto pkgcore_atom_parse_error;
422                    }
423                }
424            }
425        } else if(cpv_end) {
426            // char in between chunks...
427            Err_SetMalformedAtom(atom_str,
428                "interstitial characters between use/slot/repo_id blocks "
429                "aren't allowed");
430            goto pkgcore_atom_parse_error;
431        } else {
432            p++;
433        }
434    }
435   
436    PyObject *cpv_str = NULL;
437    if(!cpv_end)
438        cpv_end = p;
439    if (!cpv_end && op == pkgcore_atom_op_none) {
440        Py_INCREF(atom_str);
441        cpv_str = atom_str;
442    } else {
443        if(op == pkgcore_atom_op_eq && atom_start + 1 < cpv_end &&
444            '*' == cpv_end[-1]) {
445            Py_DECREF(op);
446            Py_INCREF(pkgcore_atom_op_glob);
447            op = pkgcore_atom_op_glob;
448            cpv_str = PyString_FromStringAndSize(atom_start,
449                cpv_end - atom_start -1);
450        } else {
451            cpv_str = PyString_FromStringAndSize(atom_start,
452                cpv_end - atom_start);
453        }
454        if(!cpv_str)
455            goto pkgcore_atom_parse_error;
456    }
457    int has_version;
458    if(parse_cpv(atom_str, cpv_str, self, &has_version)) {
459        Py_DECREF(cpv_str);
460        goto pkgcore_atom_parse_error;
461    }
462    Py_DECREF(cpv_str);
463
464    // ok... everythings parsed... sanity checks on the atom.
465    if(op != pkgcore_atom_op_none) {
466        if (!has_version) {
467            Err_SetMalformedAtom(atom_str,
468                "operator requires a version");
469            goto pkgcore_atom_parse_error;
470        }
471    } else if(has_version) {
472        Err_SetMalformedAtom(atom_str,
473            "versioned atom requires an operator");
474        goto pkgcore_atom_parse_error;
475    }
476
477    if(!use) {
478        Py_INCREF(Py_None);
479        use = Py_None;
480    }
481    if(!slot) {
482        Py_INCREF(Py_None);
483        slot = Py_None;
484    }
485    if(!repo_id) {
486        Py_INCREF(Py_None);
487        repo_id = Py_None;
488    }
489
490    // store remaining attributes...
491
492    long hash_val = PyObject_Hash(atom_str);
493    PyObject *tmp;
494    if(hash_val == -1 || !(tmp = PyLong_FromLong(hash_val)))
495        goto pkgcore_atom_parse_error;
496    if(PyObject_GenericSetAttr(self, pkgcore_atom_hash, tmp)) {
497        Py_DECREF(tmp);
498        goto pkgcore_atom_parse_error;
499    }
500    Py_DECREF(tmp);
501
502    #define STORE_ATTR(attr_name, val)              \
503    if(PyObject_GenericSetAttr(self, (attr_name), (val)))  \
504        goto pkgcore_atom_parse_error;
505
506    STORE_ATTR(pkgcore_atom_blocks, blocks ? Py_True : Py_False);
507    STORE_ATTR(pkgcore_atom_op, op);
508    STORE_ATTR(pkgcore_atom_use, use);
509    STORE_ATTR(pkgcore_atom_slot, slot);
510    STORE_ATTR(pkgcore_atom_repo_id, repo_id);
511    STORE_ATTR(pkgcore_atom_negate_vers, negate_vers);
512    #undef STORE_ATTR
513
514    Py_RETURN_NONE;
515
516    pkgcore_atom_parse_error:
517    Py_DECREF(op);
518    Py_CLEAR(use);
519    Py_CLEAR(slot);
520    Py_CLEAR(repo_id);
521    Py_CLEAR(negate_vers);
522    return NULL;
523}
524
525static inline PyObject *
526make_simple_restrict(PyObject *attr, PyObject *str, PyObject *val_restrict)
527{
528    PyObject *tmp = PyObject_CallFunction(val_restrict, "O", str);
529    if(tmp) {
530        PyObject *tmp2 = PyObject_CallFunction(pkgcore_atom_PackageRestrict,
531            "OO", attr, tmp);
532        Py_DECREF(tmp);
533        if(tmp2) {
534            return tmp2;
535        }
536    }
537    return NULL;
538}
539
540static inline int
541make_version_kwds(PyObject *inst, PyObject **kwds)
542{
543    PyObject *negated = PyObject_GetAttr(inst, pkgcore_atom_negate_vers);
544    if(!negated)
545        return 1;
546    if(negated != Py_False && negated != Py_None) {
547        if(negated != Py_True) {
548            int ret = PyObject_IsTrue(negated);
549            Py_DECREF(negated);
550            if(ret == -1)
551                return 1;
552            if(ret == 1) {
553                Py_INCREF(Py_True);
554                negated = Py_True;
555            } else {
556                negated = NULL;
557            }
558        }
559        if(negated) {
560            *kwds = PyDict_New();
561            if(!*kwds) {
562                Py_DECREF(negated);
563                return 1;
564            }
565            if(PyDict_SetItemString(*kwds, "negate", negated)) {
566                Py_DECREF(*kwds);
567                Py_DECREF(negated);
568                return 1;
569            }
570            Py_DECREF(negated);
571        } else {
572            *kwds = NULL;
573        }
574    } else {
575        Py_DECREF(negated);
576        *kwds = NULL;
577    }
578    return 0;
579}
580
581// handles complex version restricts, rather then glob matches
582static inline PyObject *
583make_version_restrict(PyObject *inst, PyObject *op)
584{
585    PyObject *ver = PyObject_GetAttr(inst, pkgcore_atom_version);
586    if(ver) {
587        PyObject *tup = PyTuple_New(3);
588        if(!tup)
589            return NULL;
590        Py_INCREF(op);
591        PyTuple_SET_ITEM(tup, 0, op);
592        PyTuple_SET_ITEM(tup, 1, ver);
593        PyObject *rev;
594        if(op == pkgcore_atom_op_droprev) {
595            Py_INCREF(Py_None);
596            rev = Py_None;
597        } else if(!(rev = PyObject_GetAttr(inst, pkgcore_atom_revision))) {
598            Py_DECREF(tup);
599            return NULL;
600        }
601        PyTuple_SET_ITEM(tup, 2, rev);
602        PyObject *kwds = NULL;
603        if(!make_version_kwds(inst, &kwds)) {
604            // got our args, and kwds...
605            PyObject *ret = PyObject_Call(pkgcore_atom_VersionMatch,
606                tup, kwds);
607            Py_DECREF(tup);
608            Py_XDECREF(kwds);
609            return ret;
610        }
611        // since we've been using SET_ITEM, and did _not_ incref op
612        // (stole temporarily), we have to wipe it now for the decref.
613        Py_DECREF(tup);
614        // since tup steals, that just wiped ver, and rev.
615    }
616    return NULL;
617}
618
619static inline PyObject *
620make_slot_restrict(PyObject *slot)
621{
622    PyObject *tup = PyTuple_New(PyTuple_GET_SIZE(slot));
623    if(!tup)
624        return NULL;
625
626    // whee;  convert 'em, basically a map statement.
627    // use args repeatedly to avoid allocation; the callee cannot modify it
628    // (they can technically, but that's massively broken behavior).
629   
630    Py_ssize_t idx;
631    for(idx=0; idx < PyTuple_GET_SIZE(slot); idx++) {
632        PyObject *s = PyTuple_GET_ITEM(slot, idx);
633        PyObject *tmp = PyObject_CallFunction(pkgcore_atom_StrExactMatch,
634            "O", s);
635        if(!tmp) {
636            Py_DECREF(tup);
637            return NULL;
638        }
639        PyTuple_SET_ITEM(tup, idx, tmp);
640    }
641    PyObject *tmp = PyObject_Call(pkgcore_atom_ValOr, tup, NULL);
642    Py_DECREF(tup);
643    if(tmp) {
644        PyObject *tmp2 = PyObject_CallFunction(pkgcore_atom_PackageRestrict,
645            "OO", pkgcore_atom_slot, tmp);
646        Py_DECREF(tmp);
647        tmp = tmp2;
648    }
649    return tmp;
650}
651
652static PyObject *
653make_use_val_restrict(PyObject *use)
654{
655    if(!PyTuple_CheckExact(use)) {
656        PyErr_SetString(PyExc_TypeError, "use must be None, or a tuple");
657        return NULL;
658    }
659    // fun one.
660    Py_ssize_t idx;
661    Py_ssize_t false_len = 0;
662    for(idx = 0; idx < PyTuple_GET_SIZE(use); idx++) {
663        if(!PyString_CheckExact(PyTuple_GET_ITEM(use, idx))) {
664            PyErr_SetString(PyExc_TypeError, "flags must be strings");
665            return NULL;
666        }
667        if('-' == *PyString_AS_STRING(PyTuple_GET_ITEM(use, idx))) {
668            false_len++;
669        }
670    }
671    if(!false_len) {
672        // easy case.
673        if(PyTuple_GET_SIZE(use) == 1) {
674            return PyObject_Call(pkgcore_atom_ContainmentMatch, use, NULL);
675        }
676        // slightly less easy.
677        PyObject *kwds = Py_BuildValue("{sO}", "all", Py_True);
678        if(kwds) {
679            PyObject *ret = PyObject_Call(pkgcore_atom_ContainmentMatch, use,
680                kwds);
681            Py_DECREF(kwds);
682            return ret;
683        }
684        return NULL;
685    }
686    // not so easy case.  need to split false use out, and make true use.
687
688    PyObject *enabled = NULL;
689    if(PyTuple_GET_SIZE(use) != false_len) {
690        enabled = PyTuple_New(PyTuple_GET_SIZE(use) - false_len);
691        if(!enabled)
692            return NULL;
693    }
694    PyObject *disabled = PyTuple_New(false_len);
695    if(!disabled) {
696        Py_XDECREF(enabled);
697        return NULL;
698    }
699    Py_ssize_t en_idx = 0, dis_idx = 0;
700    for(idx = 0; idx < PyTuple_GET_SIZE(use); idx++) {
701        PyObject *p = PyTuple_GET_ITEM(use, idx);
702        if('-' == *PyString_AS_STRING(p)) {
703            PyObject *s = PyString_FromStringAndSize(
704                PyString_AS_STRING(p) + 1, PyString_GET_SIZE(p) - 1);
705            if(!s) {
706                Py_XDECREF(enabled);
707                Py_DECREF(disabled);
708                return NULL;
709            }
710            PyTuple_SET_ITEM(disabled, dis_idx, s);
711            dis_idx++;
712        } else {
713            Py_INCREF(p);
714            PyTuple_SET_ITEM(enabled, en_idx, p);
715            en_idx++;
716        }
717    }
718    PyObject *kwds = PyDict_New();
719    if(kwds && (
720        PyDict_SetItemString(kwds, "negate", Py_True) ||
721        PyDict_SetItemString(kwds, "all", Py_True))) {
722        Py_CLEAR(kwds);
723    }
724    if(!kwds) {
725        // crappy.
726        Py_XDECREF(enabled);
727        Py_DECREF(disabled);
728        return NULL;
729    }
730    PyObject *dis_val = PyObject_Call(pkgcore_atom_ContainmentMatch, disabled,
731        kwds);
732    Py_DECREF(kwds);
733    Py_DECREF(disabled);
734    if(!dis_val) {
735        Py_DECREF(enabled);
736        return NULL;
737    }
738    PyObject *tmp;
739    if(enabled) {
740        kwds = PyDict_New();
741        if(kwds && PyDict_SetItemString(kwds, "all", Py_True)) {
742            Py_CLEAR(kwds);
743        }
744        if(!kwds) {
745            Py_DECREF(dis_val);
746            Py_DECREF(enabled);
747            return NULL;
748        }
749
750        PyObject *en_val = PyObject_Call(pkgcore_atom_ContainmentMatch,
751            enabled, kwds);
752        Py_DECREF(enabled);
753        Py_DECREF(kwds);
754        if(!en_val) {
755            Py_DECREF(dis_val);
756            return NULL;
757        }
758        tmp = PyObject_CallFunction(pkgcore_atom_ValAnd,
759            "OO", dis_val, en_val);
760        Py_DECREF(dis_val);
761        Py_DECREF(en_val);
762        if(!tmp) {
763            return NULL;
764        }
765    } else {
766        tmp = dis_val;
767    }
768    return tmp;
769}
770
771static PyObject *
772pkgcore_atom_getattr(PyObject *getattr_inst, PyObject *args)
773{
774    int required = 2;
775    int failed = 1;
776
777    PyObject *self = NULL, *attr = NULL;
778    if(!PyArg_ParseTuple(args, "OO", &self, &attr))
779        return NULL;
780
781    PyObject *op = NULL, *package = NULL, *category = NULL;
782    PyObject *use = NULL, *slot = NULL, *repo_id = NULL;
783    PyObject *tup = NULL, *tmp = NULL;
784
785    // prefer Py_EQ since cpythons string optimizes that case.
786    if(1 != PyObject_RichCompareBool(attr, pkgcore_atom_restrictions, Py_EQ)) {
787        PyErr_SetObject(PyExc_AttributeError, attr);
788        return NULL;
789    }
790   
791    #define MUST_LOAD(ptr, str)                     \
792    if(!((ptr) = PyObject_GetAttr(self, (str))))    \
793        return NULL;
794   
795    MUST_LOAD(op, pkgcore_atom_op);
796    MUST_LOAD(package, pkgcore_atom_package);
797    MUST_LOAD(category, pkgcore_atom_category);   
798    MUST_LOAD(use, pkgcore_atom_use);
799    MUST_LOAD(slot, pkgcore_atom_slot);
800    MUST_LOAD(repo_id, pkgcore_atom_repo_id);
801   
802    #undef MUST_LOAD
803
804    if(op != pkgcore_atom_op_none)
805        required++;
806    if(use != Py_None)
807        required++;   
808    if(slot != Py_None)
809        required++;
810    if(repo_id != Py_None)
811        required++;
812   
813    tup = PyTuple_New(required);
814    if(!tup)
815        goto pkgcore_atom_getattr_error;
816   
817    int idx = 0;
818    if(repo_id != Py_None) {
819        if(!(tmp = make_simple_restrict(pkgcore_atom_restrict_repo_id,
820            repo_id, pkgcore_atom_StrExactMatch)))
821            goto pkgcore_atom_getattr_error;
822        PyTuple_SET_ITEM(tup, 0, tmp);
823        idx++;
824    }
825   
826    if(!(tmp = make_simple_restrict(pkgcore_atom_package, package,
827        pkgcore_atom_StrExactMatch)))
828        goto pkgcore_atom_getattr_error;
829    PyTuple_SET_ITEM(tup, idx, tmp);
830    idx++;
831   
832    if(!(tmp = make_simple_restrict(pkgcore_atom_category, category,
833        pkgcore_atom_StrExactMatch)))
834        goto pkgcore_atom_getattr_error;
835    PyTuple_SET_ITEM(tup, idx, tmp);
836    idx++;
837   
838    if(op != pkgcore_atom_op_none) {
839        if(op == pkgcore_atom_op_glob) {
840            PyObject *tmp2 = PyObject_GetAttr(self, pkgcore_atom_fullver);
841            if(!tmp2) {
842                goto pkgcore_atom_getattr_error;
843            }
844            tmp = make_simple_restrict(pkgcore_atom_fullver, tmp2,
845                pkgcore_atom_StrGlobMatch);
846            Py_DECREF(tmp2);
847        } else {
848            tmp = make_version_restrict(self, op);
849        }
850        if(!tmp)
851            goto pkgcore_atom_getattr_error;
852        PyTuple_SET_ITEM(tup, idx, tmp);
853        idx++;
854    }
855    if(slot != Py_None) {
856        tmp = NULL;
857        if(!PyTuple_CheckExact(slot)) {
858            PyErr_SetString(PyExc_TypeError, "slot must be tuple or None");
859            goto pkgcore_atom_getattr_error;
860        }
861        if(PyTuple_GET_SIZE(slot) == 0) {
862            if(_PyTuple_Resize(&tup, PyTuple_GET_SIZE(tup) - 1))
863                goto pkgcore_atom_getattr_error;
864        } else {
865            if(1 == PyTuple_GET_SIZE(slot)) {
866                tmp = make_simple_restrict(pkgcore_atom_slot, slot,
867                    pkgcore_atom_StrExactMatch);
868            } else {
869                tmp = make_slot_restrict(slot);
870            }
871            if(!tmp)
872                goto pkgcore_atom_getattr_error;
873            PyTuple_SET_ITEM(tup, idx, tmp);
874        }
875        idx++;
876    }
877    if(use != Py_None) {
878        tmp = make_use_val_restrict(use);
879        if(!tmp)
880            goto pkgcore_atom_getattr_error;
881        PyObject *tmp2 = PyObject_CallFunction(pkgcore_atom_PackageRestrict,
882            "OO", pkgcore_atom_use, tmp);
883        Py_DECREF(tmp);
884        if(!tmp2)
885            goto pkgcore_atom_getattr_error;
886        PyTuple_SET_ITEM(tup, idx, tmp2);
887        idx++;
888    }
889    failed = 0;
890    pkgcore_atom_getattr_error:
891    Py_XDECREF(op);
892    Py_XDECREF(category);
893    Py_XDECREF(package);
894    Py_XDECREF(use);
895    Py_XDECREF(slot);
896    Py_XDECREF(repo_id);
897    if(failed)
898        Py_CLEAR(tup);
899    else {
900        if(PyObject_GenericSetAttr(self, pkgcore_atom_restrictions, tup)) {
901            Py_CLEAR(tup);
902        }
903    }
904    return tup;
905}
906
907PKGCORE_FUNC_BINDING("__init__", "pkgcore.ebuild._atom.__init__",
908    pkgcore_atom_init, METH_VARARGS|METH_KEYWORDS)
909PKGCORE_FUNC_BINDING("__getattr__", "pkgcore.ebuild._atom.__getattr__",
910    pkgcore_atom_getattr, METH_O|METH_COEXIST)
911
912PyDoc_STRVAR(
913    pkgcore_atom_documentation,
914    "cpython atom parsing functionality");
915
916static int
917load_external_objects()
918{
919    PyObject *s, *m = NULL;
920    #define LOAD_MODULE(char_p)             \
921    if(!(s = PyString_FromString(char_p)))  \
922        return 1;                           \
923    m = PyImport_Import(s);                 \
924    Py_DECREF(s);                           \
925    if(!m)                                  \
926        return 1;
927   
928    if(!pkgcore_atom_MalformedAtom_Exc) {
929        LOAD_MODULE("pkgcore.ebuild.errors");
930        pkgcore_atom_MalformedAtom_Exc = PyObject_GetAttrString(m,
931            "MalformedAtom");
932        Py_DECREF(m);
933        if(!pkgcore_atom_MalformedAtom_Exc) {
934            return 1;
935        }
936        m = NULL;
937    }
938
939    if(!pkgcore_atom_cpv_parse || !pkgcore_atom_InvalidCPV_Exc) {
940        LOAD_MODULE("pkgcore.ebuild.cpv");
941    }
942   
943    if(!pkgcore_atom_cpv_parse) {
944        pkgcore_atom_cpv_parse = PyObject_GetAttrString(m, "base_CPV");
945        if(!pkgcore_atom_cpv_parse)
946            return 1;
947    }
948    if(!pkgcore_atom_InvalidCPV_Exc) {
949        pkgcore_atom_InvalidCPV_Exc = PyObject_GetAttrString(m, "InvalidCPV");
950        if(!pkgcore_atom_InvalidCPV_Exc)
951            return 1;
952    }
953    if(m) {
954        Py_DECREF(m);
955    }
956   
957    if(!pkgcore_atom_VersionMatch) {
958        LOAD_MODULE("pkgcore.ebuild.atom_restricts");
959        pkgcore_atom_VersionMatch = PyObject_GetAttrString(m,
960            "VersionMatch");
961        Py_DECREF(m);
962    }
963    if(!pkgcore_atom_StrExactMatch || !pkgcore_atom_StrGlobMatch ||
964        !pkgcore_atom_ContainmentMatch || !pkgcore_atom_ValAnd) {
965        LOAD_MODULE("pkgcore.restrictions.values");
966    } else
967        m = NULL;
968   
969    #define LOAD_ATTR(ptr, name)                        \
970    if(!(ptr) && !                                      \
971        ((ptr) = PyObject_GetAttrString(m, (name)))) {  \
972        Py_DECREF(m);                                   \
973        return 1;                                       \
974    }
975    LOAD_ATTR(pkgcore_atom_StrExactMatch, "StrExactMatch");
976    LOAD_ATTR(pkgcore_atom_StrGlobMatch, "StrGlobMatch");
977    LOAD_ATTR(pkgcore_atom_ContainmentMatch, "ContainmentMatch");
978    LOAD_ATTR(pkgcore_atom_ValAnd, "AndRestriction");
979    LOAD_ATTR(pkgcore_atom_ValOr, "OrRestriction");
980    if(m) {
981        Py_DECREF(m);
982    }
983    if(!pkgcore_atom_PackageRestrict) {
984        LOAD_MODULE("pkgcore.restrictions.packages");
985        LOAD_ATTR(pkgcore_atom_PackageRestrict, "PackageRestriction");
986        Py_DECREF(m);
987    }
988    #undef LOAD_ATTR
989    #undef LOAD_MODULE
990    return 0;
991}
992
993
994PyMODINIT_FUNC
995init_atom()
996{
997    PyObject *m = Py_InitModule3("_atom", NULL, pkgcore_atom_documentation);
998    if (!m)
999        return;
1000
1001    // first get the exceptions we use.
1002    if(load_external_objects())
1003        return;
1004
1005    if(PyType_Ready(&pkgcore_atom_init_type) < 0)
1006        return;
1007
1008    if(PyType_Ready(&pkgcore_atom_getattr_type) < 0)
1009        return;
1010
1011    #define load_string(ptr, str)                   \
1012        if (!(ptr)) {                               \
1013            (ptr) = PyString_FromString(str);       \
1014            if(!(ptr))                              \
1015                return;                             \
1016        }
1017
1018    load_string(pkgcore_atom_cpvstr,        "cpvstr");
1019    load_string(pkgcore_atom_key,           "key");
1020    load_string(pkgcore_atom_category,      "category");
1021    load_string(pkgcore_atom_package,       "package");
1022    load_string(pkgcore_atom_version,       "version");
1023    load_string(pkgcore_atom_revision,      "revision");
1024    load_string(pkgcore_atom_fullver,       "fullver");
1025    load_string(pkgcore_atom_hash,          "hash");
1026    load_string(pkgcore_atom_use,           "use");
1027    load_string(pkgcore_atom_slot,          "slot");
1028    load_string(pkgcore_atom_repo_id,       "repo_id");
1029    load_string(pkgcore_atom_restrict_repo_id,
1030                                            "repo.repo_id");
1031    load_string(pkgcore_atom_op_glob,       "=*");
1032    load_string(pkgcore_atom_blocks,        "blocks");
1033    load_string(pkgcore_atom_op,            "op");
1034    load_string(pkgcore_atom_negate_vers,   "negate_vers");
1035    load_string(pkgcore_atom_restrictions,  "restrictions");
1036
1037    load_string(pkgcore_atom_op_ge,         ">=");
1038    load_string(pkgcore_atom_op_gt,         ">");
1039    load_string(pkgcore_atom_op_le,         "<=");
1040    load_string(pkgcore_atom_op_lt,         "<");
1041    load_string(pkgcore_atom_op_eq,         "=");
1042    load_string(pkgcore_atom_op_droprev,    "~");
1043    load_string(pkgcore_atom_op_none,       "");
1044    #undef load_string
1045
1046    PyObject *d = PyDict_New();
1047    if(!d)
1048        return;
1049
1050    PyObject *overrides = PyDict_New();
1051    if(!overrides)
1052        return;
1053    PyObject *tmp = PyType_GenericNew(&pkgcore_atom_init_type, NULL, NULL);
1054    if(!tmp)
1055        return;
1056    if(PyDict_SetItemString(overrides, "__init__", tmp))
1057        return;
1058    tmp = PyType_GenericNew(&pkgcore_atom_getattr_type, NULL, NULL);
1059    if(!tmp)
1060        return;
1061    if(PyDict_SetItemString(overrides, "__getattr__", tmp))
1062        return;
1063    PyModule_AddObject(m, "overrides", overrides);
1064   
1065    if (PyErr_Occurred()) {
1066        Py_FatalError("can't initialize module _atom");
1067    }
1068}
Note: See TracBrowser for help on using the browser.