rpm  5.2.1
header-py.c
Go to the documentation of this file.
1 
5 #include "system.h"
6 
7 #include "rpmio_internal.h"
8 #include <rpmcb.h>
9 
10 #include "legacy.h"
11 #define _RPMTAG_INTERNAL
12 #include "header_internal.h" /* XXX HEADERFLAG_ALLOCATED */
13 #include "rpmtypes.h"
14 #define _RPMEVR_INTERNAL
15 #include "rpmevr.h"
16 #include "pkgio.h" /* XXX rpmpkgRead */
17 
18 #include "rpmts.h" /* XXX rpmtsCreate/rpmtsFree */
19 
20 #include "rpmcli.h"
21 
22 #include "header-py.h"
23 #include "rpmds-py.h"
24 #include "rpmfi-py.h"
25 
26 #include "debug.h"
27 
138 struct hdrObject_s {
139  PyObject_HEAD
141 } ;
142 
145 /*@unused@*/ static inline Header headerAllocated(Header h)
146  /*@modifies h @*/
147 {
149  return 0;
150 }
151 
156 
159 static PyObject * hdrKeyList(hdrObject * s)
160  /*@*/
161 {
162  HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
163  PyObject * list, *o;
164  HeaderIterator hi;
165 
166  list = PyList_New(0);
167 
168  for (hi = headerInit(s->h);
169  headerNext(hi, he, 0);
170  he->p.ptr = _free(he->p.ptr))
171  {
172  if (he->tag == HEADER_I18NTABLE) continue;
173  switch (he->t) {
174  case RPM_I18NSTRING_TYPE:
175  break;
176  case RPM_BIN_TYPE:
177  case RPM_UINT64_TYPE:
178  case RPM_UINT32_TYPE:
179  case RPM_UINT16_TYPE:
180  case RPM_UINT8_TYPE:
182  case RPM_STRING_TYPE:
183  PyList_Append(list, o=PyInt_FromLong(he->tag));
184  Py_DECREF(o);
185  break;
186  }
187  }
188  hi = headerFini(hi);
189 
190  return list;
191 }
192 
195 static PyObject * hdrUnload(hdrObject * s, PyObject * args, PyObject *keywords)
196  /*@*/
197 {
198  char * buf;
199  PyObject * rc;
200  int legacy = 0;
201  int nb;
202  Header h;
203  static char *kwlist[] = { "legacyHeader", NULL};
204 
205  if (!PyArg_ParseTupleAndKeywords(args, keywords, "|i", kwlist, &legacy))
206  return NULL;
207 
208  h = headerLink(s->h);
209  /* XXX this legacy switch is a hack, needs to be removed. */
210  if (legacy) {
211  h = headerCopy(s->h); /* XXX strip region tags, etc */
212  (void)headerFree(s->h);
213  s->h = NULL;
214  }
215  { size_t len;
216  buf = headerUnload(h, &len);
217  nb = len;
218  nb -= 8; /* XXX HEADER_MAGIC_NO */
219  }
220  (void)headerFree(h);
221  h = NULL;
222 
223  if (buf == NULL || nb == 0) {
224  PyErr_SetString(pyrpmError, "can't unload bad header\n");
225  return NULL;
226  }
227 
228  rc = PyString_FromStringAndSize(buf, nb);
229  buf = _free(buf);
230 
231  return rc;
232 }
233 
236 static PyObject * hdrGetOrigin(hdrObject * s)
237  /*@*/
238 {
239  const char * origin = NULL;
240  if (s->h != NULL)
241 
242  origin = headerGetOrigin(s->h);
243  if (origin != NULL)
244  return Py_BuildValue("s", origin);
245  Py_INCREF(Py_None);
246  return Py_None;
247 }
248 
251 static PyObject * hdrSetOrigin(hdrObject * s, PyObject * args, PyObject * kwds)
252  /*@*/
253 {
254  char * kwlist[] = {"origin", NULL};
255  const char * origin = NULL;
256 
257  if (!PyArg_ParseTupleAndKeywords(args, kwds, "s:SetOrigin", kwlist, &origin))
258  return NULL;
259 
260  if (s->h != NULL && origin != NULL)
261  headerSetOrigin(s->h, origin);
262 
263  Py_INCREF(Py_None);
264  return Py_None;
265 }
266 
269 static PyObject * hdrSprintf(hdrObject * s, PyObject * args, PyObject * kwds)
270  /*@*/
271 {
272  char * fmt;
273  char * r;
274  errmsg_t err;
275  PyObject * result;
276  char * kwlist[] = {"format", NULL};
277 
278  if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &fmt))
279  return NULL;
280 
281  r = headerSprintf(s->h, fmt, NULL, rpmHeaderFormats, &err);
282  if (!r) {
283  PyErr_SetString(pyrpmError, err);
284  return NULL;
285  }
286 
287  result = Py_BuildValue("s", r);
288  r = _free(r);
289 
290  return result;
291 }
292 
297 /*@unchecked@*/ /*@observer@*/
298 static struct PyMethodDef hdr_methods[] = {
299  {"keys", (PyCFunction) hdrKeyList, METH_NOARGS,
300  NULL },
301  {"unload", (PyCFunction) hdrUnload, METH_VARARGS|METH_KEYWORDS,
302  NULL },
303  {"getorigin", (PyCFunction) hdrGetOrigin, METH_NOARGS,
304  NULL },
305  {"setorigin", (PyCFunction) hdrSetOrigin, METH_NOARGS,
306  NULL },
307  {"sprintf", (PyCFunction) hdrSprintf, METH_VARARGS|METH_KEYWORDS,
308  NULL },
309 
310  {"dsOfHeader", (PyCFunction)hdr_dsOfHeader, METH_NOARGS,
311  NULL},
312  {"dsFromHeader", (PyCFunction)hdr_dsFromHeader, METH_VARARGS|METH_KEYWORDS,
313  NULL},
314  {"fiFromHeader", (PyCFunction)hdr_fiFromHeader, METH_VARARGS|METH_KEYWORDS,
315  NULL},
316 
317  {NULL, NULL} /* sentinel */
318 };
319 
322 static int hdr_compare(hdrObject * a, hdrObject * b)
323  /*@*/
324 {
325  return rpmVersionCompare(a->h, b->h);
326 }
327 
328 static long hdr_hash(PyObject * h)
329 {
330  return (long) h;
331 }
332 
335 static void hdr_dealloc(hdrObject * s)
336  /*@*/
337 {
338  if (s->h) headerFree(s->h);
339  s->h = NULL;
340  PyObject_Del(s);
341 }
342 
345 rpmTag tagNumFromPyObject (PyObject *item)
346 {
347  char * str;
348 
349  if (PyInt_Check(item)) {
350  return (rpmTag) PyInt_AsLong(item);
351  } else if (PyString_Check(item) || PyUnicode_Check(item)) {
352  str = PyString_AsString(item);
353  return tagValue(str);
354  }
355  return (rpmTag)0xffffffff;
356 }
357 
360 static PyObject * hdr_subscript(hdrObject * s, PyObject * item)
361  /*@*/
362 {
363  HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
364  rpmTag tag = (rpmTag)0xffffffff;
365  uint32_t i;
366  PyObject * o, * metao;
367  int forceArray = 0;
368  const struct headerSprintfExtension_s * ext = NULL;
369  int xx;
370 
371  if (PyCObject_Check (item))
372  ext = PyCObject_AsVoidPtr(item);
373  else
374  tag = tagNumFromPyObject (item);
375 
376  if (tag == (rpmTag)0xffffffff && (PyString_Check(item) || PyUnicode_Check(item))) {
377  const struct headerSprintfExtension_s * extensions = rpmHeaderFormats;
378  char * str;
379  /* if we still don't have the tag, go looking for the header
380  extensions */
381  str = PyString_AsString(item);
382  while (extensions->name) {
383  if (extensions->type == HEADER_EXT_TAG
384  && !xstrcasecmp(extensions->name + 7, str)) {
385  ext = extensions;
386  }
387  extensions++;
388  if (extensions->type == HEADER_EXT_MORE)
389  extensions = *extensions->u.more;
390  }
391  }
392 
393  /* Retrieve data from extension or header. */
394  if (ext) {
395  ext->u.tagFunction(s->h, he);
396  } else {
397  if (tag == (rpmTag)0xffffffff) {
398  PyErr_SetString(PyExc_KeyError, "unknown header tag");
399  return NULL;
400  }
401 
402  he->tag = tag;
403  xx = headerGet(s->h, he, 0);
404  if (!xx) {
405  he->p.ptr = _free(he->p.ptr);
406  switch (tag) {
407  case RPMTAG_EPOCH:
408  case RPMTAG_NAME:
409  case RPMTAG_VERSION:
410  case RPMTAG_RELEASE:
411  case RPMTAG_DISTEPOCH:
412  case RPMTAG_ARCH:
413  case RPMTAG_OS:
414  Py_INCREF(Py_None);
415  return Py_None;
416  break;
417  default:
418  return PyList_New(0);
419  break;
420  }
421  }
422  }
423 
424  switch (tag) {
425  case RPMTAG_FILEPATHS:
426  case RPMTAG_ORIGPATHS:
427  case RPMTAG_OLDFILENAMES:
428  case RPMTAG_FILESIZES:
429  case RPMTAG_FILESTATES:
430  case RPMTAG_FILEMODES:
431  case RPMTAG_FILEUIDS:
432  case RPMTAG_FILEGIDS:
433  case RPMTAG_FILERDEVS:
434  case RPMTAG_FILEMTIMES:
435  case RPMTAG_FILEMD5S:
436  case RPMTAG_FILELINKTOS:
437  case RPMTAG_FILEFLAGS:
438  case RPMTAG_ROOT:
439  case RPMTAG_FILEUSERNAME:
441  case RPMTAG_REQUIRENAME:
442  case RPMTAG_REQUIREFLAGS:
444  case RPMTAG_PROVIDENAME:
445  case RPMTAG_PROVIDEFLAGS:
447  case RPMTAG_OBSOLETENAME:
450  case RPMTAG_CONFLICTNAME:
455  forceArray = 1;
456  break;
457  default:
458  break;
459  }
460 
461  switch (he->t) {
462  case RPM_BIN_TYPE:
463  o = PyString_FromStringAndSize(he->p.str, he->c);
464  break;
465 
466  case RPM_UINT8_TYPE:
467  if (he->c != 1 || forceArray) {
468  metao = PyList_New(0);
469  for (i = 0; i < he->c; i++) {
470  o = PyInt_FromLong(he->p.ui8p[i]);
471  PyList_Append(metao, o);
472  Py_DECREF(o);
473  }
474  o = metao;
475  } else {
476  o = PyInt_FromLong(he->p.ui8p[0]);
477  }
478  break;
479 
480  case RPM_UINT16_TYPE:
481  if (he->c != 1 || forceArray) {
482  metao = PyList_New(0);
483  for (i = 0; i < he->c; i++) {
484  o = PyInt_FromLong(he->p.ui16p[i]);
485  PyList_Append(metao, o);
486  Py_DECREF(o);
487  }
488  o = metao;
489  } else {
490  o = PyInt_FromLong(he->p.ui16p[0]);
491  }
492  break;
493 
494  case RPM_UINT32_TYPE:
495  if (he->c != 1 || forceArray) {
496  metao = PyList_New(0);
497  for (i = 0; i < he->c; i++) {
498  o = PyInt_FromLong(he->p.ui32p[i]);
499  PyList_Append(metao, o);
500  Py_DECREF(o);
501  }
502  o = metao;
503  } else {
504  o = PyInt_FromLong(he->p.ui32p[0]);
505  }
506  break;
507 
508  case RPM_UINT64_TYPE:
509  if (he->c != 1 || forceArray) {
510  metao = PyList_New(0);
511  for (i = 0; i < he->c; i++) {
512  o = PyInt_FromLong(he->p.ui64p[i]);
513  PyList_Append(metao, o);
514  Py_DECREF(o);
515  }
516  o = metao;
517  } else {
518  o = PyInt_FromLong(he->p.ui64p[0]);
519  }
520  break;
521 
523  metao = PyList_New(0);
524  for (i = 0; i < he->c; i++) {
525  o = PyString_FromString(he->p.argv[i]);
526  PyList_Append(metao, o);
527  Py_DECREF(o);
528  }
529  o = metao;
530  break;
531 
532  case RPM_STRING_TYPE:
533  if (he->p.str != NULL)
534  o = PyString_FromString(he->p.str);
535  else
536  o = PyString_FromString("");
537  break;
538 
539  default:
540  PyErr_SetString(PyExc_TypeError, "unsupported type in header");
541  return NULL;
542  }
543  if (he->freeData)
544  he->p.ptr = _free(he->p.ptr);
545 
546  return o;
547 }
548 
551 /*@unchecked@*/ /*@observer@*/
552 static PyMappingMethods hdr_as_mapping = {
553  (lenfunc) 0, /* mp_length */
554  (binaryfunc) hdr_subscript, /* mp_subscript */
555  (objobjargproc) 0, /* mp_ass_subscript */
556 };
557 
558 static PyObject * hdr_getattro(hdrObject * o, PyObject * n)
559  /*@*/
560 {
561  PyObject * res;
562  res = PyObject_GenericGetAttr((PyObject *)o, n);
563  if (res == NULL)
564  res = hdr_subscript(o, n);
565  return res;
566 }
567 
568 static int hdr_setattro(hdrObject * o, PyObject * n, PyObject * v)
569  /*@*/
570 {
571  return PyObject_GenericSetAttr((PyObject *)o, n, v);
572 }
573 
576 static char hdr_doc[] =
577 "";
578 
581 /*@unchecked@*/ /*@observer@*/
582 PyTypeObject hdr_Type = {
583  PyObject_HEAD_INIT(&PyType_Type)
584  0, /* ob_size */
585  "rpm.hdr", /* tp_name */
586  sizeof(hdrObject), /* tp_size */
587  0, /* tp_itemsize */
588  (destructor) hdr_dealloc, /* tp_dealloc */
589  0, /* tp_print */
590  (getattrfunc) 0, /* tp_getattr */
591  0, /* tp_setattr */
592  (cmpfunc) hdr_compare, /* tp_compare */
593  0, /* tp_repr */
594  0, /* tp_as_number */
595  0, /* tp_as_sequence */
596  &hdr_as_mapping, /* tp_as_mapping */
597  hdr_hash, /* tp_hash */
598  0, /* tp_call */
599  0, /* tp_str */
600  (getattrofunc) hdr_getattro, /* tp_getattro */
601  (setattrofunc) hdr_setattro, /* tp_setattro */
602  0, /* tp_as_buffer */
603  Py_TPFLAGS_DEFAULT, /* tp_flags */
604  hdr_doc, /* tp_doc */
605 #if Py_TPFLAGS_HAVE_ITER
606  0, /* tp_traverse */
607  0, /* tp_clear */
608  0, /* tp_richcompare */
609  0, /* tp_weaklistoffset */
610  0, /* tp_iter */
611  0, /* tp_iternext */
612  hdr_methods, /* tp_methods */
613  0, /* tp_members */
614  0, /* tp_getset */
615  0, /* tp_base */
616  0, /* tp_dict */
617  0, /* tp_descr_get */
618  0, /* tp_descr_set */
619  0, /* tp_dictoffset */
620  0, /* tp_init */
621  0, /* tp_alloc */
622  0, /* tp_new */
623  0, /* tp_free */
624  0, /* tp_is_gc */
625 #endif
626 };
627 
629 {
630  hdrObject * hdr = PyObject_New(hdrObject, &hdr_Type);
631  hdr->h = headerLink(h);
632  return hdr;
633 }
634 
636 {
637  return s->h;
638 }
639 
642 PyObject * hdrLoad(PyObject * self, PyObject * args, PyObject * kwds)
643 {
644  hdrObject * hdr;
645  char * copy = NULL;
646  char * obj;
647  Header h;
648  int len;
649  char * kwlist[] = {"headers", NULL};
650 
651  if (!PyArg_ParseTupleAndKeywords(args, kwds, "s#", kwlist, &obj, &len))
652  return NULL;
653 
654  /* malloc is needed to avoid surprises from data swab in headerLoad(). */
655  copy = malloc(len);
656  if (copy == NULL) {
657  PyErr_SetString(pyrpmError, "out of memory");
658  return NULL;
659  }
660  memcpy (copy, obj, len);
661 
662  h = headerLoad(copy);
663  if (!h) {
664  PyErr_SetString(pyrpmError, "bad header");
665  return NULL;
666  }
667  headerAllocated(h);
668 
669  hdr = hdr_Wrap(h);
670  (void)headerFree(h); /* XXX ref held by hdr */
671  h = NULL;
672 
673  return (PyObject *) hdr;
674 }
675 
678 PyObject * rpmReadHeaders (FD_t fd)
679 {
680  PyObject * list;
681  Header h;
682  hdrObject * hdr;
683 
684  if (!fd) {
685  PyErr_SetFromErrno(pyrpmError);
686  return NULL;
687  }
688 
689  list = PyList_New(0);
690  Py_BEGIN_ALLOW_THREADS
691  { const char item[] = "Header";
692  const char * msg = NULL;
693  rpmRC rc = rpmpkgRead(item, fd, &h, &msg);
694  if(rc == RPMRC_NOTFOUND) {
695  Py_INCREF(Py_None);
696  list = Py_None;
697  }
698  else if (rc != RPMRC_OK)
699  rpmlog(RPMLOG_ERR, "%s: %s: %s : error code: %d\n", "rpmpkgRead", item, msg, rc);
700  msg = _free(msg);
701  }
702  Py_END_ALLOW_THREADS
703 
704  while (h) {
705  hdr = hdr_Wrap(h);
706  if (PyList_Append(list, (PyObject *) hdr)) {
707  Py_DECREF(list);
708  Py_DECREF(hdr);
709  return NULL;
710  }
711  Py_DECREF(hdr);
712 
713  (void)headerFree(h); /* XXX ref held by hdr */
714  h = NULL;
715 
716  Py_BEGIN_ALLOW_THREADS
717  { const char item[] = "Header";
718  const char * msg = NULL;
719  rpmRC rc = rpmpkgRead(item, fd, &h, &msg);
720  if(rc == RPMRC_NOTFOUND) {
721  Py_INCREF(Py_None);
722  list = Py_None;
723  }
724  else if (rc != RPMRC_OK)
725  rpmlog(RPMLOG_ERR, "%s: %s: %s : error code: %d\n", "rpmpkgRead", item, msg, rc);
726  msg = _free(msg);
727  }
728  Py_END_ALLOW_THREADS
729  }
730 
731  return list;
732 }
733 
736 PyObject * rpmHeaderFromFD(PyObject * self, PyObject * args,
737  PyObject * kwds)
738 {
739  FD_t fd;
740  int fileno;
741  PyObject * list;
742  char * kwlist[] = {"fd", NULL};
743 
744  if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &fileno))
745  return NULL;
746 
747  fd = fdDup(fileno);
748 
749  list = rpmReadHeaders (fd);
750  Fclose(fd);
751 
752  return list;
753 }
754 
757 PyObject * rpmHeaderFromFile(PyObject * self, PyObject * args,
758  PyObject *kwds)
759 {
760  char * filespec;
761  FD_t fd;
762  PyObject * list;
763  char * kwlist[] = {"file", NULL};
764 
765  if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &filespec))
766  return NULL;
767 
768  fd = Fopen(filespec, "r.fdio");
769 
770  if (!fd) {
771  PyErr_SetFromErrno(pyrpmError);
772  return NULL;
773  }
774 
775  list = rpmReadHeaders (fd);
776  Fclose(fd);
777 
778  return list;
779 }
780 
783 PyObject *
784 rpmSingleHeaderFromFD(PyObject * self, PyObject * args,
785  PyObject * kwds)
786 {
787  FD_t fd;
788  int fileno;
789  off_t offset;
790  PyObject * tuple;
791  Header h;
792  char * kwlist[] = {"fd", NULL};
793 
794  if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &fileno))
795  return NULL;
796 
797  offset = lseek(fileno, 0, SEEK_CUR);
798 
799  fd = fdDup(fileno);
800 
801  if (!fd) {
802  PyErr_SetFromErrno(pyrpmError);
803  return NULL;
804  }
805 
806  Py_BEGIN_ALLOW_THREADS
807  { const char item[] = "Header";
808  const char * msg = NULL;
809  rpmRC rc = rpmpkgRead(item, fd, &h, &msg);
810  if(rc == RPMRC_NOTFOUND) {
811  Py_INCREF(Py_None);
812  tuple = Py_None;
813  }
814  else if (rc != RPMRC_OK)
815  rpmlog(RPMLOG_ERR, "%s: %s: %s : error code: %d\n", "rpmpkgRead", item, msg, rc);
816  msg = _free(msg);
817  }
818  Py_END_ALLOW_THREADS
819 
820  Fclose(fd);
821 
822  tuple = PyTuple_New(2);
823 
824  if (h && tuple) {
825  PyTuple_SET_ITEM(tuple, 0, (PyObject *) hdr_Wrap(h));
826  PyTuple_SET_ITEM(tuple, 1, PyLong_FromLong(offset));
827  (void)headerFree(h);
828  h = NULL;
829  } else {
830  Py_INCREF(Py_None);
831  Py_INCREF(Py_None);
832  PyTuple_SET_ITEM(tuple, 0, Py_None);
833  PyTuple_SET_ITEM(tuple, 1, Py_None);
834  }
835 
836  return tuple;
837 }
838 
841 PyObject * rpmWriteHeaders (PyObject * list, FD_t fd)
842 {
843  int count;
844 
845  if (!fd) {
846  PyErr_SetFromErrno(pyrpmError);
847  return NULL;
848  }
849 
850  for(count = 0; count < PyList_Size(list); count++){
851  Py_BEGIN_ALLOW_THREADS
852  const char item[] = "Header";
853  const char * msg = NULL;
854  hdrObject * hdr = (hdrObject *)PyList_GetItem(list, count);
855  rpmRC rc = rpmpkgWrite(item, fd, hdr->h, &msg);
856  if (rc != RPMRC_OK)
857  rpmlog(RPMLOG_ERR, "%s: %s: %s : error code: %d\n", "rpmpkgWrite", item, msg, rc);
858  msg = _free(msg);
859  Py_END_ALLOW_THREADS
860  }
861 
862  Py_RETURN_TRUE;
863 }
864 
867 PyObject * rpmHeaderToFD(PyObject * self, PyObject * args,
868  PyObject * kwds)
869 {
870  FD_t fd;
871  int fileno;
872  PyObject * list;
873  PyObject * ret;
874  char * kwlist[] = {"headers", "fd", NULL};
875 
876  if (!PyArg_ParseTupleAndKeywords(args, kwds, "Oi", kwlist, &list, &fileno))
877  return NULL;
878 
879  fd = fdDup(fileno);
880 
881  ret = rpmWriteHeaders (list, fd);
882  Fclose(fd);
883 
884  return list;
885 }
886 
889 PyObject * rpmHeaderToFile(PyObject * self, PyObject * args,
890  PyObject *kwds)
891 {
892  char * filespec;
893  FD_t fd;
894  PyObject * list;
895  PyObject * ret;
896  char * kwlist[] = {"headers", "file", NULL};
897 
898  if (!PyArg_ParseTupleAndKeywords(args, kwds, "Os", kwlist, &list, &filespec))
899  return NULL;
900 
901  fd = Fopen(filespec, "w.fdio");
902  if (!fd) {
903  PyErr_SetFromErrno(pyrpmError);
904  return NULL;
905  }
906 
907  ret = rpmWriteHeaders (list, fd);
908  Fclose(fd);
909 
910  return ret;
911 }
912 
915 PyObject * versionCompare (PyObject * self, PyObject * args,
916  PyObject * kwds)
917 {
918  hdrObject * h1, * h2;
919  char * kwlist[] = {"version0", "version1", NULL};
920 
921  if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O!", kwlist, &hdr_Type,
922  &h1, &hdr_Type, &h2))
923  return NULL;
924 
925  return Py_BuildValue("i", hdr_compare(h1, h2));
926 }
927 
928 PyObject * labelCompare (PyObject * self, PyObject * args)
929 {
932  int rc;
933  PyObject *aTuple, *bTuple;
934 
935  if (!PyArg_ParseTuple(args, "OO", &aTuple, &bTuple) ||
936  !PyArg_ParseTuple(aTuple, "zzz|z",
937  &a->F[RPMEVR_E], &a->F[RPMEVR_V], &a->F[RPMEVR_R], &a->F[RPMEVR_D]) ||
938  !PyArg_ParseTuple(bTuple, "zzz|z",
939  &b->F[RPMEVR_E], &b->F[RPMEVR_V], &b->F[RPMEVR_R], &b->F[RPMEVR_D]))
940  {
941  a = rpmEVRfree(a);
942  b = rpmEVRfree(b);
943  return NULL;
944  }
945 
946  /* XXX HACK: postpone committing to single "missing" value for now. */
947  if (a->F[RPMEVR_E] == NULL) a->F[RPMEVR_E] = "0";
948  if (b->F[RPMEVR_E] == NULL) b->F[RPMEVR_E] = "0";
949  if (a->F[RPMEVR_V] == NULL) a->F[RPMEVR_V] = "";
950  if (b->F[RPMEVR_V] == NULL) b->F[RPMEVR_V] = "";
951  if (a->F[RPMEVR_R] == NULL) a->F[RPMEVR_R] = "";
952  if (b->F[RPMEVR_R] == NULL) b->F[RPMEVR_R] = "";
953  if (a->F[RPMEVR_D] == NULL) a->F[RPMEVR_D] = "";
954  if (b->F[RPMEVR_D] == NULL) b->F[RPMEVR_D] = "";
955 
956  rc = rpmEVRcompare(a, b);
957 
958  a = rpmEVRfree(a);
959  b = rpmEVRfree(b);
960 
961  return Py_BuildValue("i", rc);
962 }