- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

# python/rpmfts-py.c

Go to the documentation of this file.

    00001
    00005 #include "system.h"
    00006
    00007 #include "structmember.h"
    00008
    00009 #ifdef __LCLINT__
    00010 #undef  PyObject_HEAD
    00011 #define PyObject_HEAD   int _PyObjectHead;
    00012 #endif
    00013
    00014 #include <fts.h>
    00015
    00016 #include "rpmfts-py.h"
    00017
    00018 #include <rpmio.h>      /* XXX _free */
    00019
    00020 #include "debug.h"
    00021
    00022 /*@unchecked@*/
    00023 static int _rpmfts_debug = 1;
    00024
    00025 #define infoBit(_ix)    (1 << (((unsigned)(_ix)) & 0x1f))
    00026
    00027 static const char * ftsInfoStrings[] = {
    00028     "UNKNOWN",
    00029     "D",
    00030     "DC",
    00031     "DEFAULT",
    00032     "DNR",
    00033     "DOT",
    00034     "DP",
    00035     "ERR",
    00036     "F",
    00037     "INIT",
    00038     "NS",
    00039     "NSOK",
    00040     "SL",
    00041     "SLNONE",
    00042     "W",
    00043 };
    00044
    00045 /*@observer@*/
    00046 static const char * ftsInfoStr(int fts_info)
    00047         /*@*/
    00048 {
    00049     if (!(fts_info >= 1 && fts_info <= 14))
    00050         fts_info = 0;
    00051     return ftsInfoStrings[ fts_info ];
    00052 }
    00053
    00054 #define RPMFTS_CLOSE            0
    00055 #define RPMFTS_OPEN             1
    00056 #define RPMFTS_OPEN_LAZY        2
    00057
    00058 static void
    00059 rpmfts_debug (const char * msg, rpmftsObject * s)
    00060 {
    00061     if (_rpmfts_debug == 0)
    00062         return;
    00063     if (msg)
    00064         fprintf(stderr, "*** %s(%p)", msg, s);
    00065     if (s)
    00066         fprintf(stderr, " %d %d ftsp %p fts %p\n", s->ob_refcnt, s->active, s->ftsp, s->fts);
    00067 }
    00068
    00069 static int
    00070 rpmfts_initialize(rpmftsObject * s, const char * root, int options, int ignore)
    00071         /*@modifies s @*/
    00072 {
    00073     int ac = 1;
    00074     size_t nb;
    00075
    00076 /*@-branchstate@*/
    00077     if (root == NULL)   root = "/";
    00078 /*@=branchstate@*/
    00079     if (options == -1)  options = (FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOSTAT);
    00080     if (ignore == -1)   ignore = infoBit(FTS_DP);
    00081
    00082     s->roots = _free(s->roots);
    00083
    00084     nb = (ac + 1) * sizeof(*s->roots);
    00085     nb += strlen(root) + 1;
    00086     s->roots = malloc(nb);
    00087     if (s->roots != NULL) {
    00088         char *t = (char *) &s->roots[ac + 1];
    00089         s->roots[0] = t;
    00090         s->roots[ac] = NULL;
    00091         (void) stpcpy(t, root);
    00092     }
    00093
    00094     s->options = options;
    00095     s->ignore = ignore;
    00096     s->compare = NULL;
    00097
    00098     s->ftsp = NULL;
    00099     s->fts = NULL;
    00100     s->active = RPMFTS_CLOSE;
    00101
    00102     return 0;
    00103
    00104 }
    00105
    00106 static int
    00107 rpmfts_state(rpmftsObject * s, int nactive)
    00108         /*@modifies s @*/
    00109 {
    00110     int rc = 0;
    00111
    00112 rpmfts_debug("rpmfts_state", s);
    00113     switch (nactive) {
    00114     case RPMFTS_CLOSE:
    00115         if (s->ftsp != NULL) {
    00116             Py_BEGIN_ALLOW_THREADS
    00117             rc = Fts_close(s->ftsp);
    00118             Py_END_ALLOW_THREADS
    00119             s->ftsp = NULL;
    00120         }
    00121         break;
    00122     case RPMFTS_OPEN_LAZY:
    00123     case RPMFTS_OPEN:
    00124         if (s->ftsp == NULL) {
    00125             Py_BEGIN_ALLOW_THREADS
    00126             s->ftsp = Fts_open((char *const *)s->roots, s->options, (int (*)(const FTSENT **, const FTSENT **))s->compare);
    00127             Py_END_ALLOW_THREADS
    00128         }
    00129         break;
    00130     }
    00131     s->fts = NULL;
    00132     s->active = nactive;
    00133     return rc;
    00134 }
    00135
    00136 /*@null@*/
    00137 static PyObject *
    00138 rpmfts_step(rpmftsObject * s)
    00139         /*@modifies s @*/
    00140 {
    00141     PyObject * result = NULL;
    00142     int xx;
    00143
    00144 rpmfts_debug("rpmfts_step", s);
    00145     if (s->ftsp == NULL)
    00146         return NULL;
    00147
    00148     do {
    00149         Py_BEGIN_ALLOW_THREADS
    00150         s->fts = Fts_read(s->ftsp);
    00151         Py_END_ALLOW_THREADS
    00152     } while (s->fts && (infoBit(s->fts->fts_info) & s->ignore));
    00153
    00154     if (s->fts != NULL) {
    00155         Py_INCREF(s);
    00156         result = (PyObject *)s;
    00157     } else {
    00158         if (s->active == RPMFTS_OPEN_LAZY)
    00159             xx = rpmfts_state(s, RPMFTS_CLOSE);
    00160         s->active = RPMFTS_CLOSE;
    00161     }
    00162
    00163     return result;
    00164 }
    00165
    00166 /* ---------- */
    00167
    00178 /*@null@*/
    00179 static PyObject *
    00180 rpmfts_Debug(/*@unused@*/ rpmftsObject * s, PyObject * args, PyObject * kwds)
    00181         /*@globals _Py_NoneStruct @*/
    00182         /*@modifies _Py_NoneStruct @*/
    00183 {
    00184     char * kwlist[] = {"debugLevel", NULL};
    00185
    00186     if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:Debug", kwlist,
    00187             &_rpmfts_debug))
    00188         return NULL;
    00189
    00190     Py_INCREF(Py_None);
    00191     return Py_None;
    00192 }
    00193
    00194 /*@null@*/
    00195 static PyObject *
    00196 rpmfts_Open(rpmftsObject * s, PyObject * args, PyObject * kwds)
    00197         /*@modifies s @*/
    00198 {
    00199     char * root = NULL;
    00200     int options = -1;
    00201     int ignore = -1;
    00202     int xx;
    00203     /* XXX: there's bound to be a better name than "ignore" */
    00204     char * kwlist[] = {"root", "options", "ignore", NULL};
    00205
    00206 rpmfts_debug("rpmfts_Open", s);
    00207     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sii:Open", kwlist,
    00208             &root, &options, &ignore))
    00209         return NULL;
    00210
    00211     xx = rpmfts_initialize(s, root, options, ignore);
    00212     xx = rpmfts_state(s, RPMFTS_OPEN);
    00213
    00214     return (PyObject *)s;
    00215 }
    00216
    00217 /*@null@*/
    00218 static PyObject *
    00219 rpmfts_Read(rpmftsObject * s)
    00220         /*@globals _Py_NoneStruct @*/
    00221         /*@modifies s, _Py_NoneStruct @*/
    00222 {
    00223     PyObject * result;
    00224
    00225 rpmfts_debug("rpmfts_Read", s);
    00226
    00227     result = rpmfts_step(s);
    00228
    00229     if (result == NULL) {
    00230         Py_INCREF(Py_None);
    00231         return Py_None;
    00232     }
    00233
    00234     return result;
    00235 }
    00236
    00237 /*@null@*/
    00238 static PyObject *
    00239 rpmfts_Children(rpmftsObject * s, PyObject * args, PyObject * kwds)
    00240         /*@globals _Py_NoneStruct @*/
    00241         /*@modifies s, _Py_NoneStruct @*/
    00242 {
    00243     int instr;
    00244     char * kwlist[] = {"instructions", NULL};
    00245
    00246 rpmfts_debug("rpmfts_Children", s);
    00247     if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:Children", kwlist, &instr))
    00248         return NULL;
    00249
    00250     if (!(s && s->ftsp))
    00251         return NULL;
    00252
    00253     Py_BEGIN_ALLOW_THREADS
    00254     s->fts = Fts_children(s->ftsp, instr);
    00255     Py_END_ALLOW_THREADS
    00256
    00257     Py_INCREF(Py_None);
    00258     return Py_None;
    00259 }
    00260
    00261 /*@null@*/
    00262 static PyObject *
    00263 rpmfts_Close(rpmftsObject * s)
    00264         /*@modifies s @*/
    00265 {
    00266
    00267 rpmfts_debug("rpmfts_Close", s);
    00268
    00269     return Py_BuildValue("i", rpmfts_state(s, RPMFTS_CLOSE));
    00270 }
    00271
    00272 /*@null@*/
    00273 static PyObject *
    00274 rpmfts_Set(rpmftsObject * s, PyObject * args, PyObject * kwds)
    00275         /*@modifies s @*/
    00276 {
    00277     int instr = 0;
    00278     int rc = 0;
    00279     char * kwlist[] = {"instructions", NULL};
    00280
    00281 rpmfts_debug("rpmfts_Set", s);
    00282     if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:Set", kwlist, &instr))
    00283         return NULL;
    00284
    00285     if (s->ftsp && s->fts)
    00286         rc = Fts_set(s->ftsp, s->fts, instr);
    00287
    00288     return Py_BuildValue("i", rc);
    00289 }
    00294 /*@-fullinitblock@*/
    00295 /*@unchecked@*/ /*@observer@*/
    00296 static struct PyMethodDef rpmfts_methods[] = {
    00297     {"Debug",   (PyCFunction)rpmfts_Debug,      METH_VARARGS|METH_KEYWORDS,
    00298         NULL},
    00299     {"open",    (PyCFunction)rpmfts_Open,       METH_VARARGS|METH_KEYWORDS,
    00300         NULL},
    00301     {"read",    (PyCFunction)rpmfts_Read,       METH_NOARGS,
    00302         NULL},
    00303     {"children",(PyCFunction)rpmfts_Children,   METH_VARARGS|METH_KEYWORDS,
    00304         NULL},
    00305     {"close",   (PyCFunction)rpmfts_Close,      METH_NOARGS,
    00306         NULL},
    00307     {"set",     (PyCFunction)rpmfts_Set,        METH_VARARGS|METH_KEYWORDS,
    00308         NULL},
    00309     {NULL,              NULL}           /* sentinel */
    00310 };
    00311 /*@=fullinitblock@*/
    00312
    00313 /* ---------- */
    00314
    00315 static PyMemberDef rpmfts_members[] = {
    00316     {"__dict__",T_OBJECT,offsetof(rpmftsObject, md_dict),       READONLY,
    00317         NULL},
    00318     {"callbacks",T_OBJECT,offsetof(rpmftsObject, callbacks),    0,
    00319 "Callback dictionary per fts_info state: FTS_{D|DC|DEFAULT|DNR|DOT|DP|ERR|F|INIT|NS|NSOK|SL|SLNONE|W}"},
    00320     {"options", T_INT,  offsetof(rpmftsObject, options),        0,
    00321 "Option bit(s): FTS_{COMFOLLOW|LOGICAL|NOCHDIR|NOSTAT|PHYSICAL|SEEDOT|XDEV}"},
    00322     {"ignore",  T_INT,  offsetof(rpmftsObject, ignore),         0,
    00323 "Ignore bit(s): (1 << info) with info one of FTS_{D|DC|DEFAULT|DNR|DOT|DP|ERR|F|INIT|NS|NSOK|SL|SLNONE|W}"},
    00324     {NULL, 0, 0, 0, NULL}
    00325 };
    00326
    00327 static PyObject * rpmfts_getattro(PyObject * o, PyObject * n)
    00328         /*@*/
    00329 {
    00330 rpmfts_debug("rpmfts_getattro", (rpmftsObject *)o);
    00331     return PyObject_GenericGetAttr(o, n);
    00332 }
    00333
    00334 static int rpmfts_setattro(PyObject * o, PyObject * n, PyObject * v)
    00335         /*@*/
    00336 {
    00337 rpmfts_debug("rpmfts_setattro", (rpmftsObject *)o);
    00338     return PyObject_GenericSetAttr(o, n, v);
    00339 }
    00340
    00341 /* ---------- */
    00342
    00343 static PyObject *
    00344 rpmfts_iter(rpmftsObject * s)
    00345         /*@*/
    00346 {
    00347     Py_INCREF(s);
    00348     return (PyObject *)s;
    00349 }
    00350
    00351 /*@null@*/
    00352 static PyObject *
    00353 rpmfts_iternext(rpmftsObject * s)
    00354         /*@modifies s @*/
    00355 {
    00356     int xx;
    00357
    00358     /* Reset loop indices on 1st entry. */
    00359     if (s->active == RPMFTS_CLOSE)
    00360         xx = rpmfts_state(s, RPMFTS_OPEN_LAZY);
    00361     return rpmfts_step(s);
    00362 }
    00363
    00364 /* ---------- */
    00365
    00366 static void rpmfts_free(/*@only@*/ PyObject * s)
    00367         /*@*/
    00368 {
    00369     _PyObject_GC_Del(s);
    00370 }
    00371
    00372 static PyObject * rpmfts_alloc(PyTypeObject * type, int nitems)
    00373         /*@*/
    00374 {
    00375     return PyType_GenericAlloc(type, nitems);
    00376 }
    00377
    00378 static void rpmfts_dealloc(/*@only@*/ rpmftsObject * s)
    00379         /*@modifies s @*/
    00380 {
    00381     int xx;
    00382
    00383 rpmfts_debug("rpmfts_dealloc", s);
    00384     xx = rpmfts_state(s, RPMFTS_CLOSE);
    00385
    00386     s->roots = _free(s->roots);
    00387
    00388     PyObject_GC_UnTrack((PyObject *)s);
    00389     if (s->md_dict != NULL) {
    00390         _PyModule_Clear((PyObject *)s);
    00391         Py_DECREF(s->md_dict);
    00392     }
    00393     if (s->callbacks != NULL) {
    00394         _PyModule_Clear((PyObject *)s);
    00395         Py_DECREF(s->callbacks);
    00396     }
    00397     _PyObject_GC_Del((PyObject *)s);
    00398 }
    00399
    00400 static int rpmfts_init(rpmftsObject * s, PyObject *args, PyObject *kwds)
    00401         /*@modifies s @*/
    00402 {
    00403     char * root = NULL;
    00404     int options = -1;
    00405     int ignore = -1;
    00406     char * kwlist[] = {"root", "options", "ignore", NULL};
    00407
    00408 rpmfts_debug("rpmfts_init", s);
    00409     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sii:rpmfts_init", kwlist,
    00410             &root, &options, &ignore))
    00411         return -1;
    00412
    00413     return rpmfts_initialize(s, root, options, ignore);
    00414 }
    00415
    00416 /*@null@*/
    00417 static PyObject * rpmfts_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
    00418         /*@*/
    00419 {
    00420     rpmftsObject *s;
    00421     PyObject *o;
    00422     PyObject *n = NULL;
    00423     char * kwlist[] = {0};
    00424
    00425     /* All the other _new() functions claim to be _init in their errors...*/
    00426     if (!PyArg_ParseTupleAndKeywords(args, kwds, ":rpmfts_new", kwlist))
    00427         return NULL;
    00428
    00429     if ((s = PyObject_GC_New(rpmftsObject, type)) == NULL)
    00430         return NULL;
    00431 rpmfts_debug("rpmfts_new", s);
    00432
    00433     s->md_dict = PyDict_New();
    00434     if (s->md_dict == NULL)
    00435         goto fail;
    00436     s->callbacks = PyDict_New();
    00437     if (s->md_dict == NULL)
    00438         goto fail;
    00439     if (type->tp_name) {
    00440         const char * name;
    00441         if ((name = strrchr(type->tp_name, '.')) != NULL)
    00442             name++;
    00443         else
    00444             name = type->tp_name;
    00445         n = PyString_FromString(name);
    00446     }
    00447     if (n != NULL && PyDict_SetItemString(s->md_dict, "__name__", n) != 0)
    00448         goto fail;
    00449     if (PyDict_SetItemString(s->md_dict, "__doc__", Py_None) != 0)
    00450         goto fail;
    00451
    00452 #define CONSTANT(_v) \
    00453     PyDict_SetItemString(s->md_dict, #_v, o=PyInt_FromLong(_v)); Py_DECREF(o)
    00454
    00455     CONSTANT(FTS_ROOTPARENTLEVEL);
    00456     CONSTANT(FTS_ROOTLEVEL);
    00457
    00458     CONSTANT(FTS_COMFOLLOW);
    00459     CONSTANT(FTS_LOGICAL);
    00460     CONSTANT(FTS_NOCHDIR);
    00461     CONSTANT(FTS_NOSTAT);
    00462     CONSTANT(FTS_PHYSICAL);
    00463     CONSTANT(FTS_SEEDOT);
    00464     CONSTANT(FTS_XDEV);
    00465     CONSTANT(FTS_WHITEOUT);
    00466     CONSTANT(FTS_OPTIONMASK);
    00467
    00468     CONSTANT(FTS_NAMEONLY);
    00469     CONSTANT(FTS_STOP);
    00470
    00471     CONSTANT(FTS_D);
    00472     CONSTANT(FTS_DC);
    00473     CONSTANT(FTS_DEFAULT);
    00474     CONSTANT(FTS_DNR);
    00475     CONSTANT(FTS_DOT);
    00476     CONSTANT(FTS_DP);
    00477     CONSTANT(FTS_ERR);
    00478     CONSTANT(FTS_F);
    00479     CONSTANT(FTS_NS);
    00480     CONSTANT(FTS_NSOK);
    00481     CONSTANT(FTS_SL);
    00482     CONSTANT(FTS_SLNONE);
    00483     CONSTANT(FTS_W);
    00484
    00485     CONSTANT(FTS_DONTCHDIR);
    00486     CONSTANT(FTS_SYMFOLLOW);
    00487
    00488     CONSTANT(FTS_AGAIN);
    00489     CONSTANT(FTS_FOLLOW);
    00490     CONSTANT(FTS_NOINSTR);
    00491     CONSTANT(FTS_SKIP);
    00492
    00493     s->roots = NULL;
    00494     s->compare = NULL;
    00495     s->ftsp = NULL;
    00496     s->fts = NULL;
    00497
    00498     Py_XDECREF(n);
    00499     PyObject_GC_Track((PyObject *)s);
    00500     return (PyObject *)s;
    00501
    00502  fail:
    00503     Py_XDECREF(n);
    00504     Py_DECREF(s);
    00505     return NULL;
    00506 }
    00507
    00508 static int rpmfts_traverse(rpmftsObject * s, visitproc visit, void * arg)
    00509         /*@*/
    00510 {
    00511     if (s->md_dict != NULL)
    00512         return visit(s->md_dict, arg);
    00513     if (s->callbacks != NULL)
    00514         return visit(s->callbacks, arg);
    00515     return 0;
    00516 }
    00517
    00518 static int rpmfts_print(rpmftsObject * s,  FILE * fp, /*@unused@*/ int flags)
    00519         /*@globals fileSystem @*/
    00520         /*@modifies fp, fileSystem @*/
    00521 {
    00522     static int indent = 2;
    00523
    00524     if (!(s != NULL && s->ftsp != NULL && s->fts != NULL))
    00525         return -1;
    00526     fprintf(fp, "FTS_%-7s %*s%s", ftsInfoStr(s->fts->fts_info),
    00527         indent * (s->fts->fts_level < 0 ? 0 : s->fts->fts_level), "",
    00528         s->fts->fts_name);
    00529     return 0;
    00530 }
    00531
    00534 /*@unchecked@*/ /*@observer@*/
    00535 static char rpmfts_doc[] =
    00536 "";
    00537
    00540 /*@-fullinitblock@*/
    00541 PyTypeObject rpmfts_Type = {
    00542         PyObject_HEAD_INIT(&PyType_Type)
    00543         0,                              /* ob_size */
    00544         "rpm.fts",                      /* tp_name */
    00545         sizeof(rpmftsObject),           /* tp_size */
    00546         0,                              /* tp_itemsize */
    00547         /* methods */
    00548         (destructor) rpmfts_dealloc,    /* tp_dealloc */
    00549         (printfunc) rpmfts_print,       /* tp_print */
    00550         (getattrfunc)0,                 /* tp_getattr */
    00551         (setattrfunc)0,                 /* tp_setattr */
    00552         (cmpfunc)0,                     /* tp_compare */
    00553         (reprfunc)0,                    /* tp_repr */
    00554         0,                              /* tp_as_number */
    00555         0,                              /* tp_as_sequence */
    00556         0,                              /* tp_as_mapping */
    00557         (hashfunc)0,                    /* tp_hash */
    00558         (ternaryfunc)0,                 /* tp_call */
    00559         (reprfunc)0,                    /* tp_str */
    00560         (getattrofunc) rpmfts_getattro, /* tp_getattro */
    00561         (setattrofunc) rpmfts_setattro, /* tp_setattro */
    00562         0,                              /* tp_as_buffer */
    00563         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
    00564         rpmfts_doc,                     /* tp_doc */
    00565         (traverseproc) rpmfts_traverse, /* tp_traverse */
    00566         0,                              /* tp_clear */
    00567         0,                              /* tp_richcompare */
    00568         0,                              /* tp_weaklistoffset */
    00569         (getiterfunc) rpmfts_iter,      /* tp_iter */
    00570         (iternextfunc) rpmfts_iternext, /* tp_iternext */
    00571         rpmfts_methods,                 /* tp_methods */
    00572         rpmfts_members,                 /* tp_members */
    00573         0,                              /* tp_getset */
    00574         0,                              /* tp_base */
    00575         0,                              /* tp_dict */
    00576         0,                              /* tp_descr_get */
    00577         0,                              /* tp_descr_set */
    00578         offsetof(rpmftsObject, md_dict),/* tp_dictoffset */
    00579         (initproc) rpmfts_init,         /* tp_init */
    00580         rpmfts_alloc,                   /* tp_alloc */
    00581         rpmfts_new,                     /* tp_new */
    00582         (freefunc) rpmfts_free,         /* tp_free */
    00583         0,                              /* tp_is_gc */
    00584 };
    00585 /*@=fullinitblock@*/