Main Page | Modules | Data Structures | File List | Data Fields | Globals | Related Pages

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 <rpmlib.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(__FUNCTION__, 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(__FUNCTION__, 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(__FUNCTION__, 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(__FUNCTION__, 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(__FUNCTION__, 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(__FUNCTION__, 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(__FUNCTION__, 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(__FUNCTION__, (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(__FUNCTION__, (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(__FUNCTION__, 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(__FUNCTION__, 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(__FUNCTION__, 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         rpmfts_free,                    /* tp_free */
00583         0,                              /* tp_is_gc */
00584 };
00585 /*@=fullinitblock@*/

Generated on Sat Oct 1 16:48:18 2011 for rpm by  doxygen 1.4.4