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

Generated on Sun Oct 26 13:02:02 2003 for rpm by doxygen1.2.18