diff options
Diffstat (limited to 'python/tag.cc')
-rw-r--r-- | python/tag.cc | 1063 |
1 files changed, 1063 insertions, 0 deletions
diff --git a/python/tag.cc b/python/tag.cc new file mode 100644 index 0000000..691b67f --- /dev/null +++ b/python/tag.cc @@ -0,0 +1,1063 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: tag.cc,v 1.3 2002/02/26 01:36:15 mdz Exp $ +/* ###################################################################### + + Tag - Binding for the RFC 822 tag file parser + + Upon reflection I have make the TagSection wrapper look like a map.. + The other option was to use a sequence (which nicely matches the internal + storage) but really makes no sense to a Python Programmer.. One + specialized lookup is provided, the FindFlag lookup - as well as the + usual set of duplicate things to match the C++ interface. + + The TagFile interface is also slightly different, it has a built in + internal TagSection object that is used. Do not hold onto a reference + to a TagSection and let TagFile go out of scope! The underlying storage + for the section will go away and it will seg. + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include "generic.h" +#include "apt_pkgmodule.h" + +#include <apt-pkg/tagfile.h> +#include <apt-pkg/fileutl.h> + +#include <stdio.h> +#include <iostream> +#include <Python.h> + +using namespace std; + /*}}}*/ +/* We need to keep a private copy of the data.. */ +struct TagSecData : public CppPyObject<pkgTagSection> +{ + char *Data; + bool Bytes; +#if PY_MAJOR_VERSION >= 3 + PyObject *Encoding; +#endif +}; + +// The owner of the TagFile is a Python file object. +struct TagFileData : public CppPyObject<pkgTagFile> +{ + TagSecData *Section; + FileFd Fd; + bool Bytes; +#if PY_MAJOR_VERSION >= 3 + PyObject *Encoding; +#endif +}; + +// Traversal and Clean for owned objects +int TagFileTraverse(PyObject *self, visitproc visit, void* arg) { + Py_VISIT(((TagFileData *)self)->Section); + Py_VISIT(((TagFileData *)self)->Owner); + return 0; +} + +int TagFileClear(PyObject *self) { + Py_CLEAR(((TagFileData *)self)->Section); + Py_CLEAR(((TagFileData *)self)->Owner); + return 0; +} + +// Helpers to return Unicode or bytes as appropriate. +#if PY_MAJOR_VERSION < 3 +#define TagSecString_FromStringAndSize(self, v, len) \ + PyString_FromStringAndSize((v), (len)) +#define TagSecString_FromString(self, v) CppPyString(v) +#else +static PyObject *TagSecString_FromStringAndSize(PyObject *self, const char *v, + Py_ssize_t len) { + TagSecData *Self = (TagSecData *)self; + if (Self->Bytes) + return PyBytes_FromStringAndSize(v, len); + else if (Self->Encoding) + return PyUnicode_Decode(v, len, PyUnicode_AsString(Self->Encoding), 0); + else + return PyUnicode_FromStringAndSize(v, len); +} + +static PyObject *TagSecString_FromString(PyObject *self, const char *v) { + TagSecData *Self = (TagSecData *)self; + if (Self->Bytes) + return PyBytes_FromString(v); + else if (Self->Encoding) + return PyUnicode_Decode(v, strlen(v), + PyUnicode_AsString(Self->Encoding), 0); + else + return PyUnicode_FromString(v); +} +#endif + + + /*}}}*/ +// TagSecFree - Free a Tag Section /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void TagSecFree(PyObject *Obj) +{ + TagSecData *Self = (TagSecData *)Obj; + delete [] Self->Data; + CppDealloc<pkgTagSection>(Obj); +} + /*}}}*/ +// TagFileFree - Free a Tag File /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void TagFileFree(PyObject *Obj) +{ + #ifdef ALLOC_DEBUG + std::cerr << "=== DEALLOCATING " << Obj->ob_type->tp_name << "^ ===\n"; + #endif + PyObject_GC_UnTrack(Obj); + TagFileData *Self = (TagFileData *)Obj; + Py_CLEAR(Self->Section); + Self->Object.~pkgTagFile(); + Self->Fd.~FileFd(); + Py_CLEAR(Self->Owner); + Obj->ob_type->tp_free(Obj); +} + /*}}}*/ + +// Tag Section Wrappers /*{{{*/ +static char *doc_Find = + "find(name: str[, default = None]) -> str\n\n" + "Find the key given by 'name' and return the value. If the key can\n" + "not be found, return 'default'."; +static PyObject *TagSecFind(PyObject *Self,PyObject *Args) +{ + char *Name = 0; + char *Default = 0; + if (PyArg_ParseTuple(Args,"s|z",&Name,&Default) == 0) + return 0; + + const char *Start; + const char *Stop; + if (GetCpp<pkgTagSection>(Self).Find(Name,Start,Stop) == false) + { + if (Default == 0) + Py_RETURN_NONE; + return TagSecString_FromString(Self,Default); + } + return TagSecString_FromStringAndSize(Self,Start,Stop-Start); +} + +static char *doc_FindRaw = + "find_raw(name: str[, default = None] -> str\n\n" + "Same as find(), but returns the complete 'key: value' field; instead of\n" + "just the value."; +static PyObject *TagSecFindRaw(PyObject *Self,PyObject *Args) +{ + char *Name = 0; + char *Default = 0; + if (PyArg_ParseTuple(Args,"s|z",&Name,&Default) == 0) + return 0; + + unsigned Pos; + if (GetCpp<pkgTagSection>(Self).Find(Name,Pos) == false) + { + if (Default == 0) + Py_RETURN_NONE; + return TagSecString_FromString(Self,Default); + } + + const char *Start; + const char *Stop; + GetCpp<pkgTagSection>(Self).Get(Start,Stop,Pos); + + return TagSecString_FromStringAndSize(Self,Start,Stop-Start); +} + +static char *doc_FindFlag = + "find_flag(name: str) -> int\n\n" + "Return 1 if the key's value is 'yes' or a similar value describing\n" + "a boolean true. If the field does not exist, or does not have such a\n" + "value, return 0."; +static PyObject *TagSecFindFlag(PyObject *Self,PyObject *Args) +{ + char *Name = 0; + if (PyArg_ParseTuple(Args,"s",&Name) == 0) + return 0; + + unsigned long Flag = 0; + if (GetCpp<pkgTagSection>(Self).FindFlag(Name,Flag,1) == false) + { + Py_INCREF(Py_None); + return Py_None; + } + return PyBool_FromLong(Flag); +} + +static char *doc_Write = + "write(file: int, order: List[str], rewrite: List[Tag]) -> None\n\n" + "Rewrites the section into the given file descriptor, which should be\n" + "a file descriptor or an object providing a fileno() method.\n" + "\n" + ".. versionadded:: 1.9.0"; +static PyObject *TagSecWrite(PyObject *Self, PyObject *Args, PyObject *kwds) +{ + char *kwlist[] = {"file", "order", "rewrite", nullptr}; + PyObject *pFile; + PyObject *pOrder; + PyObject *pRewrite; + if (PyArg_ParseTupleAndKeywords(Args,kwds, "OO!O!",kwlist, &pFile,&PyList_Type,&pOrder, &PyList_Type, &pRewrite) == 0) + return nullptr; + + int fileno = PyObject_AsFileDescriptor(pFile); + // handle invalid arguments + if (fileno == -1) + { + PyErr_SetString(PyExc_TypeError, + "Argument must be string, fd or have a fileno() method"); + return 0; + } + + FileFd file(fileno); + const char **order = ListToCharChar(pOrder,true); + if (order == nullptr) + return nullptr; + std::vector<pkgTagSection::Tag> rewrite; + for (int I = 0; I != PySequence_Length(pRewrite); I++) { + PyObject *item = PySequence_GetItem(pRewrite, I); + if (!PyObject_TypeCheck(item, &PyTag_Type)) + return PyErr_SetString(PyExc_TypeError, "Wrong type for tag in list"), nullptr; + rewrite.push_back(GetCpp<pkgTagSection::Tag>(item)); + } + + return HandleErrors(PyBool_FromLong(GetCpp<pkgTagSection>(Self).Write(file, order, rewrite))); +} + + +// Map access, operator [] +static PyObject *TagSecMap(PyObject *Self,PyObject *Arg) +{ + const char *Name = PyObject_AsString(Arg); + if (Name == 0) + return 0; + const char *Start; + const char *Stop; + if (GetCpp<pkgTagSection>(Self).Find(Name,Start,Stop) == false) + { + PyErr_SetString(PyExc_KeyError,Name); + return 0; + } + + return TagSecString_FromStringAndSize(Self,Start,Stop-Start); +} + +// len() operation +static Py_ssize_t TagSecLength(PyObject *Self) +{ + pkgTagSection &Sec = GetCpp<pkgTagSection>(Self); + return Sec.Count(); +} + +// Look like a mapping +static char *doc_Keys = + "keys() -> list\n\n" + "Return a list of all keys."; +static PyObject *TagSecKeys(PyObject *Self,PyObject *Args) +{ + pkgTagSection &Tags = GetCpp<pkgTagSection>(Self); + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + // Convert the whole configuration space into a list + PyObject *List = PyList_New(0); + for (unsigned int I = 0; I != Tags.Count(); I++) + { + const char *Start; + const char *Stop; + Tags.Get(Start,Stop,I); + const char *End = Start; + for (; End < Stop && *End != ':'; End++); + + PyObject *Obj; + PyList_Append(List,Obj = PyString_FromStringAndSize(Start,End-Start)); + Py_DECREF(Obj); + } + return List; +} + +#if PY_MAJOR_VERSION < 3 +static char *doc_Exists = + "has_key(name: str) -> bool\n\n" + "Return True if the key given by 'name' exists, False otherwise."; +static PyObject *TagSecExists(PyObject *Self,PyObject *Args) +{ + char *Name = 0; + if (PyArg_ParseTuple(Args,"s",&Name) == 0) + return 0; + + const char *Start; + const char *Stop; + return PyBool_FromLong(GetCpp<pkgTagSection>(Self).Find(Name,Start,Stop)); +} +#endif + +static int TagSecContains(PyObject *Self,PyObject *Arg) +{ + const char *Name = PyObject_AsString(Arg); + if (Name == 0) + return 0; + const char *Start; + const char *Stop; + if (GetCpp<pkgTagSection>(Self).Find(Name,Start,Stop) == false) + return 0; + return 1; +} + +static char *doc_Bytes = + "bytes() -> int\n\n" + "Return the number of bytes this section is large."; +static PyObject *TagSecBytes(PyObject *Self,PyObject *Args) +{ + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + return MkPyNumber(GetCpp<pkgTagSection>(Self).size()); +} + +static PyObject *TagSecStr(PyObject *Self) +{ + const char *Start; + const char *Stop; + GetCpp<pkgTagSection>(Self).GetSection(Start,Stop); + return TagSecString_FromStringAndSize(Self,Start,Stop-Start); +} + /*}}}*/ +// TagFile Wrappers /*{{{*/ +static char *doc_Step = + "step() -> bool\n\n" + "Step forward in the file"; +static PyObject *TagFileStep(PyObject *Self,PyObject *Args) +{ + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + TagFileData &Obj = *(TagFileData *)Self; + if (Obj.Object.Step(Obj.Section->Object) == false) + return HandleErrors(PyBool_FromLong(0)); + + return HandleErrors(PyBool_FromLong(1)); +} + +// TagFile Wrappers /*{{{*/ +static PyObject *TagFileNext(PyObject *Self) +{ + TagFileData &Obj = *(TagFileData *)Self; + // Replace the section. + Py_CLEAR(Obj.Section); + Obj.Section = (TagSecData*)(&PyTagSection_Type)->tp_alloc(&PyTagSection_Type, 0); + new (&Obj.Section->Object) pkgTagSection(); + Obj.Section->Owner = Self; + Py_INCREF(Obj.Section->Owner); + Obj.Section->Data = 0; + Obj.Section->Bytes = Obj.Bytes; +#if PY_MAJOR_VERSION >= 3 + // We don't need to incref Encoding as the previous Section object already + // held a reference to it. + Obj.Section->Encoding = Obj.Encoding; +#endif + if (Obj.Object.Step(Obj.Section->Object) == false) + return HandleErrors(NULL); + + // Bug-Debian: http://bugs.debian.org/572596 + // Duplicate the data here and scan the duplicated section data; in order + // to not use any shared storage. + // TODO: Provide an API in apt-pkg to do this; this is really ugly. + + // Fetch old section data + const char *Start; + const char *Stop; + Obj.Section->Object.GetSection(Start,Stop); + // Duplicate the data and + // append a \n because GetSection() will only give us a single \n + // but Scan() needs \n\n to work + Obj.Section->Data = new char[Stop-Start+2]; + + memcpy(Obj.Section->Data, Start, Stop - Start); + Obj.Section->Data[Stop-Start] = '\n'; + Obj.Section->Data[Stop-Start+1] = '\0'; + // Rescan it + if(Obj.Section->Object.Scan(Obj.Section->Data, Stop-Start+2) == false) + return HandleErrors(NULL); + + Py_INCREF(Obj.Section); + return HandleErrors(Obj.Section); +} + +static PyObject *TagFileIter(PyObject *Self) { + Py_INCREF(Self); + return Self; +} + +static char *doc_Offset = + "offset() -> int\n\n" + "Return the current offset."; +static PyObject *TagFileOffset(PyObject *Self,PyObject *Args) +{ + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + return MkPyNumber(((TagFileData *)Self)->Object.Offset()); + +} + +static char *doc_Jump = + "jump(offset: int) -> bool\n\n" + "Jump to the given offset; return True on success. Note that jumping to\n" + "an offset is not very reliable, and the 'section' attribute may point\n" + "to an unexpected section."; +static PyObject *TagFileJump(PyObject *Self,PyObject *Args) +{ + int Offset; + if (PyArg_ParseTuple(Args,"i",&Offset) == 0) + return 0; + + TagFileData &Obj = *(TagFileData *)Self; + if (Obj.Object.Jump(Obj.Section->Object,Offset) == false) + return HandleErrors(PyBool_FromLong(0)); + + return HandleErrors(PyBool_FromLong(1)); +} + +static char *doc_Close = + "close()\n\n" + "Close the file."; +static PyObject *TagFileClose(PyObject *self, PyObject *args) +{ + if (args != NULL && !PyArg_ParseTuple(args, "")) + return NULL; + + TagFileData &Obj = *(TagFileData *) self; + + Obj.Fd.Close(); + + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + +static PyObject *TagFileExit(PyObject *self, PyObject *args) +{ + + PyObject *exc_type = 0; + PyObject *exc_value = 0; + PyObject *traceback = 0; + if (!PyArg_UnpackTuple(args, "__exit__", 3, 3, &exc_type, &exc_value, + &traceback)) { + return 0; + } + + PyObject *res = TagFileClose(self, NULL); + + if (res == NULL) { + // The close failed. If no exception happened within the suite, we + // will raise an error here. Otherwise, we just display the error, so + // Python can handle the original exception instead. + if (exc_type == Py_None) + return NULL; + + PyErr_WriteUnraisable(self); + } else { + Py_DECREF(res); + } + // Return False, as required by the context manager protocol. + Py_RETURN_FALSE; +} + +static PyObject *TagFileEnter(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + + Py_INCREF(self); + + return self; +} + + /*}}}*/ +// ParseSection - Parse a single section from a tag file /*{{{*/ +// --------------------------------------------------------------------- +static PyObject *TagSecNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) { + char *Data; + Py_ssize_t Len; + char Bytes = 0; + char *kwlist[] = {"text", "bytes", 0}; + + // this allows reading "byte" types from python3 - but we don't + // make (much) use of it yet + if (PyArg_ParseTupleAndKeywords(Args,kwds,"s#|b",kwlist,&Data,&Len,&Bytes) == 0) + return 0; + if (memchr(Data, 0, Len) != nullptr) { + PyErr_SetString(PyExc_ValueError, "Input contains NUL byte"); + return 0; + } + if (Data[Len] != 0) { + PyErr_SetString(PyExc_ValueError, "Input is not terminated by NUL byte"); + return 0; + } + + // Create the object.. + TagSecData *New = (TagSecData*)type->tp_alloc(type, 0); + new (&New->Object) pkgTagSection(); + New->Data = new char[strlen(Data)+2]; + snprintf(New->Data,strlen(Data)+2,"%s\n",Data); + New->Bytes = Bytes; +#if PY_MAJOR_VERSION >= 3 + New->Encoding = 0; +#endif + + if (New->Object.Scan(New->Data,strlen(New->Data)) == false) + { + cerr << New->Data << endl; + Py_DECREF((PyObject *)New); + PyErr_SetString(PyExc_ValueError,"Unable to parse section data"); + return 0; + } + + New->Object.Trim(); + + return New; +} + + /*}}}*/ +// ParseTagFile - Parse a tagd file /*{{{*/ +// --------------------------------------------------------------------- +/* This constructs the parser state. */ + +static PyObject *TagFileNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) +{ + PyObject *File = 0; + char Bytes = 0; + + char *kwlist[] = {"file", "bytes", 0}; + if (PyArg_ParseTupleAndKeywords(Args,kwds,"O|b",kwlist,&File,&Bytes) == 0) + return 0; + + // check if we got a filename or a file object + int fileno = -1; + PyApt_Filename filename; + if (!filename.init(File)) { + PyErr_Clear(); + fileno = PyObject_AsFileDescriptor(File); + } + + // handle invalid arguments + if (fileno == -1 && filename == NULL) + { + PyErr_SetString(PyExc_TypeError, + "Argument must be string, fd or have a fileno() method"); + return 0; + } + + PyApt_UniqueObject<TagFileData> New((TagFileData*)type->tp_alloc(type, 0)); + if (fileno != -1) + { +#ifdef APT_HAS_GZIP + new (&New->Fd) FileFd(); + New->Fd.OpenDescriptor(fileno, FileFd::ReadOnlyGzip, false); +#else + new (&New->Fd) FileFd(fileno,false); +#endif + } + else + { + // FileFd::Extension got added in this revision +#if (APT_PKG_MAJOR > 4 || (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 12)) + new (&New->Fd) FileFd(filename, FileFd::ReadOnly, FileFd::Extension, false); +#else + new (&New->Fd) FileFd(filename, FileFd::ReadOnly, false); +#endif + } + New->Bytes = Bytes; + New->Owner = File; + Py_INCREF(New->Owner); +#if PY_MAJOR_VERSION >= 3 + if (fileno != -1) { + New->Encoding = PyObject_GetAttr(File, PyUnicode_FromString("encoding")); + if (!New->Encoding) + PyErr_Clear(); + if (New->Encoding && !PyUnicode_Check(New->Encoding)) + New->Encoding = 0; + } else + New->Encoding = 0; + Py_XINCREF(New->Encoding); +#endif + new (&New->Object) pkgTagFile(&New->Fd); + + // Create the section + New->Section = (TagSecData*)(&PyTagSection_Type)->tp_alloc(&PyTagSection_Type, 0); + new (&New->Section->Object) pkgTagSection(); + New->Section->Owner = New.get(); + Py_INCREF(New->Section->Owner); + New->Section->Data = 0; + New->Section->Bytes = Bytes; +#if PY_MAJOR_VERSION >= 3 + New->Section->Encoding = New->Encoding; + Py_XINCREF(New->Section->Encoding); +#endif + + return HandleErrors(New.release()); +} + /*}}}*/ + +// Method table for the Tag Section object +static PyMethodDef TagSecMethods[] = +{ + // Query + {"find",TagSecFind,METH_VARARGS,doc_Find}, + {"find_raw",TagSecFindRaw,METH_VARARGS,doc_FindRaw}, + {"find_flag",TagSecFindFlag,METH_VARARGS,doc_FindFlag}, + {"bytes",TagSecBytes,METH_VARARGS,doc_Bytes}, + {"write",(PyCFunction) TagSecWrite,METH_VARARGS|METH_KEYWORDS,doc_Write}, + + // Python Special + {"keys",TagSecKeys,METH_VARARGS,doc_Keys}, +#if PY_MAJOR_VERSION < 3 + {"has_key",TagSecExists,METH_VARARGS,doc_Exists}, +#endif + {"get",TagSecFind,METH_VARARGS,doc_Find}, + {} +}; + + +PySequenceMethods TagSecSeqMeth = {0,0,0,0,0,0,0,TagSecContains,0,0}; +PyMappingMethods TagSecMapMeth = {TagSecLength,TagSecMap,0}; + + +static char *doc_TagSec = "TagSection(text: str, [bytes: bool = False])\n\n" + "Provide methods to access RFC822-style header sections, like those\n" + "found in debian/control or Packages files.\n\n" + "TagSection() behave like read-only dictionaries and also provide access\n" + "to the functions provided by the C++ class (e.g. find).\n\n" + "By default, text read from files is treated as strings (binary data in\n" + "Python 2, Unicode strings in Python 3). Use bytes=True to cause all\n" + "header values read from this TagSection to be bytes even in Python 3.\n" + "Header names are always treated as Unicode."; +PyTypeObject PyTagSection_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.TagSection", // tp_name + sizeof(TagSecData), // tp_basicsize + 0, // tp_itemsize + // Methods + TagSecFree, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + &TagSecSeqMeth, // tp_as_sequence + &TagSecMapMeth, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + TagSecStr, // tp_str + _PyAptObject_getattro, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + (Py_TPFLAGS_DEFAULT | // tp_flags + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC), + doc_TagSec, // tp_doc + CppTraverse<pkgTagSection>, // tp_traverse + CppClear<pkgTagSection>, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + TagSecMethods, // tp_methods + 0, // tp_members + 0, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + TagSecNew, // tp_new +}; + +// Method table for the Tag File object +static PyMethodDef TagFileMethods[] = +{ + // Query + {"step",TagFileStep,METH_VARARGS,doc_Step}, + {"offset",TagFileOffset,METH_VARARGS,doc_Offset}, + {"jump",TagFileJump,METH_VARARGS,doc_Jump}, + {"close",TagFileClose,METH_VARARGS,doc_Close}, + {"__enter__",TagFileEnter,METH_VARARGS,"Context manager entry, return self."}, + {"__exit__",TagFileExit,METH_VARARGS,"Context manager exit, calls close."}, + + {} +}; + +// Return the current section. +static PyObject *TagFileGetSection(PyObject *Self,void*) { + PyObject *Obj = ((TagFileData *)Self)->Section; + Py_INCREF(Obj); + return Obj; +} + +static PyGetSetDef TagFileGetSet[] = { + {"section",TagFileGetSection,0, + "The current section, as a TagSection object.",0}, + {} +}; + + +static char *doc_TagFile = "TagFile(file, [bytes: bool = False])\n\n" + "TagFile() objects provide access to debian control files, which consist\n" + "of multiple RFC822-style sections.\n\n" + "To provide access to those sections, TagFile objects provide an iterator\n" + "which yields TagSection objects for each section.\n\n" + "TagFile objects also provide another API which uses a shared TagSection\n" + "object in the 'section' member. The functions step() and jump() can be\n" + "used to navigate within the file; offset() returns the current\n" + "position.\n\n" + "It is important to not mix the use of both APIs, because this can have\n" + "unwanted effects.\n\n" + "The parameter 'file' refers to an object providing a fileno() method or\n" + "a file descriptor (an integer).\n\n" + "By default, text read from files is treated as strings (binary data in\n" + "Python 2, Unicode strings in Python 3). Use bytes=True to cause all\n" + "header values read from this TagFile to be bytes even in Python 3.\n" + "Header names are always treated as Unicode."; + +// Type for a Tag File +PyTypeObject PyTagFile_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.TagFile", // tp_name + sizeof(TagFileData), // tp_basicsize + 0, // tp_itemsize + // Methods + TagFileFree, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + _PyAptObject_getattro, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + (Py_TPFLAGS_DEFAULT | // tp_flags + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC), + doc_TagFile, // tp_doc + TagFileTraverse, // tp_traverse + TagFileClear, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + TagFileIter, // tp_iter + TagFileNext, // tp_iternext + TagFileMethods, // tp_methods + 0, // tp_members + TagFileGetSet, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + TagFileNew, // tp_new + +}; + + +// Return the current section. +static PyObject *TagGetAction(PyObject *Self,void*) { + return MkPyNumber(GetCpp<pkgTagSection::Tag>(Self).Action); +} + +static PyObject *TagGetName(PyObject *Self,void*) { + return CppPyString(GetCpp<pkgTagSection::Tag>(Self).Name); +} + +static PyObject *TagGetData(PyObject *Self,void*) { + return CppPyString(GetCpp<pkgTagSection::Tag>(Self).Data); +} + +static PyObject *PyTagRename_New(PyTypeObject *type,PyObject *Args,PyObject *kwds) { + char *oldName; + char *newName; + char *kwlist[] = {"old_name", "new_name", 0}; + + if (PyArg_ParseTupleAndKeywords(Args,kwds,"ss",kwlist, &oldName, &newName) == 0) + return nullptr; + if (oldName[0] == '\0') { + PyErr_SetString(PyExc_ValueError, "Old tag name may not be empty."); + return nullptr; + } + if (newName[0] == '\0') { + PyErr_SetString(PyExc_ValueError, "New tag name may not be empty."); + return nullptr; + } + + auto tag = pkgTagSection::Tag::Rename(oldName, newName); + return CppPyObject_NEW<pkgTagSection::Tag>(nullptr, type, tag); +} + +static PyObject *PyTagRewrite_New(PyTypeObject *type,PyObject *Args,PyObject *kwds) { + char *name; + char *data; + char *kwlist[] = {"name", "data", 0}; + + if (PyArg_ParseTupleAndKeywords(Args,kwds,"ss",kwlist, &name, &data) == 0) + return nullptr; + if (name[0] == '\0') { + PyErr_SetString(PyExc_ValueError, "Tag name may not be empty."); + return nullptr; + } + if (data[0] == '\0') { + PyErr_SetString(PyExc_ValueError, "New value may not be empty."); + return nullptr; + } + + auto tag = pkgTagSection::Tag::Rewrite(name, data); + return CppPyObject_NEW<pkgTagSection::Tag>(nullptr, type, tag); +} + +static PyObject *PyTagRemove_New(PyTypeObject *type,PyObject *Args,PyObject *kwds) { + char *name; + char *kwlist[] = {"name", nullptr}; + + if (PyArg_ParseTupleAndKeywords(Args,kwds,"s",kwlist, &name) == 0) + return nullptr; + if (name[0] == '\0') { + PyErr_SetString(PyExc_ValueError, "Tag name may not be empty."); + return nullptr; + } + + auto tag = pkgTagSection::Tag::Remove(name); + return CppPyObject_NEW<pkgTagSection::Tag>(nullptr, type, tag); +} + +static PyGetSetDef TagGetSet[] = { + {"action",TagGetAction,0, + "The action to perform.",0}, + {"name",TagGetName,0, + "The name of the tag to perform the action on.",0}, + {"data",TagGetData,0, + "The data to write instead (for REWRITE), or the new tag name (RENAME)",0}, + {} +}; + +static char doc_Tag[] = "Tag\n\n" + "Identify actions to be executed on a task\n" + "\n" + "This is used in conjunction with :meth:`TagSection.write` to rewrite\n" + "a tag section into a new one.\n" + "\n" + "This class is abstract, use one of the subclasses:\n" + ":class:`TagRewrite`, :class:`TagRemove`, :class:`TagRename`\n" + "\n" + ".. versionadded:: 1.1"; + +static char doc_TagRewrite[] = "TagRewrite(name: str, data: str)\n\n" + "Change the value of the tag to the string passed in *data*\n" + "\n" + ".. versionadded:: 1.1"; +static char doc_TagRename[] = "TagRename(old_name: str, new_name: str)\n\n" + "Rename the tag *old_name* to *new_name*\n" + "\n" + ".. versionadded:: 1.1"; + +static char doc_TagRemove[] = "TagRemove(name: str)\n\n" + "Remove the tag *name* from the tag section\n" + "\n" + ".. versionadded:: 1.1"; + + +// Type for a Tag File +PyTypeObject PyTag_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.Tag", // tp_name + sizeof(CppPyObject<pkgTagSection::Tag>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<pkgTagSection::Tag>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + (Py_TPFLAGS_DEFAULT // tp_flags + | Py_TPFLAGS_BASETYPE), + doc_Tag, // tp_doc + CppTraverse<pkgTagSection::Tag>, // tp_traverse + CppClear<pkgTagSection::Tag>, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + 0, // tp_methods + 0, // tp_members + TagGetSet, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + 0, // tp_new +}; + +// Type for a Tag File +PyTypeObject PyTagRewrite_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.TagRewrite", // tp_name + sizeof(CppPyObject<pkgTagSection::Tag>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<pkgTagSection::Tag>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT, // tp_flags + doc_TagRewrite, // tp_doc + CppTraverse<pkgTagSection::Tag>, // tp_traverse + CppClear<pkgTagSection::Tag>, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + 0, // tp_methods + 0, // tp_members + 0, // tp_getset + &PyTag_Type, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + PyTagRewrite_New, // tp_new +}; + +// Type for a Tag File +PyTypeObject PyTagRemove_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.TagRemove", // tp_name + sizeof(CppPyObject<pkgTagSection::Tag>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<pkgTagSection::Tag>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT, // tp_flags + doc_TagRemove, // tp_doc + CppTraverse<pkgTagSection::Tag>, // tp_traverse + CppClear<pkgTagSection::Tag>, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + 0, // tp_methods + 0, // tp_members + 0, // tp_getset + &PyTag_Type, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + PyTagRemove_New, // tp_new +}; + +// Type for a Tag File +PyTypeObject PyTagRename_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.TagRename", // tp_name + sizeof(CppPyObject<pkgTagSection::Tag>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<pkgTagSection::Tag>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT, // tp_flags + doc_TagRename, // tp_doc + CppTraverse<pkgTagSection::Tag>, // tp_traverse + CppClear<pkgTagSection::Tag>, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + 0, // tp_methods + 0, // tp_members + 0, // tp_getset + &PyTag_Type, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + PyTagRename_New, // tp_new +}; |