diff options
| -rw-r--r-- | debian/control | 9 | ||||
| -rw-r--r-- | debian/python-apt.dirs | 1 | ||||
| -rwxr-xr-x | debian/rules | 23 | ||||
| -rwxr-xr-x | doc/examples/config.py | 55 | ||||
| -rwxr-xr-x | doc/examples/configisc.py | 39 | ||||
| -rwxr-xr-x | doc/examples/tagfile.py | 8 | ||||
| -rwxr-xr-x | doc/examples/versiontest.py | 36 | ||||
| -rw-r--r-- | python/apt_instmodule.cc | 83 | ||||
| -rw-r--r-- | python/apt_pkgmodule.cc | 357 | ||||
| -rw-r--r-- | python/apt_pkgmodule.h | 65 | ||||
| -rw-r--r-- | python/cache.cc | 731 | ||||
| -rw-r--r-- | python/configuration.cc | 523 | ||||
| -rw-r--r-- | python/generic.cc | 86 | ||||
| -rw-r--r-- | python/generic.h | 132 | ||||
| -rw-r--r-- | python/makefile | 21 | ||||
| -rw-r--r-- | python/pkgrecords.cc | 119 | ||||
| -rw-r--r-- | python/string.cc | 96 | ||||
| -rw-r--r-- | python/tag.cc | 445 |
18 files changed, 2829 insertions, 0 deletions
diff --git a/debian/control b/debian/control new file mode 100644 index 00000000..7463bc9c --- /dev/null +++ b/debian/control @@ -0,0 +1,9 @@ +Package: python-apt +Architecture: any +Depends: ${shlibs:Depends} +Priority: optional +Description: Python interface to libapt-pkg + The apt-pkg Python interface will provide full access to the internal + libapt-pkg structures allowing Python programs to easially perform a + variety of functions. + diff --git a/debian/python-apt.dirs b/debian/python-apt.dirs new file mode 100644 index 00000000..621814df --- /dev/null +++ b/debian/python-apt.dirs @@ -0,0 +1 @@ +usr/lib/python1.5/site-packages diff --git a/debian/rules b/debian/rules new file mode 100755 index 00000000..a6919824 --- /dev/null +++ b/debian/rules @@ -0,0 +1,23 @@ + +python-apt: build debian/shlibs.local + dh_testdir -p$@ + dh_testroot -p$@ + dh_clean -p$@ -k + dh_installdirs -p$@ + + # install the modules + cp $(BLD)/bin/apt_pkgmodule.so $(BLD)/bin/apt_instmodule.so debian/$@/usr/lib/python$(PYTHONVER)/site-packages/ + + dh_installdocs -p$@ + dh_installexamples -p$@ $(BLD)/docs/examples/python/* + + dh_installchangelogs -p$@ + dh_strip -p$@ + dh_compress -p$@ + dh_fixperms -p$@ + dh_installdeb -p$@ + LD_LIBRARY_PATH=`pwd`/debian/tmp/usr/lib:`pwd`/debian/apt-utils/usr/lib dh_shlibdeps -p$@ + dh_gencontrol -p$@ + dh_md5sums -p$@ + dh_builddeb -p$@ + diff --git a/doc/examples/config.py b/doc/examples/config.py new file mode 100755 index 00000000..222c1331 --- /dev/null +++ b/doc/examples/config.py @@ -0,0 +1,55 @@ +#!/usr/bin/python +# Example demonstrating how to use the configuration/commandline system +# for configuration. +# Some valid command lines.. +# config.py -h --help ; Turn on help +# config.py -no-h --no-help --help=no ; Turn off help +# config.py -qqq -q=3 ; verbosity to 3 +# config.py -c /etc/apt/apt.conf ; include that config file] +# config.py -o help=true ; Turn on help by giving a config file string +# config.py -no-h -- -help ; Turn off help, specify the file '-help' +# -c and -o are standard APT-program options. + +# This shows how to use the system for configuration and option control. +# The other varient is for ISC object config files. See configisc.py. +import apt_pkg,sys,posixpath; + +# Create a new empty Configuration object - there is also the system global +# configuration object apt_pkg.Config which is used interally by apt-pkg +# routines to control unusual situations. I recommend using the sytem global +# whenever possible.. +Cnf = apt_pkg.newConfiguration(); + +print "Command line is",sys.argv + +# Load the default configuration file, InitConfig() does this better.. +Cnf.Set("config-file","/etc/apt/apt.conf"); # or Cnf["config-file"] = ".."; +if posixpath.exists(Cnf.FindFile("config-file")): + apt_pkg.ReadConfigFile(Cnf,"/etc/apt/apt.conf"); + +# Merge the command line arguments into the configuration space +Arguments = [('h',"help","help"), + ('v',"version","version"), + ('q',"quiet","quiet","IntLevel"), + ('c',"config-file","","ConfigFile"), + ('o',"option","","ArbItem")] +print "FileNames",apt_pkg.ParseCommandLine(Cnf,Arguments,sys.argv); + +print "Quiet level selected is",Cnf.FindI("quiet",0); + +# Do some stuff with it +if Cnf.FindB("version",0) == 1: + print "Version selected - 1.1"; + +if Cnf.FindB("help",0) == 1: + print apt_pkg.Package,apt_pkg.Version,"for",apt_pkg.Architecture, \ + "compiled on",apt_pkg.Date,apt_pkg.Time; + print "Hi, I am the help text for this program"; + sys.exit(0); + +print "No help for you, try -h"; + +# Print the configuration space +print "The Configuration space looks like:"; +for I in Cnf.keys(): + print "%s \"%s\";"%(I,Cnf[I]); diff --git a/doc/examples/configisc.py b/doc/examples/configisc.py new file mode 100755 index 00000000..1773a919 --- /dev/null +++ b/doc/examples/configisc.py @@ -0,0 +1,39 @@ +#!/usr/bin/python +# Example demonstrating how to use the configuration/commandline system +# for object setup. + +# This parses the given config file in 'ISC' style where the sections +# represent object instances and shows how to iterate over the sections. +# Pass it the sample apt-ftparchive configuration, +# doc/examples/ftp-archive.conf +# or a bind8 config file.. + +import apt_pkg,sys,posixpath; + +ConfigFile = apt_pkg.ParseCommandLine(apt_pkg.Config,[],sys.argv); + +if len(ConfigFile) != 1: + print "Must have exactly 1 file name"; + sys.exit(0); + +Cnf = apt_pkg.newConfiguration(); +apt_pkg.ReadConfigFileISC(Cnf,ConfigFile[0]); + +# Print the configuration space +#print "The Configuration space looks like:"; +#for I in Cnf.keys(): +# print "%s \"%s\";"%(I,Cnf[I]); + +# bind8 config file.. +if Cnf.has_key("Zone"): + print "Zones: ",Cnf.SubTree("zone").List(); + for I in Cnf.List("zone"): + SubCnf = Cnf.SubTree(I); + if SubCnf.Find("type") == "slave": + print "Masters for %s: %s"%(SubCnf.MyTag(),SubCnf.ValueList("masters")); +else: + print "Tree definitions:"; + for I in Cnf.List("tree"): + SubCnf = Cnf.SubTree(I); + # This could use Find which would eliminate the possibility of exceptions. + print "Subtree %s with sections '%s' and architectures '%s'"%(SubCnf.MyTag(),SubCnf["Sections"],SubCnf["Architectures"]); diff --git a/doc/examples/tagfile.py b/doc/examples/tagfile.py new file mode 100755 index 00000000..01fed2cc --- /dev/null +++ b/doc/examples/tagfile.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python +import apt_pkg + +Parse = apt_pkg.ParseTagFile(open("apt/lists/_org_ftp.debian.org_ftp_dists_potato_main_binary-i386_Packages","r")); + +while Parse.Step() == 1: + print Parse.Section.get("Package"); + print apt_pkg.ParseDepends(Parse.Section.get("Depends","")); diff --git a/doc/examples/versiontest.py b/doc/examples/versiontest.py new file mode 100755 index 00000000..95f887f2 --- /dev/null +++ b/doc/examples/versiontest.py @@ -0,0 +1,36 @@ +#!/usr/bin/python + +# This is a simple clone of tests/versiontest.cc +import apt_pkg,sys,re,string; +apt_pkg.InitConfig(); +apt_pkg.InitSystem(); + +TestFile = apt_pkg.ParseCommandLine(apt_pkg.Config,[],sys.argv); +if len(TestFile) != 1: + print "Must have exactly 1 file name"; + sys.exit(0); + +# Go over the file.. +List = open(TestFile[0],"r"); +CurLine = 0; +while(1): + Line = List.readline(); + CurLine = CurLine + 1; + if Line == "": + break; + Line = string.strip(Line); + if len(Line) == 0 or Line[0] == '#': + continue; + + Split = re.split("[ \n]",Line); + + # Check forward + if apt_pkg.VersionCompare(Split[0],Split[1]) != int(Split[2]): + print "Comparision failed on line %u. '%s' ? '%s' %i != %i"%(CurLine, + Split[0],Split[1],apt_pkg.VersionCompare(Split[0],Split[1]), + int(Split[2])); + # Check reverse + if apt_pkg.VersionCompare(Split[1],Split[0]) != -1*int(Split[2]): + print "Comparision failed on line %u. '%s' ? '%s' %i != %i"%(CurLine, + Split[1],Split[0],apt_pkg.VersionCompare(Split[1],Split[0]), + -1*int(Split[2])); diff --git a/python/apt_instmodule.cc b/python/apt_instmodule.cc new file mode 100644 index 00000000..519d4730 --- /dev/null +++ b/python/apt_instmodule.cc @@ -0,0 +1,83 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: apt_instmodule.cc,v 1.1 2001/02/20 06:32:01 jgg Exp $ +/* ###################################################################### + + apt_intmodule - Top level for the python module. Create the internal + structures for the module in the interpriter. + + Note, this module shares state (particularly global config) with the + apt_pkg module. + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include "generic.h" + +#include <apt-pkg/debfile.h> +#include <apt-pkg/error.h> + +#include <sys/stat.h> +#include <unistd.h> +#include <python/Python.h> + /*}}}*/ + +// debExtractControl - Exctract an arbitary control member /*{{{*/ +// --------------------------------------------------------------------- +/* This is a common operation so this function will stay, but others that + expose the full range of the apt-inst .deb processing will join it some + day. */ +static char *doc_debExtractControl = +"debExtractControl(File[,Member]) -> String\n" +"Returns the indicated file from the control tar. The default is 'control'\n"; +static PyObject *debExtractControl(PyObject *Self,PyObject *Args) +{ + char *Member = "control"; + PyObject *File; + if (PyArg_ParseTuple(Args,"O!|s",&PyFile_Type,&File,&Member) == 0) + return 0; + + // Subscope makes sure any clean up errors are properly handled. + PyObject *Res = 0; + { + // Open the file and associate the .deb + FileFd Fd(fileno(PyFile_AsFile(File)),false); + debDebFile Deb(Fd); + if (_error->PendingError() == true) + return HandleErrors(); + + debDebFile::MemControlExtract Extract(Member); + if (Extract.Read(Deb) == false) + return HandleErrors(); + + // Build the return result + + if (Extract.Control == 0) + { + Py_INCREF(Py_None); + Res = Py_None; + } + else + Res = PyString_FromStringAndSize(Extract.Control,Extract.Length+2); + } + + return HandleErrors(Res); +} + /*}}}*/ + +// initapt_inst - Core Module Initialization /*{{{*/ +// --------------------------------------------------------------------- +/* */ +static PyMethodDef methods[] = +{ + // Stuff + {"debExtractControl",debExtractControl,METH_VARARGS,doc_debExtractControl}, + + {} +}; + +extern "C" void initapt_inst() +{ + Py_InitModule("apt_inst",methods); +} + /*}}}*/ diff --git a/python/apt_pkgmodule.cc b/python/apt_pkgmodule.cc new file mode 100644 index 00000000..ded265aa --- /dev/null +++ b/python/apt_pkgmodule.cc @@ -0,0 +1,357 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: apt_pkgmodule.cc,v 1.1 2001/02/20 06:32:01 jgg Exp $ +/* ###################################################################### + + apt_pkgmodule - Top level for the python module. Create the internal + structures for the module in the interpriter. + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include "apt_pkgmodule.h" +#include "generic.h" + +#include <apt-pkg/configuration.h> +#include <apt-pkg/version.h> +#include <apt-pkg/deblistparser.h> +#include <apt-pkg/pkgcache.h> +#include <apt-pkg/tagfile.h> +#include <apt-pkg/md5.h> +#include <apt-pkg/init.h> +#include <apt-pkg/pkgsystem.h> + +#include <sys/stat.h> +#include <unistd.h> +#include <python/Python.h> + /*}}}*/ + +// newConfiguration - Build a new configuration class /*{{{*/ +// --------------------------------------------------------------------- +static char *doc_newConfiguration = "Construct a configuration instance"; +static PyObject *newConfiguration(PyObject *self,PyObject *args) +{ + return CppPyObject_NEW<Configuration>(&ConfigurationType); +} + /*}}}*/ + +// Version Wrappers /*{{{*/ +// These are kind of legacy.. +static char *doc_VersionCompare = "VersionCompare(a,b) -> int"; +static PyObject *VersionCompare(PyObject *Self,PyObject *Args) +{ + char *A; + char *B; + int LenA; + int LenB; + + if (PyArg_ParseTuple(Args,"s#s#",&A,&LenA,&B,&LenB) == 0) + return 0; + + if (_system == 0) + { + PyErr_SetString(PyExc_ValueError,"_system not initialized"); + return 0; + } + + return Py_BuildValue("i",_system->VS->DoCmpVersion(A,A+LenA,B,B+LenB)); +} + +static char *doc_CheckDep = "CheckDep(PkgVer,DepOp,DepVer) -> int"; +static PyObject *CheckDep(PyObject *Self,PyObject *Args) +{ + char *A; + char *B; + char *OpStr; + unsigned int Op = 0; + + if (PyArg_ParseTuple(Args,"sss",&A,&OpStr,&B) == 0) + return 0; + if (*debListParser::ConvertRelation(OpStr,Op) != 0) + { + PyErr_SetString(PyExc_ValueError,"Bad comparision operation"); + return 0; + } + + if (_system == 0) + { + PyErr_SetString(PyExc_ValueError,"_system not initialized"); + return 0; + } + + return Py_BuildValue("i",_system->VS->CheckDep(A,Op,B)); +// return Py_BuildValue("i",pkgCheckDep(B,A,Op)); +} + +static char *doc_UpstreamVersion = "UpstreamVersion(a) -> string"; +static PyObject *UpstreamVersion(PyObject *Self,PyObject *Args) +{ + char *Ver; + if (PyArg_ParseTuple(Args,"s",&Ver) == 0) + return 0; + return CppPyString(_system->VS->UpstreamVersion(Ver)); +} + +static char *doc_ParseDepends = +"ParseDepends(s) -> list of tuples\n" +"\n" +"The resulting tuples are (Pkg,Ver,Operation). Each anded dependency is a\n" +"list of or'd dependencies\n" +"Source depends are evaluated against the curernt arch and only those that\n" +"Match are returned."; +static PyObject *RealParseDepends(PyObject *Self,PyObject *Args, + bool ParseArchFlags) +{ + string Package; + string Version; + unsigned int Op; + + const char *Start; + const char *Stop; + int Len; + + if (PyArg_ParseTuple(Args,"s#",&Start,&Len) == 0) + return 0; + Stop = Start + Len; + + PyObject *List = PyList_New(0); + PyObject *LastRow = 0; + while (1) + { + if (Start == Stop) + break; + + Start = debListParser::ParseDepends(Start,Stop,Package,Version,Op, + ParseArchFlags); + if (Start == 0) + { + PyErr_SetString(PyExc_ValueError,"Problem Parsing Dependency"); + Py_DECREF(List); + return 0; + } + + if (LastRow == 0) + LastRow = PyList_New(0); + + if (Package.empty() == false) + { + PyObject *Obj; + PyList_Append(LastRow,Obj = Py_BuildValue("sss",Package.c_str(), + Version.c_str(), + pkgCache::CompTypeDeb(Op))); + Py_DECREF(Obj); + } + + // Group ORd deps into a single row.. + if ((Op & pkgCache::Dep::Or) != pkgCache::Dep::Or) + { + if (PyList_Size(LastRow) != 0) + PyList_Append(List,LastRow); + Py_DECREF(LastRow); + LastRow = 0; + } + } + return List; +} +static PyObject *ParseDepends(PyObject *Self,PyObject *Args) +{ + return RealParseDepends(Self,Args,false); +} +static PyObject *ParseSrcDepends(PyObject *Self,PyObject *Args) +{ + return RealParseDepends(Self,Args,true); +} + /*}}}*/ +// md5sum - Compute the md5sum of a file or string /*{{{*/ +// --------------------------------------------------------------------- +static char *doc_md5sum = "md5sum(String) -> String or md5sum(File) -> String"; +static PyObject *md5sum(PyObject *Self,PyObject *Args) +{ + PyObject *Obj; + if (PyArg_ParseTuple(Args,"O",&Obj) == 0) + return 0; + + // Digest of a string. + if (PyString_Check(Obj) != 0) + { + MD5Summation Sum; + Sum.Add(PyString_AsString(Obj)); + return CppPyString(Sum.Result().Value()); + } + + // Digest of a file + if (PyFile_Check(Obj) != 0) + { + MD5Summation Sum; + int Fd = fileno(PyFile_AsFile(Obj)); + struct stat St; + if (fstat(Fd,&St) != 0 || + Sum.AddFD(Fd,St.st_size) == false) + { + PyErr_SetFromErrno(PyExc_SystemError); + return 0; + } + + return CppPyString(Sum.Result().Value()); + } + + PyErr_SetString(PyExc_TypeError,"Only understand strings and files"); + return 0; +} + /*}}}*/ +// init - 3 init functions /*{{{*/ +// --------------------------------------------------------------------- +static char *doc_Init = +"init() -> None\n" +"Legacy. Do InitConfig then parse the command line then do InitSystem\n"; +static PyObject *Init(PyObject *Self,PyObject *Args) +{ + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + pkgInitConfig(*_config); + pkgInitSystem(*_config,_system); + + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + +static char *doc_InitConfig = +"initconfig() -> None\n" +"Load the default configuration and the config file\n"; +static PyObject *InitConfig(PyObject *Self,PyObject *Args) +{ + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + pkgInitConfig(*_config); + + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + +static char *doc_InitSystem = +"initsystem() -> None\n" +"Construct the underlying system\n"; +static PyObject *InitSystem(PyObject *Self,PyObject *Args) +{ + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + pkgInitSystem(*_config,_system); + + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + /*}}}*/ + +// initapt_pkg - Core Module Initialization /*{{{*/ +// --------------------------------------------------------------------- +/* */ +static PyMethodDef methods[] = +{ + // Constructors + {"newConfiguration",newConfiguration,METH_VARARGS,doc_newConfiguration}, + {"init",Init,METH_VARARGS,doc_Init}, + {"InitConfig",InitConfig,METH_VARARGS,doc_InitConfig}, + {"InitSystem",InitSystem,METH_VARARGS,doc_InitSystem}, + + // Tag File + {"ParseSection",ParseSection,METH_VARARGS,doc_ParseSection}, + {"ParseTagFile",ParseTagFile,METH_VARARGS,doc_ParseTagFile}, + {"RewriteSection",RewriteSection,METH_VARARGS,doc_RewriteSection}, + + // Command line + {"ReadConfigFile",LoadConfig,METH_VARARGS,doc_LoadConfig}, + {"ReadConfigFileISC",LoadConfigISC,METH_VARARGS,doc_LoadConfig}, + {"ParseCommandLine",ParseCommandLine,METH_VARARGS,doc_ParseCommandLine}, + + // Versioning + {"VersionCompare",VersionCompare,METH_VARARGS,doc_VersionCompare}, + {"CheckDep",CheckDep,METH_VARARGS,doc_CheckDep}, + {"UpstreamVersion",UpstreamVersion,METH_VARARGS,doc_UpstreamVersion}, + + // Depends + {"ParseDepends",ParseDepends,METH_VARARGS,doc_ParseDepends}, + {"ParseSrcDepends",ParseSrcDepends,METH_VARARGS,doc_ParseDepends}, + + // Stuff + {"md5sum",md5sum,METH_VARARGS,doc_md5sum}, + + // Strings + {"QuoteString",StrQuoteString,METH_VARARGS,"QuoteString(String,String) -> String"}, + {"DeQuoteString",StrDeQuote,METH_VARARGS,"DeQuoteString(String) -> String"}, + {"SizeToStr",StrSizeToStr,METH_VARARGS,"SizeToStr(int) -> String"}, + {"TimeToStr",StrTimeToStr,METH_VARARGS,"TimeToStr(int) -> String"}, + {"URItoFileName",StrURItoFileName,METH_VARARGS,"URItoFileName(String) -> String"}, + {"Base64Encode",StrBase64Encode,METH_VARARGS,"Base64Encode(String) -> String"}, + {"StringToBool",StrStringToBool,METH_VARARGS,"StringToBool(String) -> int"}, + {"TimeRFC1123",StrTimeRFC1123,METH_VARARGS,"TimeRFC1123(int) -> String"}, + {"StrToTime",StrStrToTime,METH_VARARGS,"StrToTime(String) -> Int"}, + + // Cache + {"GetCache",TmpGetCache,METH_VARARGS,"GetCache() -> PkgCache"}, + {"GetPkgRecords",GetPkgRecords,METH_VARARGS,"GetPkgRecords(Cache) -> PkgRecrods"}, + + {} +}; + +static void AddStr(PyObject *Dict,const char *Itm,const char *Str) +{ + PyObject *Obj = PyString_FromString(Str); + PyDict_SetItemString(Dict,(char *)Itm,Obj); + Py_DECREF(Obj); +} + +static void AddInt(PyObject *Dict,const char *Itm,unsigned long I) +{ + PyObject *Obj = Py_BuildValue("i",I); + PyDict_SetItemString(Dict,(char *)Itm,Obj); + Py_DECREF(Obj); +} + +extern "C" void initapt_pkg() +{ + PyObject *Module = Py_InitModule("apt_pkg",methods); + PyObject *Dict = PyModule_GetDict(Module); + + // Global variable linked to the global configuration class + CppPyObject<Configuration *> *Config = CppPyObject_NEW<Configuration *>(&ConfigurationPtrType); + Config->Object = _config; + PyDict_SetItemString(Dict,"Config",Config); + Py_DECREF(Config); + + // Tag file constants + PyObject *Obj; + PyDict_SetItemString(Dict,"RewritePackageOrder", + Obj = CharCharToList(TFRewritePackageOrder)); + Py_DECREF(Obj); + PyDict_SetItemString(Dict,"RewriteSourceOrder", + Obj = CharCharToList(TFRewriteSourceOrder)); + Py_DECREF(Obj); + + // Version.. + AddStr(Dict,"Version",pkgVersion); + AddStr(Dict,"LibVersion",pkgLibVersion); + AddStr(Dict,"CPU",pkgCPU); + AddStr(Dict,"OS",pkgOS); + AddStr(Dict,"Date",__DATE__); + AddStr(Dict,"Time",__TIME__); + + // My constants!! + AddInt(Dict,"DepDepends",pkgCache::Dep::Depends); + AddInt(Dict,"DepPreDepends",pkgCache::Dep::PreDepends); + AddInt(Dict,"DepSuggests",pkgCache::Dep::Suggests); + AddInt(Dict,"DepRecommends",pkgCache::Dep::Recommends); + AddInt(Dict,"DepConflicts",pkgCache::Dep::Conflicts); + AddInt(Dict,"DepReplaces",pkgCache::Dep::Replaces); + AddInt(Dict,"DepObsoletes",pkgCache::Dep::Obsoletes); + + AddInt(Dict,"PriImportant",pkgCache::State::Important); + AddInt(Dict,"PriRequired",pkgCache::State::Required); + AddInt(Dict,"PriStandard",pkgCache::State::Standard); + AddInt(Dict,"PriOptional",pkgCache::State::Optional); + AddInt(Dict,"PriExtra",pkgCache::State::Extra); +} + /*}}}*/ + diff --git a/python/apt_pkgmodule.h b/python/apt_pkgmodule.h new file mode 100644 index 00000000..5398bd96 --- /dev/null +++ b/python/apt_pkgmodule.h @@ -0,0 +1,65 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: apt_pkgmodule.h,v 1.1 2001/02/20 06:32:01 jgg Exp $ +/* ###################################################################### + + Prototypes for the module + + ##################################################################### */ + /*}}}*/ +#ifndef APT_PKGMODULE_H +#define APT_PKGMODULE_H + +#include <python/Python.h> + +// Configuration Stuff +#define Configuration_Check(op) ((op)->ob_type == &ConfigurationType || \ + (op)->ob_type == &ConfigurationPtrType || \ + (op)->ob_type == &ConfigurationSubType) +extern PyTypeObject ConfigurationType; +extern PyTypeObject ConfigurationPtrType; +extern PyTypeObject ConfigurationSubType; +extern PyTypeObject VersionType; + +extern char *doc_LoadConfig; +extern char *doc_LoadConfigISC; +extern char *doc_ParseCommandLine; +PyObject *LoadConfig(PyObject *Self,PyObject *Args); +PyObject *LoadConfigISC(PyObject *Self,PyObject *Args); +PyObject *ParseCommandLine(PyObject *Self,PyObject *Args); + +// Tag File Stuff +extern PyTypeObject TagSecType; +extern PyTypeObject TagFileType; +extern char *doc_ParseSection; +extern char *doc_ParseTagFile; +extern char *doc_RewriteSection; +PyObject *ParseSection(PyObject *self,PyObject *Args); +PyObject *ParseTagFile(PyObject *self,PyObject *Args); +PyObject *RewriteSection(PyObject *self,PyObject *Args); + +// String Stuff +PyObject *StrQuoteString(PyObject *self,PyObject *Args); +PyObject *StrDeQuote(PyObject *self,PyObject *Args); +PyObject *StrSizeToStr(PyObject *self,PyObject *Args); +PyObject *StrTimeToStr(PyObject *self,PyObject *Args); +PyObject *StrURItoFileName(PyObject *self,PyObject *Args); +PyObject *StrBase64Encode(PyObject *self,PyObject *Args); +PyObject *StrStringToBool(PyObject *self,PyObject *Args); +PyObject *StrTimeRFC1123(PyObject *self,PyObject *Args); +PyObject *StrStrToTime(PyObject *self,PyObject *Args); + +// Cache Stuff +extern PyTypeObject PkgCacheType; +extern PyTypeObject PkgListType; +extern PyTypeObject PackageType; +extern PyTypeObject PackageFileType; +extern PyTypeObject DependencyType; +extern PyTypeObject RDepListType; +PyObject *TmpGetCache(PyObject *Self,PyObject *Args); + +// PkgRecords Stuff +extern PyTypeObject PkgRecordsType; +PyObject *GetPkgRecords(PyObject *Self,PyObject *Args); + +#endif diff --git a/python/cache.cc b/python/cache.cc new file mode 100644 index 00000000..794b4f57 --- /dev/null +++ b/python/cache.cc @@ -0,0 +1,731 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: cache.cc,v 1.1 2001/02/20 06:32:01 jgg Exp $ +/* ###################################################################### + + Cache - Wrapper for the cache related functions + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include "generic.h" +#include "apt_pkgmodule.h" + +#include <apt-pkg/pkgcache.h> +#include <apt-pkg/cachefile.h> +#include <apt-pkg/sptr.h> + +#include <python/Python.h> + /*}}}*/ + +struct PkgListStruct +{ + pkgCache::PkgIterator Iter; + unsigned long LastIndex; + + PkgListStruct(pkgCache::PkgIterator const &I) : Iter(I), LastIndex(0) {} + PkgListStruct() {abort();}; // G++ Bug.. +}; + +struct RDepListStruct +{ + pkgCache::DepIterator Iter; + pkgCache::DepIterator Start; + unsigned long LastIndex; + unsigned long Len; + + RDepListStruct(pkgCache::DepIterator const &I) : Iter(I), Start(I), + LastIndex(0) + { + Len = 0; + pkgCache::DepIterator D = I; + for (; D.end() == false; D++) + Len++; + } + RDepListStruct() {abort();}; // G++ Bug.. +}; + +static PyObject *CreateProvides(PyObject *Owner,pkgCache::PrvIterator I) +{ + PyObject *List = PyList_New(0); + for (; I.end() == false; I++) + { + PyObject *Obj; + PyObject *Ver; + Ver = CppOwnedPyObject_NEW<pkgCache::VerIterator>(Owner,&VersionType, + I.OwnerVer()); + Obj = Py_BuildValue("ssN",I.ParentPkg().Name(),I.ProvideVersion(), + Ver); + PyList_Append(List,Obj); + Py_DECREF(Obj); + } + return List; +} + +// Cache Class /*{{{*/ +// --------------------------------------------------------------------- +static PyObject *CacheAttr(PyObject *Self,char *Name) +{ + pkgCache *Cache = GetCpp<pkgCache *>(Self); + + if (strcmp("Packages",Name) == 0) + return CppOwnedPyObject_NEW<PkgListStruct>(Self,&PkgListType,Cache->PkgBegin()); + else if (strcmp("PackageCount",Name) == 0) + return Py_BuildValue("i",Cache->HeaderP->PackageCount); + else if (strcmp("VersionCount",Name) == 0) + return Py_BuildValue("i",Cache->HeaderP->VersionCount); + else if (strcmp("DependsCount",Name) == 0) + return Py_BuildValue("i",Cache->HeaderP->DependsCount); + else if (strcmp("PackageFileCount",Name) == 0) + return Py_BuildValue("i",Cache->HeaderP->PackageFileCount); + else if (strcmp("VerFileCount",Name) == 0) + return Py_BuildValue("i",Cache->HeaderP->VerFileCount); + else if (strcmp("ProvidesCount",Name) == 0) + return Py_BuildValue("i",Cache->HeaderP->ProvidesCount); + else if (strcmp("FileList",Name) == 0) + { + PyObject *List = PyList_New(0); + for (pkgCache::PkgFileIterator I = Cache->FileBegin(); I.end() == false; I++) + { + PyObject *Obj; + Obj = CppOwnedPyObject_NEW<pkgCache::PkgFileIterator>(Self,&PackageFileType,I); + PyList_Append(List,Obj); + Py_DECREF(Obj); + } + return List; + } + + PyErr_SetString(PyExc_AttributeError,Name); + return 0; +} + +// Map access, operator [] +static PyObject *CacheMapOp(PyObject *Self,PyObject *Arg) +{ + pkgCache *Cache = GetCpp<pkgCache *>(Self); + + if (PyString_Check(Arg) == 0) + { + PyErr_SetNone(PyExc_TypeError); + return 0; + } + + // Search for the package + const char *Name = PyString_AsString(Arg); + pkgCache::PkgIterator Pkg = Cache->FindPkg(Name); + if (Pkg.end() == true) + { + PyErr_SetString(PyExc_KeyError,Name); + return 0; + } + + return CppOwnedPyObject_NEW<pkgCache::PkgIterator>(Self,&PackageType,Pkg); +} + +static PyMappingMethods CacheMap = {0,CacheMapOp,0}; +PyTypeObject PkgCacheType = +{ + PyObject_HEAD_INIT(&PyType_Type) + 0, // ob_size + "pkgCache", // tp_name + sizeof(CppOwnedPyObject<pkgCache *>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppOwnedDealloc<pkgCache *>, // tp_dealloc + 0, // tp_print + CacheAttr, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + &CacheMap, // tp_as_mapping + 0, // tp_hash +}; + + /*}}}*/ +// Package List Class /*{{{*/ +// --------------------------------------------------------------------- +static int PkgListLen(PyObject *Self) +{ + return GetCpp<PkgListStruct>(Self).Iter.Cache()->HeaderP->PackageCount; +} + +static PyObject *PkgListItem(PyObject *iSelf,int Index) +{ + PkgListStruct &Self = GetCpp<PkgListStruct>(iSelf); + if (Index < 0 || (unsigned)Index >= Self.Iter.Cache()->HeaderP->PackageCount) + { + PyErr_SetNone(PyExc_IndexError); + return 0; + } + + if ((unsigned)Index < Self.LastIndex) + { + Self.LastIndex = 0; + Self.Iter = Self.Iter.Cache()->PkgBegin(); + } + + while ((unsigned)Index > Self.LastIndex) + { + Self.LastIndex++; + Self.Iter++; + if (Self.Iter.end() == true) + { + PyErr_SetNone(PyExc_IndexError); + return 0; + } + } + + return CppOwnedPyObject_NEW<pkgCache::PkgIterator>(GetOwner<PkgListStruct>(iSelf),&PackageType, + Self.Iter); +} + +static PySequenceMethods PkgListSeq = +{ + PkgListLen, + 0, // concat + 0, // repeat + PkgListItem, + 0, // slice + 0, // assign item + 0 // assign slice +}; + +PyTypeObject PkgListType = +{ + PyObject_HEAD_INIT(&PyType_Type) + 0, // ob_size + "pkgCache::PkgIterator", // tp_name + sizeof(CppOwnedPyObject<PkgListStruct>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppOwnedDealloc<PkgListStruct>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + &PkgListSeq, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash +}; + + /*}}}*/ +// Package Class /*{{{*/ +// --------------------------------------------------------------------- +static PyObject *PackageAttr(PyObject *Self,char *Name) +{ + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(Self); + PyObject *Owner = GetOwner<pkgCache::PkgIterator>(Self); + + if (strcmp("Name",Name) == 0) + return PyString_FromString(Pkg.Name()); + else if (strcmp("VersionList",Name) == 0) + { + PyObject *List = PyList_New(0); + for (pkgCache::VerIterator I = Pkg.VersionList(); I.end() == false; I++) + { + PyObject *Obj; + Obj = CppOwnedPyObject_NEW<pkgCache::VerIterator>(Owner,&VersionType,I); + PyList_Append(List,Obj); + Py_DECREF(Obj); + } + return List; + } + else if (strcmp("CurrentVer",Name) == 0) + { + if (Pkg->CurrentVer == 0) + { + Py_INCREF(Py_None); + return Py_None; + } + + return CppOwnedPyObject_NEW<pkgCache::VerIterator>(Owner,&VersionType, + Pkg.CurrentVer()); + } + else if (strcmp("Section",Name) == 0) + return Safe_FromString(Pkg.Section()); + else if (strcmp("RevDependsList",Name) == 0) + return CppOwnedPyObject_NEW<RDepListStruct>(Owner,&RDepListType, + Pkg.RevDependsList()); + else if (strcmp("ProvidesList",Name) == 0) + return CreateProvides(Owner,Pkg.ProvidesList()); + else if (strcmp("SelectedState",Name) == 0) + return Py_BuildValue("i",Pkg->SelectedState); + else if (strcmp("InstState",Name) == 0) + return Py_BuildValue("i",Pkg->InstState); + else if (strcmp("CurrentState",Name) == 0) + return Py_BuildValue("i",Pkg->CurrentState); + else if (strcmp("ID",Name) == 0) + return Py_BuildValue("i",Pkg->ID); + else if (strcmp("Auto",Name) == 0) + return Py_BuildValue("i",(Pkg->Flags & pkgCache::Flag::Auto) != 0); + else if (strcmp("Essential",Name) == 0) + return Py_BuildValue("i",(Pkg->Flags & pkgCache::Flag::Essential) != 0); + else if (strcmp("Important",Name) == 0) + return Py_BuildValue("i",(Pkg->Flags & pkgCache::Flag::Important) != 0); + + PyErr_SetString(PyExc_AttributeError,Name); + return 0; +} + +static PyObject *PackageRepr(PyObject *Self) +{ + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(Self); + + char S[300]; + snprintf(S,sizeof(S),"<pkgCache::Package object: Name:'%s' Section: '%s'" + " ID:%u Flags:0x%lX>", + Pkg.Name(),Pkg.Section(),Pkg->ID,Pkg->Flags); + return PyString_FromString(S); +} + +PyTypeObject PackageType = +{ + PyObject_HEAD_INIT(&PyType_Type) + 0, // ob_size + "pkgCache::Package", // tp_name + sizeof(CppOwnedPyObject<pkgCache::PkgIterator>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppOwnedDealloc<pkgCache::PkgIterator>, // tp_dealloc + 0, // tp_print + PackageAttr, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + PackageRepr, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash +}; + /*}}}*/ +// Version Class /*{{{*/ +// --------------------------------------------------------------------- + +/* This is the simple depends result, the elements are split like + ParseDepends does */ +static PyObject *MakeDepends(PyObject *Owner,pkgCache::VerIterator &Ver, + bool AsObj) +{ + PyObject *Dict = PyDict_New(); + PyObject *LastDep = 0; + unsigned LastDepType = 0; + for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++) + { + pkgCache::DepIterator Start; + pkgCache::DepIterator End; + D.GlobOr(Start,End); + + // Switch/create a new dict entry + if (LastDepType != Start->Type || LastDep != 0) + { + PyObject *Dep = PyString_FromString(Start.DepType()); + LastDepType = Start->Type; + LastDep = PyDict_GetItem(Dict,Dep); + if (LastDep == 0) + { + LastDep = PyList_New(0); + PyDict_SetItem(Dict,Dep,LastDep); + Py_DECREF(LastDep); + } + Py_DECREF(Dep); + } + + PyObject *OrGroup = PyList_New(0); + while (1) + { + PyObject *Obj; + if (AsObj == true) + Obj = CppOwnedPyObject_NEW<pkgCache::DepIterator>(Owner,&DependencyType, + Start); + else + { + if (Start->Version == 0) + Obj = Py_BuildValue("sss", + Start.TargetPkg().Name(), + "", + Start.CompType()); + else + Obj = Py_BuildValue("sss", + Start.TargetPkg().Name(), + Start.TargetVer(), + Start.CompType()); + } + PyList_Append(OrGroup,Obj); + Py_DECREF(Obj); + + if (Start == End) + break; + Start++; + } + + PyList_Append(LastDep,OrGroup); + Py_DECREF(OrGroup); + } + + return Dict; +} + +static PyObject *VersionAttr(PyObject *Self,char *Name) +{ + pkgCache::VerIterator &Ver = GetCpp<pkgCache::VerIterator>(Self); + PyObject *Owner = GetOwner<pkgCache::VerIterator>(Self); + + if (strcmp("VerStr",Name) == 0) + return PyString_FromString(Ver.VerStr()); + else if (strcmp("Section",Name) == 0) + return Safe_FromString(Ver.Section()); + else if (strcmp("Arch",Name) == 0) + return Safe_FromString(Ver.Arch()); + else if (strcmp("FileList",Name) == 0) + { + /* The second value in the tuple is the index of the VF item. If the + user wants to request a lookup then that number will be used. + Maybe later it can become an object. */ + PyObject *List = PyList_New(0); + for (pkgCache::VerFileIterator I = Ver.FileList(); I.end() == false; I++) + { + PyObject *PkgFile; + PyObject *Obj; + PkgFile = CppOwnedPyObject_NEW<pkgCache::PkgFileIterator>(Owner,&PackageFileType,I.File()); + Obj = Py_BuildValue("Nl",PkgFile,I.Index()); + PyList_Append(List,Obj); + Py_DECREF(Obj); + } + return List; + } + else if (strcmp("DependsListStr",Name) == 0) + return MakeDepends(Owner,Ver,false); + else if (strcmp("DependsList",Name) == 0) + return MakeDepends(Owner,Ver,true); + else if (strcmp("ParentPkg",Name) == 0) + return CppOwnedPyObject_NEW<pkgCache::PkgIterator>(Owner,&PackageType, + Ver.ParentPkg()); + else if (strcmp("ProvidesList",Name) == 0) + return CreateProvides(Owner,Ver.ProvidesList()); + else if (strcmp("Size",Name) == 0) + return Py_BuildValue("i",Ver->Size); + else if (strcmp("InstalledSize",Name) == 0) + return Py_BuildValue("i",Ver->InstalledSize); + else if (strcmp("Hash",Name) == 0) + return Py_BuildValue("i",Ver->Hash); + else if (strcmp("ID",Name) == 0) + return Py_BuildValue("i",Ver->ID); + else if (strcmp("Priority",Name) == 0) + return Py_BuildValue("i",Ver->Priority); + else if (strcmp("PriorityStr",Name) == 0) + return PyString_FromString(Ver.PriorityType()); + + PyErr_SetString(PyExc_AttributeError,Name); + return 0; +} + +static PyObject *VersionRepr(PyObject *Self) +{ + pkgCache::VerIterator &Ver = GetCpp<pkgCache::VerIterator>(Self); + + char S[300]; + snprintf(S,sizeof(S),"<pkgCache::Version object: Pkg:'%s' Ver:'%s' " + "Section:'%s' Arch:'%s' Size:%lu ISize:%lu Hash:%u " + "ID:%u Priority:%u>", + Ver.ParentPkg().Name(),Ver.VerStr(),Ver.Section(),Ver.Arch(), + (unsigned long)Ver->Size,(unsigned long)Ver->InstalledSize, + Ver->Hash,Ver->ID,Ver->Priority); + return PyString_FromString(S); +} + +PyTypeObject VersionType = +{ + PyObject_HEAD_INIT(&PyType_Type) + 0, // ob_size + "pkgCache::VerIterator", // tp_name + sizeof(CppOwnedPyObject<pkgCache::VerIterator>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppOwnedDealloc<pkgCache::VerIterator>, // tp_dealloc + 0, // tp_print + VersionAttr, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + VersionRepr, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash +}; + + /*}}}*/ +// PackageFile Class /*{{{*/ +// --------------------------------------------------------------------- +static PyObject *PackageFileAttr(PyObject *Self,char *Name) +{ + pkgCache::PkgFileIterator &File = GetCpp<pkgCache::PkgFileIterator>(Self); +// PyObject *Owner = GetOwner<pkgCache::PkgFileIterator>(Self); + + if (strcmp("FileName",Name) == 0) + return Safe_FromString(File.FileName()); + else if (strcmp("Archive",Name) == 0) + return Safe_FromString(File.Archive()); + else if (strcmp("Component",Name) == 0) + return Safe_FromString(File.Component()); + else if (strcmp("Version",Name) == 0) + return Safe_FromString(File.Version()); + else if (strcmp("Origin",Name) == 0) + return Safe_FromString(File.Origin()); + else if (strcmp("Label",Name) == 0) + return Safe_FromString(File.Label()); + else if (strcmp("Architecture",Name) == 0) + return Safe_FromString(File.Architecture()); + else if (strcmp("Site",Name) == 0) + return Safe_FromString(File.Site()); + else if (strcmp("IndexType",Name) == 0) + return Safe_FromString(File.IndexType()); + else if (strcmp("Size",Name) == 0) + return Py_BuildValue("i",File->Size); + else if (strcmp("NotSource",Name) == 0) + return Py_BuildValue("i",(File->Flags & pkgCache::Flag::NotSource) != 0); + else if (strcmp("NotAutomatic",Name) == 0) + return Py_BuildValue("i",(File->Flags & pkgCache::Flag::NotAutomatic) != 0); + else if (strcmp("ID",Name) == 0) + return Py_BuildValue("i",File->ID); + /* mtime is really a cookie these days and has no meaning outside the + list handlers */ + + PyErr_SetString(PyExc_AttributeError,Name); + return 0; +} + +static PyObject *PackageFileRepr(PyObject *Self) +{ + pkgCache::PkgFileIterator &File = GetCpp<pkgCache::PkgFileIterator>(Self); + + char S[300]; + snprintf(S,sizeof(S),"<pkgCache::PackageFile object: " + "File:'%s' a=%s,c=%s,v=%s,o=%s,l=%s " + "Arch='%s' Site='%s' IndexType='%s' Size=%lu " + "Flags=0x%lX ID:%u>", + File.FileName(),File.Archive(),File.Component(),File.Version(), + File.Origin(),File.Label(),File.Architecture(),File.Site(), + File.IndexType(),File->Size,File->Flags,File->ID); + return PyString_FromString(S); +} + +PyTypeObject PackageFileType = +{ + PyObject_HEAD_INIT(&PyType_Type) + 0, // ob_size + "pkgCache::PkgFileIterator", // tp_name + sizeof(CppOwnedPyObject<pkgCache::PkgFileIterator>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppOwnedDealloc<pkgCache::PkgFileIterator>, // tp_dealloc + 0, // tp_print + PackageFileAttr, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + PackageFileRepr, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash +}; + + /*}}}*/ +// Dependency Class /*{{{*/ +// --------------------------------------------------------------------- +static PyMethodDef DependencyMethods[]; + +static PyObject *DependencyAttr(PyObject *Self,char *Name) +{ + pkgCache::DepIterator &Dep = GetCpp<pkgCache::DepIterator>(Self); + PyObject *Owner = GetOwner<pkgCache::DepIterator>(Self); + + if (strcmp("TargetVer",Name) == 0) + { + if (Dep->Version == 0) + return PyString_FromString(""); + return PyString_FromString(Dep.TargetVer()); + } + else if (strcmp("TargetPkg",Name) == 0) + return CppOwnedPyObject_NEW<pkgCache::PkgIterator>(Owner,&PackageType, + Dep.TargetPkg()); + else if (strcmp("ParentVer",Name) == 0) + return CppOwnedPyObject_NEW<pkgCache::VerIterator>(Owner,&VersionType, + Dep.ParentVer()); + else if (strcmp("ParentPkg",Name) == 0) + return CppOwnedPyObject_NEW<pkgCache::PkgIterator>(Owner,&PackageType, Dep.ParentPkg()); + else if (strcmp("CompType",Name) == 0) + return PyString_FromString(Dep.CompType()); + else if (strcmp("DepType",Name) == 0) + return PyString_FromString(Dep.DepType()); + else if (strcmp("ID",Name) == 0) + return Py_BuildValue("i",Dep->ID); + + return Py_FindMethod(DependencyMethods,Self,Name); +} + +static PyObject *DependencyRepr(PyObject *Self) +{ + pkgCache::DepIterator &Dep = GetCpp<pkgCache::DepIterator>(Self); + + char S[300]; + snprintf(S,sizeof(S),"<pkgCache::Dependency object: " + "Pkg:'%s' Ver:'%s' Comp:'%s'>", + Dep.TargetPkg().Name(), + (Dep.TargetVer() == 0?"":Dep.TargetVer()), + Dep.CompType()); + return PyString_FromString(S); +} + +static PyObject *DepSmartTargetPkg(PyObject *Self,PyObject *Args) +{ + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + pkgCache::DepIterator &Dep = GetCpp<pkgCache::DepIterator>(Self); + PyObject *Owner = GetOwner<pkgCache::DepIterator>(Self); + + pkgCache::PkgIterator P; + if (Dep.SmartTargetPkg(P) == false) + { + Py_INCREF(Py_None); + return Py_None; + } + + return CppOwnedPyObject_NEW<pkgCache::PkgIterator>(Owner,&PackageType,P); +} + +static PyObject *DepAllTargets(PyObject *Self,PyObject *Args) +{ + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + pkgCache::DepIterator &Dep = GetCpp<pkgCache::DepIterator>(Self); + PyObject *Owner = GetOwner<pkgCache::DepIterator>(Self); + + SPtr<pkgCache::Version *> Vers = Dep.AllTargets(); + PyObject *List = PyList_New(0); + for (pkgCache::Version **I = Vers; *I != 0; I++) + { + PyObject *Obj; + Obj = CppOwnedPyObject_NEW<pkgCache::VerIterator>(Owner,&VersionType, + pkgCache::VerIterator(*Dep.Cache(),*I)); + PyList_Append(List,Obj); + Py_DECREF(Obj); + } + return List; +} + +static PyMethodDef DependencyMethods[] = +{ + {"SmartTargetPkg",DepSmartTargetPkg,METH_VARARGS,"Returns the natural Target or None"}, + {"AllTargets",DepAllTargets,METH_VARARGS,"Returns all possible Versions that match this dependency"}, + {} +}; + +PyTypeObject DependencyType = +{ + PyObject_HEAD_INIT(&PyType_Type) + 0, // ob_size + "pkgCache::DepIterator", // tp_name + sizeof(CppOwnedPyObject<pkgCache::DepIterator>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppOwnedDealloc<pkgCache::DepIterator>, // tp_dealloc + 0, // tp_print + DependencyAttr, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + DependencyRepr, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash +}; + + /*}}}*/ +// Reverse Dependency List Class /*{{{*/ +// --------------------------------------------------------------------- +static int RDepListLen(PyObject *Self) +{ + return GetCpp<RDepListStruct>(Self).Len; +} + +static PyObject *RDepListItem(PyObject *iSelf,int Index) +{ + RDepListStruct &Self = GetCpp<RDepListStruct>(iSelf); + if (Index < 0 || (unsigned)Index >= Self.Len) + { + PyErr_SetNone(PyExc_IndexError); + return 0; + } + + if ((unsigned)Index < Self.LastIndex) + { + Self.LastIndex = 0; + Self.Iter = Self.Start; + } + + while ((unsigned)Index > Self.LastIndex) + { + Self.LastIndex++; + Self.Iter++; + if (Self.Iter.end() == true) + { + PyErr_SetNone(PyExc_IndexError); + return 0; + } + } + + return CppOwnedPyObject_NEW<pkgCache::DepIterator>(GetOwner<RDepListStruct>(iSelf), + &DependencyType,Self.Iter); +} + +static PySequenceMethods RDepListSeq = +{ + RDepListLen, + 0, // concat + 0, // repeat + RDepListItem, + 0, // slice + 0, // assign item + 0 // assign slice +}; + +PyTypeObject RDepListType = +{ + PyObject_HEAD_INIT(&PyType_Type) + 0, // ob_size + "pkgCache::DepIterator", // tp_name + sizeof(CppOwnedPyObject<RDepListStruct>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppOwnedDealloc<RDepListStruct>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + &RDepListSeq, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash +}; + + /*}}}*/ + +PyObject *TmpGetCache(PyObject *Self,PyObject *Args) +{ + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + pkgCacheFile *Cache = new pkgCacheFile(); + OpTextProgress Prog; + if (Cache->Open(Prog,false) == false) + return HandleErrors(); + + return CppOwnedPyObject_NEW<pkgCache *>(0,&PkgCacheType,(pkgCache *)(*Cache)); +} diff --git a/python/configuration.cc b/python/configuration.cc new file mode 100644 index 00000000..9667f190 --- /dev/null +++ b/python/configuration.cc @@ -0,0 +1,523 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: configuration.cc,v 1.1 2001/02/20 06:32:01 jgg Exp $ +/* ###################################################################### + + Configuration - Binding for the configuration object. + + There are three seperate classes.. + Configuration - A stand alone configuration instance + ConfigurationPtr - A pointer to a configuration instance, used only + for the global instance (_config) + ConfigurationSub - A subtree - has a reference to its owner. + + The wrapping is mostly 1:1 with the C++ code, but there are additions to + wrap the linked tree walking into nice flat sequence walking. + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include "generic.h" +#include "apt_pkgmodule.h" + +#include <apt-pkg/configuration.h> +#include <apt-pkg/cmndline.h> + +#include <python/Python.h> + /*}}}*/ +static PyMethodDef CnfMethods[]; + +/* If we create a sub tree then it is of this type, the Owner is used + to manage reference counting. */ +struct SubConfiguration : public CppPyObject<Configuration> +{ + PyObject *Owner; +}; + +// CnfGetAttr - Get an attribute - variable/method /*{{{*/ +// --------------------------------------------------------------------- +/* */ +static PyObject *CnfGetAttr(PyObject *Self,char *Name) +{ + return Py_FindMethod(CnfMethods,Self,Name); +} + /*}}}*/ +// CnfSubFree - Free a sub configuration /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void CnfSubFree(PyObject *Obj) +{ + SubConfiguration *Self = (SubConfiguration *)Obj; + Py_DECREF(Self->Owner); + CppDealloc<Configuration>(Obj); +} + /*}}}*/ + +// GetSelf - Convert PyObject to Configuration /*{{{*/ +// --------------------------------------------------------------------- +/* */ +static inline Configuration &GetSelf(PyObject *Obj) +{ + if (Obj->ob_type == &ConfigurationPtrType) + return *GetCpp<Configuration *>(Obj); + return GetCpp<Configuration>(Obj); +} + /*}}}*/ + +// Method Wrappers /*{{{*/ +static char *doc_Find = "Find(Name[,default]) -> String/None"; +static PyObject *CnfFind(PyObject *Self,PyObject *Args) +{ + char *Name = 0; + char *Default = 0; + if (PyArg_ParseTuple(Args,"s|s",&Name,&Default) == 0) + return 0; + return CppPyString(GetSelf(Self).Find(Name,Default)); +} + +static char *doc_FindFile = "FindFile(Name[,default]) -> String/None"; +static PyObject *CnfFindFile(PyObject *Self,PyObject *Args) +{ + char *Name = 0; + char *Default = 0; + if (PyArg_ParseTuple(Args,"s|s",&Name,&Default) == 0) + return 0; + return CppPyString(GetSelf(Self).FindFile(Name,Default)); +} + +static char *doc_FindDir = "FindDir(Name[,default]) -> String/None"; +static PyObject *CnfFindDir(PyObject *Self,PyObject *Args) +{ + char *Name = 0; + char *Default = 0; + if (PyArg_ParseTuple(Args,"s|s",&Name,&Default) == 0) + return 0; + return CppPyString(GetSelf(Self).FindDir(Name,Default)); +} + +static char *doc_FindI = "FindI(Name[,default]) -> Integer"; +static PyObject *CnfFindI(PyObject *Self,PyObject *Args) +{ + char *Name = 0; + int Default = 0; + if (PyArg_ParseTuple(Args,"s|i",&Name,&Default) == 0) + return 0; + return Py_BuildValue("i",GetSelf(Self).FindI(Name,Default)); +} + +static char *doc_FindB = "FindB(Name[,default]) -> Integer"; +static PyObject *CnfFindB(PyObject *Self,PyObject *Args) +{ + char *Name = 0; + int Default = 0; + if (PyArg_ParseTuple(Args,"s|i",&Name,&Default) == 0) + return 0; + return Py_BuildValue("i",(int)GetSelf(Self).FindB(Name,(Default == 0?false:true))); +} + +static char *doc_Set = "Set(Name,Value) -> None"; +static PyObject *CnfSet(PyObject *Self,PyObject *Args) +{ + char *Name = 0; + char *Value = 0; + if (PyArg_ParseTuple(Args,"ss",&Name,&Value) == 0) + return 0; + + GetSelf(Self).Set(Name,Value); + Py_INCREF(Py_None); + return Py_None; +} + +static char *doc_Exists = "Exists(Name) -> Integer"; +static PyObject *CnfExists(PyObject *Self,PyObject *Args) +{ + char *Name = 0; + if (PyArg_ParseTuple(Args,"s",&Name) == 0) + return 0; + return Py_BuildValue("i",(int)GetSelf(Self).Exists(Name)); +} + +static char *doc_Clear = "Clear(Name) -> None"; +static PyObject *CnfClear(PyObject *Self,PyObject *Args) +{ + char *Name = 0; + if (PyArg_ParseTuple(Args,"s",&Name) == 0) + return 0; + + GetSelf(Self).Clear(Name); + + Py_INCREF(Py_None); + return Py_None; +} + +// The amazing narrowing search ability! +static char *doc_SubTree = "SubTree(Name) -> Configuration"; +static PyObject *CnfSubTree(PyObject *Self,PyObject *Args) +{ + char *Name; + if (PyArg_ParseTuple(Args,"s",&Name) == 0) + return 0; + const Configuration::Item *Itm = GetSelf(Self).Tree(Name); + if (Itm == 0) + { + PyErr_SetString(PyExc_KeyError,Name); + return 0; + } + + // Create a new sub configuration. + SubConfiguration *New = PyObject_NEW(SubConfiguration,&ConfigurationSubType); + new (&New->Object) Configuration(Itm); + New->Owner = Self; + Py_INCREF(Self); + return New; +} + +// Return a list of items at a specific level +static char *doc_List = "List([root]) -> List"; +static PyObject *CnfList(PyObject *Self,PyObject *Args) +{ + char *RootName = 0; + if (PyArg_ParseTuple(Args,"|s",&RootName) == 0) + return 0; + + // Convert the whole configuration space into a list + PyObject *List = PyList_New(0); + const Configuration::Item *Top = GetSelf(Self).Tree(RootName); + const Configuration::Item *Root = GetSelf(Self).Tree(0)->Parent; + if (Top != 0 && RootName != 0) + Top = Top->Child; + for (; Top != 0; Top = Top->Next) + { + PyObject *Obj; + PyList_Append(List,Obj = CppPyString(Top->FullTag(Root))); + Py_DECREF(Obj); + } + + return List; +} + +/* Return a list of values of items at a specific level.. This is used to + get out value lists */ +static char *doc_ValueList = "ValueList([root]) -> List"; +static PyObject *CnfValueList(PyObject *Self,PyObject *Args) +{ + char *RootName = 0; + if (PyArg_ParseTuple(Args,"|s",&RootName) == 0) + return 0; + + // Convert the whole configuration space into a list + PyObject *List = PyList_New(0); + const Configuration::Item *Top = GetSelf(Self).Tree(RootName); + if (Top != 0 && RootName != 0) + Top = Top->Child; + for (; Top != 0; Top = Top->Next) + { + PyObject *Obj; + PyList_Append(List,Obj = CppPyString(Top->Value)); + Py_DECREF(Obj); + } + + return List; +} + +static char *doc_MyTag = "MyTag() -> String"; +static PyObject *CnfMyTag(PyObject *Self,PyObject *Args) +{ + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + const Configuration::Item *Top = GetSelf(Self).Tree(0); + if (Top == 0) + return Py_BuildValue("s",""); + return CppPyString(Top->Parent->Tag); +} + +// Look like a mapping +static char *doc_Keys = "keys([root]) -> List"; +static PyObject *CnfKeys(PyObject *Self,PyObject *Args) +{ + char *RootName = 0; + if (PyArg_ParseTuple(Args,"|s",&RootName) == 0) + return 0; + + // Convert the whole configuration space into a list + PyObject *List = PyList_New(0); + const Configuration::Item *Top = GetSelf(Self).Tree(RootName); + const Configuration::Item *Stop = Top; + if (RootName == 0) + Stop = 0; + const Configuration::Item *Root = GetSelf(Self).Tree(0)->Parent; + for (; Top != 0;) + { + PyObject *Obj; + PyList_Append(List,Obj = CppPyString(Top->FullTag(Root))); + Py_DECREF(Obj); + + if (Top->Child != 0) + { + Top = Top->Child; + continue; + } + + while (Top != 0 && Top->Next == 0 && Top != Root && + Top->Parent != Stop) + Top = Top->Parent; + if (Top != 0) + Top = Top->Next; + } + + return List; +} + +// Map access, operator [] +static PyObject *CnfMap(PyObject *Self,PyObject *Arg) +{ + if (PyString_Check(Arg) == 0) + { + PyErr_SetNone(PyExc_TypeError); + return 0; + } + + if (GetSelf(Self).Exists(PyString_AsString(Arg)) == false) + { + PyErr_SetString(PyExc_KeyError,PyString_AsString(Arg)); + return 0; + } + + return CppPyString(GetSelf(Self).Find(PyString_AsString(Arg))); +} + +// Assignment with operator [] +static int CnfMapSet(PyObject *Self,PyObject *Arg,PyObject *Val) +{ + if (PyString_Check(Arg) == 0 || PyString_Check(Val) == 0) + { + PyErr_SetNone(PyExc_TypeError); + return -1; + } + + GetSelf(Self).Set(PyString_AsString(Arg),PyString_AsString(Val)); + return 0; +} + /*}}}*/ +// Config file loaders /*{{{*/ +char *doc_LoadConfig = "LoadConfig(Configuration,FileName) -> None"; +PyObject *LoadConfig(PyObject *Self,PyObject *Args) +{ + char *Name = 0; + if (PyArg_ParseTuple(Args,"Os",&Self,&Name) == 0) + return 0; + if (Configuration_Check(Self)== 0) + { + PyErr_SetString(PyExc_TypeError,"argument 1: expected Configuration."); + return 0; + } + + if (ReadConfigFile(GetSelf(Self),Name,false) == false) + return HandleErrors(); + + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} +char *doc_LoadConfigISC = "LoadConfigISC(Configuration,FileName) -> None"; +PyObject *LoadConfigISC(PyObject *Self,PyObject *Args) +{ + char *Name = 0; + if (PyArg_ParseTuple(Args,"Os",&Self,&Name) == 0) + return 0; + if (Configuration_Check(Self)== 0) + { + PyErr_SetString(PyExc_TypeError,"argument 1: expected Configuration."); + return 0; + } + + if (ReadConfigFile(GetSelf(Self),Name,true) == false) + return HandleErrors(); + + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + /*}}}*/ + +// ParseCommandLine - Wrapper for the command line interface /*{{{*/ +// --------------------------------------------------------------------- +char *doc_ParseCommandLine = +"ParseCommandLine(Configuration,ListOfOptions,List-argv) -> List\n" +"\n" +"This function is like getopt except it manipulates a configuration space.\n" +"output is a list of non-option arguments (filenames, etc).\n" +"ListOfOptions is a list of tuples of the form:\n" +" ('c',\"long-opt or None\",\"Configuration::Variable\",\"optional type\")\n" +"Where type may be one of HasArg, IntLevel, Boolean, InvBoolean,\n" +"ConfigFile, or ArbItem. The default is Boolean."; +PyObject *ParseCommandLine(PyObject *Self,PyObject *Args) +{ + PyObject *POList; + PyObject *Pargv; + if (PyArg_ParseTuple(Args,"OO!O!",&Self, + &PyList_Type,&POList,&PyList_Type,&Pargv) == 0) + return 0; + if (Configuration_Check(Self)== 0) + { + PyErr_SetString(PyExc_TypeError,"argument 1: expected Configuration."); + return 0; + } + + // Convert the option list + int Length = PySequence_Length(POList); + CommandLine::Args *OList = new CommandLine::Args[Length+1]; + OList[Length].ShortOpt = 0; + OList[Length].LongOpt = 0; + + for (int I = 0; I != Length; I++) + { + char *Type = 0; + if (PyArg_ParseTuple(PySequence_GetItem(POList,I),"czs|s", + &OList[I].ShortOpt,&OList[I].LongOpt, + &OList[I].ConfName,&Type) == 0) + { + delete [] OList; + return 0; + } + OList[I].Flags = 0; + + // Convert the type over to flags.. + if (Type != 0) + { + if (strcasecmp(Type,"HasArg") == 0) + OList[I].Flags = CommandLine::HasArg; + else if (strcasecmp(Type,"IntLevel") == 0) + OList[I].Flags = CommandLine::IntLevel; + else if (strcasecmp(Type,"Boolean") == 0) + OList[I].Flags = CommandLine::Boolean; + else if (strcasecmp(Type,"InvBoolean") == 0) + OList[I].Flags = CommandLine::InvBoolean; + else if (strcasecmp(Type,"ConfigFile") == 0) + OList[I].Flags = CommandLine::ConfigFile; + else if (strcasecmp(Type,"ArbItem") == 0) + OList[I].Flags = CommandLine::ArbItem; + } + } + + // Convert the argument list into a char ** + const char **argv = ListToCharChar(Pargv); + if (argv == 0) + { + delete [] OList; + return 0; + } + + // Do the command line processing + PyObject *List = 0; + { + CommandLine CmdL(OList,&GetSelf(Self)); + if (CmdL.Parse(PySequence_Length(Pargv),argv) == false) + { + delete [] argv; + delete [] OList; + return HandleErrors(); + } + + // Convert the file listing into a python sequence + for (Length = 0; CmdL.FileList[Length] != 0; Length++); + List = PyList_New(Length); + for (int I = 0; CmdL.FileList[I] != 0; I++) + { + PyList_SetItem(List,I,PyString_FromString(CmdL.FileList[I])); + } + } + + delete [] argv; + delete [] OList; + return HandleErrors(List); +} + /*}}}*/ + +// Method table for the Configuration object +static PyMethodDef CnfMethods[] = +{ + // Query + {"Find",CnfFind,METH_VARARGS,doc_Find}, + {"FindFile",CnfFindFile,METH_VARARGS,doc_FindFile}, + {"FindDir",CnfFindDir,METH_VARARGS,doc_FindDir}, + {"FindI",CnfFindI,METH_VARARGS,doc_FindI}, + {"FindB",CnfFindB,METH_VARARGS,doc_FindB}, + + // Others + {"Set",CnfSet,METH_VARARGS,doc_Set}, + {"Exists",CnfExists,METH_VARARGS,doc_Exists}, + {"SubTree",CnfSubTree,METH_VARARGS,doc_SubTree}, + {"List",CnfList,METH_VARARGS,doc_List}, + {"ValueList",CnfValueList,METH_VARARGS,doc_ValueList}, + {"MyTag",CnfMyTag,METH_VARARGS,doc_MyTag}, + {"Clear",CnfClear,METH_VARARGS,doc_Clear}, + + // Python Special + {"keys",CnfKeys,METH_VARARGS,doc_Keys}, + {"has_key",CnfExists,METH_VARARGS,doc_Exists}, + {"get",CnfFind,METH_VARARGS,doc_Find}, + {} +}; + +// Type for a Normal Configuration object +static PyMappingMethods ConfigurationMap = {0,CnfMap,CnfMapSet}; +PyTypeObject ConfigurationType = +{ + PyObject_HEAD_INIT(&PyType_Type) + 0, // ob_size + "Configuration", // tp_name + sizeof(CppPyObject<Configuration>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<Configuration>, // tp_dealloc + 0, // tp_print + CnfGetAttr, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + &ConfigurationMap, // tp_as_mapping + 0, // tp_hash +}; + +PyTypeObject ConfigurationPtrType = +{ + PyObject_HEAD_INIT(&PyType_Type) + 0, // ob_size + "ConfigurationPtr", // tp_name + sizeof(CppPyObject<Configuration *>), // tp_basicsize + 0, // tp_itemsize + // Methods + (destructor)PyMem_Free, // tp_dealloc + 0, // tp_print + CnfGetAttr, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + &ConfigurationMap, // tp_as_mapping + 0, // tp_hash +}; + +PyTypeObject ConfigurationSubType = +{ + PyObject_HEAD_INIT(&PyType_Type) + 0, // ob_size + "ConfigurationSub", // tp_name + sizeof(SubConfiguration), // tp_basicsize + 0, // tp_itemsize + // Methods + CnfSubFree, // tp_dealloc + 0, // tp_print + CnfGetAttr, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + &ConfigurationMap, // tp_as_mapping + 0, // tp_hash +}; + diff --git a/python/generic.cc b/python/generic.cc new file mode 100644 index 00000000..aab03d7b --- /dev/null +++ b/python/generic.cc @@ -0,0 +1,86 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: generic.cc,v 1.1 2001/02/20 06:32:01 jgg Exp $ +/* ###################################################################### + + generic - Some handy functions to make integration a tad simpler + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include "generic.h" + +#include <apt-pkg/error.h> + /*}}}*/ + +// HandleErrors - This moves errors from _error to Python Exceptions /*{{{*/ +// --------------------------------------------------------------------- +/* We throw away all warnings and only propogate the first error. */ +PyObject *HandleErrors(PyObject *Res) +{ + if (_error->PendingError() == false) + { + // Throw away warnings + _error->Discard(); + return Res; + } + + if (Res != 0) + Py_DECREF(Res); + + string Err = "Internal Error Error"; + while (_error->empty() == false) + { + bool Type = _error->PopMessage(Err); + if (Type == false) + continue; + } + + _error->Discard(); + PyErr_SetString(PyExc_SystemError,Err.c_str()); + return 0; +} + /*}}}*/ +// ListToCharChar - Convert a list to an array of char char /*{{{*/ +// --------------------------------------------------------------------- +/* Caller must free the result. 0 on error. */ +const char **ListToCharChar(PyObject *List,bool NullTerm) +{ + // Convert the argument list into a char ** + int Length = PySequence_Length(List); + const char **Res = new const char *[Length + (NullTerm == true?1:0)]; + for (int I = 0; I != Length; I++) + { + PyObject *Itm = PySequence_GetItem(List,I); + if (PyString_Check(Itm) == 0) + { + PyErr_SetNone(PyExc_TypeError); + delete [] Res; + return 0; + } + Res[I] = PyString_AsString(Itm); + } + if (NullTerm == true) + Res[Length] = 0; + return Res; +} + /*}}}*/ +// CharCharToList - Inverse of the above /*{{{*/ +// --------------------------------------------------------------------- +/* Zero size indicates the list is Null terminated. */ +PyObject *CharCharToList(const char **List,unsigned long Size) +{ + if (Size == 0) + { + for (const char **I = List; *I != 0; I++) + Size++; + } + + // Convert the whole configuration space into a list + PyObject *PList = PyList_New(Size); + for (unsigned long I = 0; I != Size; I++, List++) + PyList_SetItem(PList,I,PyString_FromString(*List)); + + return PList; +} + /*}}}*/ diff --git a/python/generic.h b/python/generic.h new file mode 100644 index 00000000..3cbe374b --- /dev/null +++ b/python/generic.h @@ -0,0 +1,132 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: generic.h,v 1.1 2001/02/20 06:32:01 jgg Exp $ +/* ###################################################################### + + generic - Some handy functions to make integration a tad simpler + + Python needs this little _HEAD tacked onto the front of the object.. + This complicates the integration with C++. We use some templates to + make that quite transparent to us. It would have been nice if Python + internally used a page from the C++ ref counting book to hide its little + header from the world, but it doesn't. + + The CppPyObject has the target object and the Python header, this is + needed to ensure proper alignment. + GetCpp returns the C++ object from a PyObject. + CppPyObject_NEW creates the Python object and then uses placement new + to init the C++ class.. This is good for simple situations and as an + example on how to do it in other more specific cases. + CppPyObject_Dealloc should be used in the Type as the destructor + function. + HandleErrors converts errors from the internal _error stack into Python + exceptions and makes sure the _error stack is empty. + + ##################################################################### */ + /*}}}*/ +#ifndef GENERIC_H +#define GENERIC_H + +#include <python/Python.h> +#include <string> + +template <class T> struct CppPyObject : public PyObject +{ + T Object; +}; + +template <class T> struct CppOwnedPyObject : public CppPyObject<T> +{ + PyObject *Owner; +}; + +template <class T> +inline T &GetCpp(PyObject *Obj) +{ + return ((CppPyObject<T> *)Obj)->Object; +} + +template <class T> +inline PyObject *GetOwner(PyObject *Obj) +{ + return ((CppOwnedPyObject<T> *)Obj)->Owner; +} + +// Generic 'new' functions +template <class T> +inline CppPyObject<T> *CppPyObject_NEW(PyTypeObject *Type) +{ + CppPyObject<T> *New = PyObject_NEW(CppPyObject<T>,Type); + new (&New->Object) T; + return New; +} + +template <class T,class A> +inline CppPyObject<T> *CppPyObject_NEW(PyTypeObject *Type,A const &Arg) +{ + CppPyObject<T> *New = PyObject_NEW(CppPyObject<T>,Type); + new (&New->Object) T(Arg); + return New; +} + +template <class T> +inline CppOwnedPyObject<T> *CppOwnedPyObject_NEW(PyObject *Owner, + PyTypeObject *Type) +{ + CppOwnedPyObject<T> *New = PyObject_NEW(CppOwnedPyObject<T>,Type); + new (&New->Object) T; + New->Owner = Owner; + Py_INCREF(Owner); + return New; +} + +template <class T,class A> +inline CppOwnedPyObject<T> *CppOwnedPyObject_NEW(PyObject *Owner, + PyTypeObject *Type,A const &Arg) +{ + CppOwnedPyObject<T> *New = PyObject_NEW(CppOwnedPyObject<T>,Type); + new (&New->Object) T(Arg); + New->Owner = Owner; + if (Owner != 0) + Py_INCREF(Owner); + return New; +} + +// Generic Dealloc type functions +template <class T> +void CppDealloc(PyObject *Obj) +{ + GetCpp<T>(Obj).~T(); + PyMem_DEL(Obj); +} + +template <class T> +void CppOwnedDealloc(PyObject *iObj) +{ + CppOwnedPyObject<T> *Obj = (CppOwnedPyObject<T> *)iObj; + Obj->Object.~T(); + if (Obj->Owner != 0) + Py_DECREF(Obj->Owner); + PyMem_DEL(Obj); +} + +inline PyObject *CppPyString(string Str) +{ + return PyString_FromStringAndSize(Str.begin(),Str.length()); +} + +inline PyObject *Safe_FromString(const char *Str) +{ + if (Str == 0) + return PyString_FromString(""); + return PyString_FromString(Str); +} + +// Convert _error into Python exceptions +PyObject *HandleErrors(PyObject *Res = 0); + +// Convert a list of strings to a char ** +const char **ListToCharChar(PyObject *List,bool NullTerm = false); +PyObject *CharCharToList(const char **List,unsigned long Size = 0); + +#endif diff --git a/python/makefile b/python/makefile new file mode 100644 index 00000000..f8639c93 --- /dev/null +++ b/python/makefile @@ -0,0 +1,21 @@ +# -*- make -*- +BASE=.. +SUBDIR=python + +# Bring in the default rules +include ../buildlib/defaults.mak + +# The apt_pkg module +MODULE=apt_pkg +SLIBS = -lapt-pkg +LIB_MAKES = apt-pkg/makefile +SOURCE = apt_pkgmodule.cc configuration.cc generic.cc tag.cc string.cc \ + cache.cc pkgrecords.cc +include $(PYTHON_H) + +# The apt_int module.. +MODULE=apt_inst +SLIBS = -lapt-inst -lapt-pkg +LIB_MAKES = apt-inst/makefile +SOURCE = apt_instmodule.cc generic.cc +include $(PYTHON_H) diff --git a/python/pkgrecords.cc b/python/pkgrecords.cc new file mode 100644 index 00000000..3128365a --- /dev/null +++ b/python/pkgrecords.cc @@ -0,0 +1,119 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: pkgrecords.cc,v 1.1 2001/02/20 06:32:01 jgg Exp $ +/* ###################################################################### + + Package Records - Wrapper for the package records functions + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include "generic.h" +#include "apt_pkgmodule.h" + +#include <apt-pkg/pkgrecords.h> + +#include <python/Python.h> + /*}}}*/ + +struct PkgRecordsStruct +{ + pkgRecords Records; + pkgRecords::Parser *Last; + + PkgRecordsStruct(pkgCache *Cache) : Records(*Cache), Last(0) {}; + PkgRecordsStruct() : Records(*(pkgCache *)0) {abort();}; // G++ Bug.. +}; + +// PkgRecords Class /*{{{*/ +// --------------------------------------------------------------------- +static PyMethodDef PkgRecordsMethods[]; + +static PyObject *PkgRecordsAttr(PyObject *Self,char *Name) +{ + PkgRecordsStruct &Struct = GetCpp<PkgRecordsStruct>(Self); + + if (Struct.Last != 0) + { + if (strcmp("FileName",Name) == 0) + return CppPyString(Struct.Last->FileName()); + else if (strcmp("MD5Hash",Name) == 0) + return CppPyString(Struct.Last->MD5Hash()); + else if (strcmp("SourcePkg",Name) == 0) + return CppPyString(Struct.Last->SourcePkg()); + else if (strcmp("Maintainer",Name) == 0) + return CppPyString(Struct.Last->Maintainer()); + else if (strcmp("ShortDesc",Name) == 0) + return CppPyString(Struct.Last->ShortDesc()); + else if (strcmp("LongDesc",Name) == 0) + return CppPyString(Struct.Last->LongDesc()); + else if (strcmp("Name",Name) == 0) + return CppPyString(Struct.Last->Name()); + } + + return Py_FindMethod(PkgRecordsMethods,Self,Name); +} + +static PyObject *PkgRecordsLookup(PyObject *Self,PyObject *Args) +{ + PkgRecordsStruct &Struct = GetCpp<PkgRecordsStruct>(Self); + + PyObject *PkgFObj; + long int Index; + if (PyArg_ParseTuple(Args,"(O!l)",&PackageFileType,&PkgFObj,&Index) == 0) + return 0; + + // Get the index and check to make sure it is reasonable + pkgCache::PkgFileIterator &PkgF = GetCpp<pkgCache::PkgFileIterator>(PkgFObj); + pkgCache *Cache = PkgF.Cache(); + if (Cache->DataEnd() <= Cache->VerFileP + Index + 1 || + Cache->VerFileP[Index].File != PkgF.Index()) + { + PyErr_SetNone(PyExc_IndexError); + return 0; + } + + // Do the lookup + Struct.Last = &Struct.Records.Lookup(pkgCache::VerFileIterator(*Cache,Cache->VerFileP+Index)); + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + +static PyMethodDef PkgRecordsMethods[] = +{ + {"Lookup",PkgRecordsLookup,METH_VARARGS,"Changes to a new package"}, + {} +}; + +PyTypeObject PkgRecordsType = +{ + PyObject_HEAD_INIT(&PyType_Type) + 0, // ob_size + "pkgRecords", // tp_name + sizeof(CppOwnedPyObject<PkgRecordsStruct>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppOwnedDealloc<PkgRecordsStruct>, // tp_dealloc + 0, // tp_print + PkgRecordsAttr, // 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 +}; + + /*}}}*/ + +PyObject *GetPkgRecords(PyObject *Self,PyObject *Args) +{ + PyObject *Owner; + if (PyArg_ParseTuple(Args,"O!",&PkgCacheType,&Owner) == 0) + return 0; + + return HandleErrors(CppOwnedPyObject_NEW<PkgRecordsStruct>(Owner,&PkgRecordsType, + GetCpp<pkgCache *>(Owner))); +} + diff --git a/python/string.cc b/python/string.cc new file mode 100644 index 00000000..7564899b --- /dev/null +++ b/python/string.cc @@ -0,0 +1,96 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: string.cc,v 1.1 2001/02/20 06:32:01 jgg Exp $ +/* ###################################################################### + + string - Mappings for the string functions that are worthwile for + Python users + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include "apt_pkgmodule.h" +#include "generic.h" + +#include <apt-pkg/strutl.h> + +#include <python/Python.h> + /*}}}*/ + +// Templated function /*{{{*/ +/* Macro for the generic string in string out function */ +#define MkStr(Python,CFunc) \ +PyObject *Python(PyObject *Self,PyObject *Args) \ +{ \ + char *Str = 0; \ + if (PyArg_ParseTuple(Args,"s",&Str) == 0) \ + return 0; \ + return CppPyString(CFunc(Str)); \ +} + +#define MkInt(Python,CFunc) \ +PyObject *Python(PyObject *Self,PyObject *Args) \ +{ \ + int Val = 0; \ + if (PyArg_ParseTuple(Args,"i",&Val) == 0) \ + return 0; \ + return CppPyString(CFunc(Val)); \ +} + +MkStr(StrDeQuote,DeQuoteString); +MkStr(StrBase64Encode,Base64Encode); +MkStr(StrURItoFileName,URItoFileName); + +//MkFloat(StrSizeToStr,SizeToStr); +MkInt(StrTimeToStr,TimeToStr); +MkInt(StrTimeRFC1123,TimeRFC1123); + /*}}}*/ + +// Other String functions /*{{{*/ +PyObject *StrSizeToStr(PyObject *Self,PyObject *Args) +{ + PyObject *Obj; + if (PyArg_ParseTuple(Args,"O",&Obj) == 0) + return 0; + if (PyInt_Check(Obj)) + return CppPyString(SizeToStr(PyInt_AS_LONG(Obj))); + if (PyFloat_Check(Obj)) + return CppPyString(SizeToStr(PyFloat_AS_DOUBLE(Obj))); + + PyErr_SetString(PyExc_TypeError,"Only understand integers and floats"); + return 0; +} + +PyObject *StrQuoteString(PyObject *Self,PyObject *Args) +{ + char *Str = 0; + char *Bad = 0; + if (PyArg_ParseTuple(Args,"ss",&Str,&Bad) == 0) + return 0; + return CppPyString(QuoteString(Str,Bad)); +} + +PyObject *StrStringToBool(PyObject *Self,PyObject *Args) +{ + char *Str = 0; + if (PyArg_ParseTuple(Args,"s",&Str) == 0) + return 0; + return Py_BuildValue("i",StringToBool(Str)); +} + +PyObject *StrStrToTime(PyObject *Self,PyObject *Args) +{ + char *Str = 0; + if (PyArg_ParseTuple(Args,"s",&Str) == 0) + return 0; + + time_t Result; + if (StrToTime(Str,Result) == false) + { + Py_INCREF(Py_None); + return Py_None; + } + + return Py_BuildValue("i",Result); +} + /*}}}*/ diff --git a/python/tag.cc b/python/tag.cc new file mode 100644 index 00000000..da151832 --- /dev/null +++ b/python/tag.cc @@ -0,0 +1,445 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: tag.cc,v 1.1 2001/02/20 06:32:01 jgg 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 /*{{{*/ +#define _GNU_SOURCE +#include "generic.h" +#include "apt_pkgmodule.h" + +#include <apt-pkg/tagfile.h> + +#include <stdio.h> +#include <python/Python.h> + /*}}}*/ +static PyMethodDef TagSecMethods[]; +static PyMethodDef TagFileMethods[]; + +/* We need to keep a private copy of the data.. */ +struct TagSecData : public CppPyObject<pkgTagSection> +{ + char *Data; +}; + +struct TagFileData : public PyObject +{ + pkgTagFile Object; + PyObject *File; + TagSecData *Section; + FileFd Fd; +}; + +// TagSecGetAttr - Get an attribute - variable/method /*{{{*/ +// --------------------------------------------------------------------- +/* */ +static PyObject *TagSecGetAttr(PyObject *Self,char *Name) +{ + return Py_FindMethod(TagSecMethods,Self,Name); +} + /*}}}*/ +// TagFileGetAttr - Get an attribute - variable/method /*{{{*/ +// --------------------------------------------------------------------- +/* */ +static PyObject *TagFileGetAttr(PyObject *Self,char *Name) +{ + if (strcmp("Section",Name) == 0) + { + PyObject *Obj = ((TagFileData *)Self)->Section; + Py_INCREF(Obj); + return Obj; + } + + return Py_FindMethod(TagFileMethods,Self,Name); +} + /*}}}*/ +// 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) +{ + TagFileData *Self = (TagFileData *)Obj; + Py_DECREF((PyObject *)Self->Section); + Self->Object.~pkgTagFile(); + Self->Fd.~FileFd(); + Py_DECREF(Self->File); + PyMem_DEL(Obj); +} + /*}}}*/ + +// Tag Section Wrappers /*{{{*/ +static char *doc_Find = "Find(Name) -> String/None"; +static PyObject *TagSecFind(PyObject *Self,PyObject *Args) +{ + char *Name = 0; + char *Default = 0; + if (PyArg_ParseTuple(Args,"s|s",&Name,&Default) == 0) + return 0; + + const char *Start; + const char *Stop; + if (GetCpp<pkgTagSection>(Self).Find(Name,Start,Stop) == false) + { + if (Default == 0) + { + Py_INCREF(Py_None); + return Py_None; + } + return PyString_FromString(Default); + } + return PyString_FromStringAndSize(Start,Stop-Start); +} + +static char *doc_FindFlag = "FindFlag(Name) -> integer/none"; +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 Py_BuildValue("i",Flag); +} + +// Map access, operator [] +static PyObject *TagSecMap(PyObject *Self,PyObject *Arg) +{ + if (PyString_Check(Arg) == 0) + { + PyErr_SetNone(PyExc_TypeError); + return 0; + } + + const char *Start; + const char *Stop; + if (GetCpp<pkgTagSection>(Self).Find(PyString_AsString(Arg),Start,Stop) == false) + { + PyErr_SetString(PyExc_KeyError,PyString_AsString(Arg)); + return 0; + } + + return PyString_FromStringAndSize(Start,Stop-Start); +} + +// len() operation +static int TagSecLength(PyObject *Self) +{ + pkgTagSection &Sec = GetCpp<pkgTagSection>(Self); + return Sec.Count(); +} + +// Look like a mapping +static char *doc_Keys = "keys() -> List"; +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; +} + +static char *doc_Exists = "Exists(Name) -> integer"; +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; + if (GetCpp<pkgTagSection>(Self).Find(Name,Start,Stop) == false) + return Py_BuildValue("i",0); + return Py_BuildValue("i",1); +} + +static char *doc_Bytes = "Bytes() -> integer"; +static PyObject *TagSecBytes(PyObject *Self,PyObject *Args) +{ + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + return Py_BuildValue("i",GetCpp<pkgTagSection>(Self).size()); +} + +static PyObject *TagSecStr(PyObject *Self) +{ + const char *Start; + const char *Stop; + GetCpp<pkgTagSection>(Self).GetSection(Start,Stop); + return PyString_FromStringAndSize(Start,Stop-Start); +} + /*}}}*/ +// TagFile Wrappers /*{{{*/ +static char *doc_Step = "Step() -> Integer\n0 means EOF."; +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(Py_BuildValue("i",0)); + + return HandleErrors(Py_BuildValue("i",1)); +} + +static char *doc_Offset = "Offset() -> Integer"; +static PyObject *TagFileOffset(PyObject *Self,PyObject *Args) +{ + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + return Py_BuildValue("i",((TagFileData *)Self)->Object.Offset()); +} + +static char *doc_Jump = "Jump(Offset) -> Integer"; +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(Py_BuildValue("i",0)); + + return HandleErrors(Py_BuildValue("i",1)); +} + /*}}}*/ +// ParseSection - Parse a single section from a tag file /*{{{*/ +// --------------------------------------------------------------------- +char *doc_ParseSection ="ParseSection(Text) -> SectionObject"; +PyObject *ParseSection(PyObject *self,PyObject *Args) +{ + char *Data; + if (PyArg_ParseTuple(Args,"s",&Data) == 0) + return 0; + + // Create the object.. + TagSecData *New = PyObject_NEW(TagSecData,&TagSecType); + new (&New->Object) pkgTagSection(); + New->Data = new char[strlen(Data)+2]; + snprintf(New->Data,strlen(Data)+2,"%s\n",Data); + + 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. */ +char *doc_ParseTagFile = "ParseTagFile(File) -> TagFile"; +PyObject *ParseTagFile(PyObject *self,PyObject *Args) +{ + PyObject *File; + if (PyArg_ParseTuple(Args,"O!",&PyFile_Type,&File) == 0) + return 0; + + TagFileData *New = PyObject_NEW(TagFileData,&TagFileType); + new (&New->Fd) FileFd(fileno(PyFile_AsFile(File)),false); + New->File = File; + Py_INCREF(New->File); + new (&New->Object) pkgTagFile(&New->Fd); + + // Create the section + New->Section = PyObject_NEW(TagSecData,&TagSecType); + new (&New->Section->Object) pkgTagSection(); + New->Section->Data = 0; + + return HandleErrors(New); +} + /*}}}*/ +// RewriteSection - Rewrite a section.. /*{{{*/ +// --------------------------------------------------------------------- +/* An interesting future extension would be to add a user settable + order list */ +char *doc_RewriteSection = +"RewriteSection(Section,Order,RewriteList) -> String\n" +"\n" +"The section rewriter allows a section to be taken in, have fields added,\n" +"removed or changed and then put back out. During this process the fields\n" +"within the section are sorted to corrispond to a proper order. Order is a\n" +"list of field names with their proper capitialization.\n" +"apt_pkg.RewritePackageOrder and apt_pkg.RewriteSourceOrder are two predefined\n" +"orders.\n" +"RewriteList is a list of tuples. Each tuple is of the form:\n" +" (Tag,NewValue[,RenamedTo])\n" +"Tag specifies the tag in the source section. NewValue is the new value of\n" +"that tag and the optional RenamedTo field can cause the tag to be changed.\n" +"If NewValue is None then the tag is removed\n" +"Ex. ('Source','apt','Package') is used for .dsc files."; +PyObject *RewriteSection(PyObject *self,PyObject *Args) +{ + PyObject *Section; + PyObject *Order; + PyObject *Rewrite; + if (PyArg_ParseTuple(Args,"O!O!O!",&TagSecType,&Section, + &PyList_Type,&Order,&PyList_Type,&Rewrite) == 0) + return 0; + + // Convert the order list + const char **OrderList = ListToCharChar(Order,true); + + // Convert the Rewrite list. + TFRewriteData *List = new TFRewriteData[PySequence_Length(Rewrite)+1]; + memset(List,0,sizeof(*List)*(PySequence_Length(Rewrite)+1)); + for (int I = 0; I != PySequence_Length(Rewrite); I++) + { + List[I].NewTag = 0; + if (PyArg_ParseTuple(PySequence_GetItem(Rewrite,I),"sz|s", + &List[I].Tag,&List[I].Rewrite,&List[I].NewTag) == 0) + { + delete [] OrderList; + delete [] List; + return 0; + } + } + + /* This is a glibc extension.. If not running on glibc I'd just take + this whole function out, it is probably infrequently used */ + char *bp = 0; + size_t size; + FILE *F = open_memstream (&bp, &size); + + // Do the rewrite + bool Res = TFRewrite(F,GetCpp<pkgTagSection>(Section),OrderList,List); + delete [] OrderList; + delete [] List; + fclose(F); + + if (Res == false) + { + free(bp); + return HandleErrors(); + } + + // Return the string + PyObject *ResObj = PyString_FromStringAndSize(bp,size); + free(bp); + return HandleErrors(ResObj); +} + /*}}}*/ + +// Method table for the Tag Section object +static PyMethodDef TagSecMethods[] = +{ + // Query + {"Find",TagSecFind,METH_VARARGS,doc_Find}, + {"FindFlag",TagSecFindFlag,METH_VARARGS,doc_FindFlag}, + {"Bytes",TagSecBytes,METH_VARARGS,doc_Bytes}, + + // Python Special + {"keys",TagSecKeys,METH_VARARGS,doc_Keys}, + {"has_key",TagSecExists,METH_VARARGS,doc_Exists}, + {"get",TagSecFind,METH_VARARGS,doc_Find}, + {} +}; + +// Type for a Tag Section +PyMappingMethods TagSecMapMeth = {TagSecLength,TagSecMap,0}; +PyTypeObject TagSecType = +{ + PyObject_HEAD_INIT(&PyType_Type) + 0, // ob_size + "TagSection", // tp_name + sizeof(TagSecData), // tp_basicsize + 0, // tp_itemsize + // Methods + TagSecFree, // tp_dealloc + 0, // tp_print + TagSecGetAttr, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + &TagSecMapMeth, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + TagSecStr, // tp_str +}; + +// 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}, + + {} +}; + +// Type for a Tag File +PyTypeObject TagFileType = +{ + PyObject_HEAD_INIT(&PyType_Type) + 0, // ob_size + "TagFile", // tp_name + sizeof(TagFileData), // tp_basicsize + 0, // tp_itemsize + // Methods + TagFileFree, // tp_dealloc + 0, // tp_print + TagFileGetAttr, // 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 +}; |
