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

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 
00174 /*@null@*/
00175 static PyObject *
00176 rpmfts_Debug(/*@unused@*/ rpmftsObject * s, PyObject * args)
00177         /*@globals _Py_NoneStruct @*/
00178         /*@modifies _Py_NoneStruct @*/
00179 {
00180     if (!PyArg_ParseTuple(args, "i:Debug", &_rpmfts_debug))
00181         return NULL;
00182 
00183     Py_INCREF(Py_None);
00184     return Py_None;
00185 }
00186 
00187 /*@null@*/
00188 static PyObject *
00189 rpmfts_Open(rpmftsObject * s, PyObject * args)
00190         /*@modifies s @*/
00191 {
00192     char * root = NULL;
00193     int options = -1;
00194     int ignore = -1;
00195     int xx;
00196 
00197 rpmfts_debug(__FUNCTION__, s);
00198     if (!PyArg_ParseTuple(args, "|sii:Open", &root, &options, &ignore))
00199         return NULL;
00200 
00201     xx = rpmfts_initialize(s, root, options, ignore);
00202     xx = rpmfts_state(s, RPMFTS_OPEN);
00203 
00204     return (PyObject *)s;
00205 }
00206 
00207 /*@null@*/
00208 static PyObject *
00209 rpmfts_Read(rpmftsObject * s, PyObject * args)
00210         /*@globals _Py_NoneStruct @*/
00211         /*@modifies s, _Py_NoneStruct @*/
00212 {
00213     PyObject * result;
00214 
00215 rpmfts_debug(__FUNCTION__, s);
00216     if (!PyArg_ParseTuple(args, ":Read")) return NULL;
00217 
00218     result = rpmfts_step(s);
00219 
00220     if (result == NULL) {
00221         Py_INCREF(Py_None);
00222         return Py_None;
00223     }
00224 
00225     return result;
00226 }
00227 
00228 /*@null@*/
00229 static PyObject *
00230 rpmfts_Children(rpmftsObject * s, PyObject * args)
00231         /*@globals _Py_NoneStruct @*/
00232         /*@modifies s, _Py_NoneStruct @*/
00233 {
00234     int instr;
00235 
00236 rpmfts_debug(__FUNCTION__, s);
00237     if (!PyArg_ParseTuple(args, "i:Children", &instr)) return NULL;
00238 
00239     if (!(s && s->ftsp))
00240         return NULL;
00241 
00242     Py_BEGIN_ALLOW_THREADS
00243     s->fts = Fts_children(s->ftsp, instr);
00244     Py_END_ALLOW_THREADS
00245 
00246     Py_INCREF(Py_None);
00247     return Py_None;
00248 }
00249 
00250 /*@null@*/
00251 static PyObject *
00252 rpmfts_Close(rpmftsObject * s, PyObject * args)
00253         /*@modifies s @*/
00254 {
00255 
00256 rpmfts_debug(__FUNCTION__, s);
00257     if (!PyArg_ParseTuple(args, ":Close")) return NULL;
00258 
00259     return Py_BuildValue("i", rpmfts_state(s, RPMFTS_CLOSE));
00260 }
00261 
00262 /*@null@*/
00263 static PyObject *
00264 rpmfts_Set(rpmftsObject * s, PyObject * args)
00265         /*@modifies s @*/
00266 {
00267     int instr = 0;
00268     int rc = 0;
00269 
00270 rpmfts_debug(__FUNCTION__, s);
00271     if (!PyArg_ParseTuple(args, "i:Set", &instr)) return NULL;
00272 
00273     if (s->ftsp && s->fts)
00274         rc = Fts_set(s->ftsp, s->fts, instr);
00275 
00276     return Py_BuildValue("i", rc);
00277 }
00278 
00281 /*@-fullinitblock@*/
00282 /*@unchecked@*/ /*@observer@*/
00283 static struct PyMethodDef rpmfts_methods[] = {
00284     {"Debug",   (PyCFunction)rpmfts_Debug,      METH_VARARGS,
00285         NULL},
00286     {"open",    (PyCFunction)rpmfts_Open,       METH_VARARGS,
00287         NULL},
00288     {"read",    (PyCFunction)rpmfts_Read,       METH_VARARGS,
00289         NULL},
00290     {"children",(PyCFunction)rpmfts_Children,   METH_VARARGS,
00291         NULL},
00292     {"close",   (PyCFunction)rpmfts_Close,      METH_VARARGS,
00293         NULL},
00294     {"set",     (PyCFunction)rpmfts_Set,        METH_VARARGS,
00295         NULL},
00296     {NULL,              NULL}           /* sentinel */
00297 };
00298 /*@=fullinitblock@*/
00299 
00300 /* ---------- */
00301 
00302 static PyMemberDef rpmfts_members[] = {
00303     {"__dict__",T_OBJECT,offsetof(rpmftsObject, md_dict),       READONLY,
00304         NULL},
00305     {"callbacks",T_OBJECT,offsetof(rpmftsObject, callbacks),    0,
00306 "Callback dictionary per fts_info state: FTS_{D|DC|DEFAULT|DNR|DOT|DP|ERR|F|INIT|NS|NSOK|SL|SLNONE|W}"},
00307     {"options", T_INT,  offsetof(rpmftsObject, options),        0,
00308 "Option bit(s): FTS_{COMFOLLOW|LOGICAL|NOCHDIR|NOSTAT|PHYSICAL|SEEDOT|XDEV}"},
00309     {"ignore",  T_INT,  offsetof(rpmftsObject, ignore),         0,
00310 "Ignore bit(s): (1 << info) with info one of FTS_{D|DC|DEFAULT|DNR|DOT|DP|ERR|F|INIT|NS|NSOK|SL|SLNONE|W}"},
00311     {NULL, 0, 0, 0, NULL}
00312 };
00313 
00314 static PyObject * rpmfts_getattro(PyObject * o, PyObject * n)
00315         /*@*/
00316 {
00317 rpmfts_debug(__FUNCTION__, (rpmftsObject *)o);
00318     return PyObject_GenericGetAttr(o, n);
00319 }
00320 
00321 static int rpmfts_setattro(PyObject * o, PyObject * n, PyObject * v)
00322         /*@*/
00323 {
00324 rpmfts_debug(__FUNCTION__, (rpmftsObject *)o);
00325     return PyObject_GenericSetAttr(o, n, v);
00326 }
00327 
00328 /* ---------- */
00329 
00330 static PyObject *
00331 rpmfts_iter(rpmftsObject * s)
00332         /*@*/
00333 {
00334     Py_INCREF(s);
00335     return (PyObject *)s;
00336 }
00337 
00338 /*@null@*/
00339 static PyObject *
00340 rpmfts_iternext(rpmftsObject * s)
00341         /*@modifies s @*/
00342 {
00343     int xx;
00344 
00345     /* Reset loop indices on 1st entry. */
00346     if (s->active == RPMFTS_CLOSE)
00347         xx = rpmfts_state(s, RPMFTS_OPEN_LAZY);
00348     return rpmfts_step(s);
00349 }
00350 
00351 /* ---------- */
00352 
00353 static void rpmfts_free(/*@only@*/ PyObject * s)
00354         /*@*/
00355 {
00356     _PyObject_GC_Del(s);
00357 }
00358 
00359 static PyObject * rpmfts_alloc(PyTypeObject * type, int nitems)
00360         /*@*/
00361 {
00362     return PyType_GenericAlloc(type, nitems);
00363 }
00364 
00365 static void rpmfts_dealloc(/*@only@*/ rpmftsObject * s)
00366         /*@modifies s @*/
00367 {
00368     int xx;
00369 
00370 rpmfts_debug(__FUNCTION__, s);
00371     xx = rpmfts_state(s, RPMFTS_CLOSE);
00372 
00373     s->roots = _free(s->roots);
00374 
00375     PyObject_GC_UnTrack((PyObject *)s);
00376     if (s->md_dict != NULL) {
00377         _PyModule_Clear((PyObject *)s);
00378         Py_DECREF(s->md_dict);
00379     }
00380     if (s->callbacks != NULL) {
00381         _PyModule_Clear((PyObject *)s);
00382         Py_DECREF(s->callbacks);
00383     }
00384     _PyObject_GC_Del((PyObject *)s);
00385 }
00386 
00387 static int rpmfts_init(rpmftsObject * s, PyObject *args, PyObject *kwds)
00388         /*@modifies s @*/
00389 {
00390     char * root = NULL;
00391     int options = -1;
00392     int ignore = -1;
00393 
00394 rpmfts_debug(__FUNCTION__, s);
00395     if (!PyArg_ParseTuple(args, "|sii:rpmfts_init", &root, &options, &ignore))
00396         return -1;
00397 
00398     return rpmfts_initialize(s, root, options, ignore);
00399 }
00400 
00401 /*@null@*/
00402 static PyObject * rpmfts_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
00403         /*@*/
00404 {
00405     rpmftsObject *s;
00406     PyObject *o;
00407     PyObject *n = NULL;
00408 
00409 
00410     if ((s = PyObject_GC_New(rpmftsObject, type)) == NULL)
00411         return NULL;
00412 rpmfts_debug(__FUNCTION__, s);
00413 
00414     s->md_dict = PyDict_New();
00415     if (s->md_dict == NULL)
00416         goto fail;
00417     s->callbacks = PyDict_New();
00418     if (s->md_dict == NULL)
00419         goto fail;
00420     if (type->tp_name) {
00421         char * name;
00422         if ((name = strrchr(type->tp_name, '.')) != NULL)
00423             name++;
00424         else
00425             name = type->tp_name;
00426         n = PyString_FromString(name);
00427     }
00428     if (n != NULL && PyDict_SetItemString(s->md_dict, "__name__", n) != 0)
00429         goto fail;
00430     if (PyDict_SetItemString(s->md_dict, "__doc__", Py_None) != 0)
00431         goto fail;
00432 
00433 #define CONSTANT(_v) \
00434     PyDict_SetItemString(s->md_dict, #_v, o=PyInt_FromLong(_v)); Py_DECREF(o)
00435 
00436     CONSTANT(FTS_ROOTPARENTLEVEL);
00437     CONSTANT(FTS_ROOTLEVEL);
00438 
00439     CONSTANT(FTS_COMFOLLOW);
00440     CONSTANT(FTS_LOGICAL);
00441     CONSTANT(FTS_NOCHDIR);
00442     CONSTANT(FTS_NOSTAT);
00443     CONSTANT(FTS_PHYSICAL);
00444     CONSTANT(FTS_SEEDOT);
00445     CONSTANT(FTS_XDEV);
00446     CONSTANT(FTS_WHITEOUT);
00447     CONSTANT(FTS_OPTIONMASK);
00448 
00449     CONSTANT(FTS_NAMEONLY);
00450     CONSTANT(FTS_STOP);
00451 
00452     CONSTANT(FTS_D);
00453     CONSTANT(FTS_DC);
00454     CONSTANT(FTS_DEFAULT);
00455     CONSTANT(FTS_DNR);
00456     CONSTANT(FTS_DOT);
00457     CONSTANT(FTS_DP);
00458     CONSTANT(FTS_ERR);
00459     CONSTANT(FTS_F);
00460     CONSTANT(FTS_NS);
00461     CONSTANT(FTS_NSOK);
00462     CONSTANT(FTS_SL);
00463     CONSTANT(FTS_SLNONE);
00464     CONSTANT(FTS_W);
00465 
00466     CONSTANT(FTS_DONTCHDIR);
00467     CONSTANT(FTS_SYMFOLLOW);
00468 
00469     CONSTANT(FTS_AGAIN);
00470     CONSTANT(FTS_FOLLOW);
00471     CONSTANT(FTS_NOINSTR);
00472     CONSTANT(FTS_SKIP);
00473 
00474     s->roots = NULL;
00475     s->compare = NULL;
00476     s->ftsp = NULL;
00477     s->fts = NULL;
00478 
00479     Py_XDECREF(n);
00480     PyObject_GC_Track((PyObject *)s);
00481     return (PyObject *)s;
00482 
00483  fail:
00484     Py_XDECREF(n);
00485     Py_DECREF(s);
00486     return NULL;
00487 }
00488 
00489 static int rpmfts_traverse(rpmftsObject * s, visitproc visit, void * arg)
00490         /*@*/
00491 {
00492     if (s->md_dict != NULL)
00493         return visit(s->md_dict, arg);
00494     if (s->callbacks != NULL)
00495         return visit(s->callbacks, arg);
00496     return 0;
00497 }
00498 
00499 static int rpmfts_print(rpmftsObject * s,  FILE * fp, /*@unused@*/ int flags)
00500         /*@globals fileSystem @*/
00501         /*@modifies fp, fileSystem @*/
00502 {
00503     static int indent = 2;
00504 
00505     if (!(s != NULL && s->ftsp != NULL && s->fts != NULL))
00506         return -1;
00507     fprintf(fp, "FTS_%-7s %*s%s", ftsInfoStr(s->fts->fts_info),
00508         indent * (s->fts->fts_level < 0 ? 0 : s->fts->fts_level), "",
00509         s->fts->fts_name);
00510     return 0;
00511 }
00512 
00515 /*@unchecked@*/ /*@observer@*/
00516 static char rpmfts_doc[] =
00517 "";
00518 
00521 /*@-fullinitblock@*/
00522 PyTypeObject rpmfts_Type = {
00523         PyObject_HEAD_INIT(&PyType_Type)
00524         0,                              /* ob_size */
00525         "rpm.fts",                      /* tp_name */
00526         sizeof(rpmftsObject),           /* tp_size */
00527         0,                              /* tp_itemsize */
00528         /* methods */
00529         (destructor) rpmfts_dealloc,    /* tp_dealloc */
00530         (printfunc) rpmfts_print,       /* tp_print */
00531         (getattrfunc)0,                 /* tp_getattr */
00532         (setattrfunc)0,                 /* tp_setattr */
00533         (cmpfunc)0,                     /* tp_compare */
00534         (reprfunc)0,                    /* tp_repr */
00535         0,                              /* tp_as_number */
00536         0,                              /* tp_as_sequence */
00537         0,                              /* tp_as_mapping */
00538         (hashfunc)0,                    /* tp_hash */
00539         (ternaryfunc)0,                 /* tp_call */
00540         (reprfunc)0,                    /* tp_str */
00541         (getattrofunc) rpmfts_getattro, /* tp_getattro */
00542         (setattrofunc) rpmfts_setattro, /* tp_setattro */
00543         0,                              /* tp_as_buffer */
00544         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
00545         rpmfts_doc,                     /* tp_doc */
00546         (traverseproc) rpmfts_traverse, /* tp_traverse */
00547         0,                              /* tp_clear */
00548         0,                              /* tp_richcompare */
00549         0,                              /* tp_weaklistoffset */
00550         (getiterfunc) rpmfts_iter,      /* tp_iter */
00551         (iternextfunc) rpmfts_iternext, /* tp_iternext */
00552         rpmfts_methods,                 /* tp_methods */
00553         rpmfts_members,                 /* tp_members */
00554         0,                              /* tp_getset */
00555         0,                              /* tp_base */
00556         0,                              /* tp_dict */
00557         0,                              /* tp_descr_get */
00558         0,                              /* tp_descr_set */
00559         offsetof(rpmftsObject, md_dict),/* tp_dictoffset */
00560         (initproc) rpmfts_init,         /* tp_init */
00561         rpmfts_alloc,                   /* tp_alloc */
00562         rpmfts_new,                     /* tp_new */
00563         rpmfts_free,                    /* tp_free */
00564         0,                              /* tp_is_gc */
00565 };
00566 /*@=fullinitblock@*/

Generated on Fri Aug 11 13:29:38 2006 for rpm by  doxygen 1.3.9.1