Imported the old britney and its libraries.

bzr-import-20160707
Fabio Tranchitella 19 years ago
parent 70be82be3f
commit c8468f9516

@ -0,0 +1,32 @@
CC = gcc
CXX = g++
CFLAGS = -Wall -W -O2 -DNDEBUG -DMDEBUG0 -g -p
all : checklib aptvercmp freelist britneymodule.so # libajdpkg.a
clean :
rm -f *.so *.o *~ Makefile.dep gmon.out
rm -f freelist aptvercmp checklib libajdpkg.a
checklib : checklib.o dpkg.o dpkg-lib.o memory3.o freelist.o assert.o
$(CC) $(CFLAGS) -o checklib -lapt-pkg $^ # -lccmalloc -ldl
aptvercmp : dpkg-lib.cpp
$(CXX) $(CFLAGS) -DTESTBIN -o aptvercmp dpkg-lib.cpp -lapt-pkg
freelist : freelist.c assert.o
$(CC) $(CFLAGS) -DTESTBIN -o $@ $^
#libajdpkg.a : dpkg.o dpkg-lib.o memory3.o freelist.o assert.o
# ar rv $@ $^
# ranlib $@
britneymodule.so : britney-py.o dpkg.o dpkg-lib.o memory3.o freelist.o assert.o
$(CC) -shared -o britneymodule.so $^ -lapt-pkg
Makefile.dep :
@gcc -MM *.c *.cpp > Makefile.dep
@echo Makefile.dep : Makefile *.c *.h >> Makefile.dep
-include Makefile.dep

@ -0,0 +1,10 @@
assert.o: assert.c
britney-py.o: britney-py.c dpkg.h templates.h memory.h
checklib.o: checklib.c dpkg.h templates.h memory.h
dpkg.o: dpkg.c dpkg.h templates.h memory.h
freelist.o: freelist.c templates.h memory.h
memory2.o: memory2.c
memory3.o: memory3.c memory.h templates.h freelist.h
memory.o: memory.c memory.h templates.h freelist.h
dpkg-lib.o: dpkg-lib.cpp dpkg.h templates.h memory.h
Makefile.dep : Makefile assert.c britney-py.c checklib.c dpkg.c freelist.c memory2.c memory3.c memory.c dpkg.h freelist.h memory.h templates.h

@ -0,0 +1,32 @@
BUILDING
========
Install libapt-pkg-dev
testing/ $ make
testing/ $ mkdir old cur out
testing/ $ cd testing
testing/testing/ $ perl Makefile.PL
testing/testing/ $ make
Add old and new packages files into old and cur, respectively.
testing/ $ ./checklib i386 alpha
Will generate some test stuff in out/
TODO
====
Need some way of actually updating archives.
Need some way of judging differences between Packages files.
(so I can see what hasn't been updated and work out why;
so I can check that Packages.gz matches dpkg-scanpackages output)
Need some way of automatically explaining why packages aren't upgraded.
(shouldn't be hard?)
BUGS
====
out/ directory must exist for checklib, or segfault

@ -0,0 +1,11 @@
#include <stdio.h>
#include <stdlib.h>
int _myassertbug(int line, char *file, char *err) {
fprintf(stderr, "Assertion failed: %s:%d: %s\n", file, line, err);
fprintf(stderr, "I HATE YOU!!!");
((void(*)())0)();
abort();
return 0;
}

@ -0,0 +1,871 @@
#include <python2.3/Python.h>
#include "dpkg.h"
#define MAKE_PY_LIST(L,S,E,I,V) \
do { \
L = PyList_New(0); \
if (!L) break; \
for (S; E; I) { \
PyObject *EL; \
EL = Py_BuildValue V; \
if (!EL) { \
Py_DECREF(L); \
L = NULL; \
break; \
} \
PyList_Append(L, EL); \
Py_DECREF(EL); \
} \
if (L) PyList_Sort(L); \
} while(0)
/**************************************************************************
* britney.Packages -- dpkg_packages wrapper
*******************************************/
typedef enum { DONTFREE, FREE } dpkgpackages_freeme;
typedef struct {
PyObject_HEAD
dpkg_packages *pkgs;
PyObject *ref; /* object packages are "in" */
dpkgpackages_freeme freeme; /* free pkgs when deallocing? */
} dpkgpackages;
staticforward PyTypeObject Packages_Type;
static PyObject *dpkgpackages_new(dpkg_packages *pkgs,
dpkgpackages_freeme freeme, PyObject *ref)
{
dpkgpackages *res;
res = PyObject_NEW(dpkgpackages, &Packages_Type);
if (res == NULL) return NULL;
res->pkgs = pkgs;
res->ref = ref; Py_INCREF(res->ref);
res->freeme = freeme;
return (PyObject *) res;
}
static void dpkgpackages_dealloc(dpkgpackages *self) {
if (self->freeme == FREE) free_packages(self->pkgs);
Py_XDECREF(self->ref);
self->pkgs = NULL;
self->ref = NULL;
PyMem_DEL(self);
}
static dpkg_collected_package *dpkgpackages_lookuppkg(dpkgpackages *self,
char *pkgname)
{
dpkg_collected_package *cpkg = NULL;
cpkg = lookup_packagetbl(self->pkgs->packages, pkgname);
if (!cpkg) {
PyErr_SetString(PyExc_ValueError, "Not a valid package");
}
return cpkg;
}
static PyObject *dpkgpackages_ispresent(dpkgpackages *self, PyObject *args) {
dpkg_collected_package *cpkg;
char *pkgname;
if (!PyArg_ParseTuple(args, "s", &pkgname)) return NULL;
cpkg = lookup_packagetbl(self->pkgs->packages, pkgname);
return cpkg ? Py_BuildValue("i", 1) : Py_BuildValue("i", 0);
}
static PyObject *dpkgpackages_getversion(dpkgpackages *self, PyObject *args) {
dpkg_collected_package *cpkg;
char *pkgname;
if (!PyArg_ParseTuple(args, "s", &pkgname)) return NULL;
cpkg = lookup_packagetbl(self->pkgs->packages, pkgname);
if (cpkg) return Py_BuildValue("s", cpkg->pkg->version);
else return Py_BuildValue("");
}
static PyObject *dpkgpackages_getsource(dpkgpackages *self, PyObject *args) {
dpkg_collected_package *cpkg;
char *pkgname;
if (!PyArg_ParseTuple(args, "s", &pkgname)) return NULL;
cpkg = lookup_packagetbl(self->pkgs->packages, pkgname);
if (cpkg) return Py_BuildValue("s", cpkg->pkg->source);
else return Py_BuildValue("");
}
static PyObject *dpkgpackages_getsourcever(dpkgpackages *self, PyObject *args) {
dpkg_collected_package *cpkg;
char *pkgname;
if (!PyArg_ParseTuple(args, "s", &pkgname)) return NULL;
cpkg = lookup_packagetbl(self->pkgs->packages, pkgname);
if (cpkg) return Py_BuildValue("s", cpkg->pkg->source_ver);
else return Py_BuildValue("");
}
static PyObject *dpkgpackages_isarchall(dpkgpackages *self, PyObject *args) {
dpkg_collected_package *cpkg;
char *pkgname;
if (!PyArg_ParseTuple(args, "s", &pkgname)) return NULL;
cpkg = lookup_packagetbl(self->pkgs->packages, pkgname);
if (cpkg) return Py_BuildValue("i", cpkg->pkg->arch_all);
else return Py_BuildValue("");
}
static PyObject *dpkgpackages_isntarchall(dpkgpackages *self, PyObject *args) {
dpkg_collected_package *cpkg;
char *pkgname;
if (!PyArg_ParseTuple(args, "s", &pkgname)) return NULL;
cpkg = lookup_packagetbl(self->pkgs->packages, pkgname);
if (cpkg) return Py_BuildValue("i", !cpkg->pkg->arch_all);
else return Py_BuildValue("");
}
static PyObject *dpkgpackages_getfield(dpkgpackages *self, PyObject *args) {
char *field;
char *pkgname;
int i;
dpkg_collected_package *cpkg;
dpkg_paragraph *para;
if (!PyArg_ParseTuple(args, "ss", &pkgname, &field)) return NULL;
cpkg = dpkgpackages_lookuppkg(self, pkgname);
if (!cpkg) return NULL;
para = cpkg->pkg->details;
for (i = 0; i < para->n_entries; i++) {
if (strcasecmp(para->entry[i].name, field) == 0) {
return Py_BuildValue("s", para->entry[i].value);
}
}
return Py_BuildValue("");
}
static PyObject *dpkgpackages_isinstallable(dpkgpackages *self, PyObject *args)
{
char *pkgname;
if (!PyArg_ParseTuple(args, "s", &pkgname)) return NULL;
if (checkinstallable2(self->pkgs, pkgname)) {
return Py_BuildValue("i", 1);
} else {
return Py_BuildValue("");
}
}
static PyObject *dpkgpackages_isuninstallable(dpkgpackages *self,
PyObject *args)
{
char *pkgname;
if (!PyArg_ParseTuple(args, "s", &pkgname)) return NULL;
if (!checkinstallable2(self->pkgs, pkgname)) {
return Py_BuildValue("i", 1);
} else {
return Py_BuildValue("");
}
}
static PyObject *dpkgpackages_unsatdeps(dpkgpackages *self, PyObject *args) {
/* arguments are:
* testingpkgs[arch].unsatisfiable_deps(unstablepkgs[arch], "netbase", "Depends")
* exciting, huh?
*/
dpkgpackages *pkgpkgs;
char *pkgname, *fieldname;
dpkg_collected_package *cpkg;
int fieldidx;
int buflen = 100;
char *buf = malloc(buflen);
const char *fields[] = { "Pre-Depends", "Depends", "Recommends",
"Suggests", NULL };
satisfieddeplist *unsatdeps, *dl;
PyObject *res = Py_BuildValue("[]");
if (!PyArg_ParseTuple(args, "O!ss", &Packages_Type, &pkgpkgs, &pkgname, &fieldname)) return NULL;
cpkg = lookup_packagetbl(pkgpkgs->pkgs->packages, pkgname);
if (!cpkg) {
PyErr_SetString(PyExc_ValueError, "Not a valid package");
return NULL;
}
for (fieldidx = 0; fields[fieldidx]; fieldidx++) {
if (strcmp(fields[fieldidx], fieldname) == 0) break;
}
if (!fields[fieldidx]) {
PyErr_SetString(PyExc_ValueError, "Not a valid dependency field");
return NULL;
}
unsatdeps = checkunsatisfiabledeps(self->pkgs,
cpkg->pkg->depends[fieldidx]);
for (dl = unsatdeps; dl != NULL; dl = dl->next) {
int len;
packagelist *it;
PyObject *pkglist;
deplist *depl;
dependency *dep;
len = 0;
buf[0] = '\0';
for (depl = dl->value->depl; depl; depl = depl->next) {
dep = depl->value;
len += strlen(dep->package) + 4;
/* 4 = strlen(" | ") + 1 */
if (dep->op != dr_NOOP) {
len += strlen(dep->version) + 6;
/* 6 = strlen(" (>= )") */
}
if (len >= buflen) {
char *newbuf;
newbuf = realloc(buf, len + 100);
if (newbuf == NULL) {
free_satisfieddeplist(unsatdeps);
free(buf);
Py_DECREF(res);
PyErr_SetFromErrno(PyExc_MemoryError);
return NULL;
}
buf = newbuf;
buflen = len + 100;
}
if (buf[0] != '\0') strcat(buf, " | ");
strcat(buf, dep->package);
if (dep->op != dr_NOOP) {
sprintf(buf + strlen(buf), " (%s %s)",
dependency_relation_sym[dep->op],
dep->version);
}
}
MAKE_PY_LIST(pkglist, it = dl->value->pkgs, it, it = it->next,
("s", it->value->package)
);
{
PyObject *depel = Py_BuildValue("(sN)", buf, pkglist);
PyList_Append(res, depel);
Py_DECREF(depel);
}
}
free_satisfieddeplist(unsatdeps);
free(buf);
return res;
}
static PyObject *dpkgpackages_getattr(dpkgpackages *self, char *name) {
static struct PyMethodDef dpkgsources_methods[] = {
{ "is_present", (binaryfunc) dpkgpackages_ispresent,
METH_VARARGS, NULL },
{ "get_version", (binaryfunc) dpkgpackages_getversion,
METH_VARARGS, NULL },
{ "get_source", (binaryfunc) dpkgpackages_getsource,
METH_VARARGS, NULL },
{ "get_sourcever", (binaryfunc) dpkgpackages_getsourcever,
METH_VARARGS, NULL },
{ "is_arch_all", (binaryfunc) dpkgpackages_isarchall,
METH_VARARGS, NULL },
{ "isnt_arch_all", (binaryfunc) dpkgpackages_isntarchall,
METH_VARARGS, NULL },
{ "get_field", (binaryfunc) dpkgpackages_getfield,
METH_VARARGS, NULL },
{ "is_installable", (binaryfunc) dpkgpackages_isinstallable,
METH_VARARGS, NULL },
{ "is_uninstallable", (binaryfunc)dpkgpackages_isuninstallable,
METH_VARARGS, NULL },
{ "unsatisfiable_deps", (binaryfunc) dpkgpackages_unsatdeps,
METH_VARARGS, NULL },
{ NULL, NULL, 0, NULL }
};
if (strcmp(name, "packages") == 0) {
PyObject *packages;
packagetbl_iter it;
MAKE_PY_LIST(packages,
it = first_packagetbl(self->pkgs->packages),
!done_packagetbl(it), it = next_packagetbl(it),
("s", it.k)
);
return packages;
}
return Py_FindMethod(dpkgsources_methods, (PyObject *)self, name);
}
static PyTypeObject Packages_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0, /* ob_size (0) */
"Packages", /* type name */
sizeof(dpkgpackages), /* basicsize */
0, /* itemsize (0) */
(destructor) dpkgpackages_dealloc,
(printfunc) 0,
(getattrfunc) dpkgpackages_getattr,
(setattrfunc) 0,
(cmpfunc) 0,
(reprfunc) 0,
0, /* number methods */
0, /* sequence methods */
0, /* mapping methods */
(hashfunc) 0, /* dict[x] ?? */
(ternaryfunc) 0, /* x() */
(reprfunc) 0 /* str(x) */
};
/**************************************************************************
* britney.Sources -- dpkg_sources wrapper
*****************************************/
typedef struct {
PyObject_HEAD
dpkg_sources *srcs;
} dpkgsources;
staticforward PyTypeObject Sources_Type;
static PyObject *dpkgsources_new(PyObject *self, PyObject *args) {
dpkgsources *res = NULL;
char *dir;
PyObject *arches;
char **archesStr = NULL;
int i, count;
(void)self; /* unused */
if (!PyArg_ParseTuple(args, "sO!", &dir, &PyList_Type, &arches)) {
goto end;
}
count = PyList_Size(arches);
if (count <= 0) {
PyErr_SetString(PyExc_TypeError, "No architectures specified");
goto end;
}
archesStr = malloc(sizeof(char *) * count);
if (!archesStr) {
PyErr_SetFromErrno(PyExc_MemoryError);
goto end;
}
for (i = 0; i < count; i++) {
PyObject *arch = PyList_GetItem(arches, i);
if (!PyString_Check(arch)) {
goto end;
}
archesStr[i] = PyString_AsString(arch);
}
res = PyObject_NEW(dpkgsources, &Sources_Type);
if (res == NULL) goto end;
res->srcs = read_directory(dir, count, archesStr);
if (!res->srcs) {
Py_DECREF(res);
res = NULL;
goto end;
}
end:
if (archesStr) free(archesStr);
return (PyObject *) res;
}
static void dpkgsources_dealloc(dpkgsources *self) {
free_sources(self->srcs);
self->srcs = NULL;
PyMem_DEL(self);
}
static PyObject *dpkgsources_packages(dpkgsources *self, PyObject *args)
{
char *arch;
dpkg_packages *pkgs;
if (!PyArg_ParseTuple(args, "s", &arch)) return NULL;
pkgs = get_architecture(self->srcs, arch);
return dpkgpackages_new(pkgs, FREE, (PyObject *) self);
}
static PyObject *dpkgsources_isfake(dpkgsources *self, PyObject *args) {
char *srcname;
dpkg_source *src;
if (!PyArg_ParseTuple(args, "s", &srcname)) return NULL;
src = lookup_sourcetbl(self->srcs->sources, srcname);
if (src) return Py_BuildValue("i", src->fake);
else return Py_BuildValue("");
}
static PyObject *dpkgsources_getversion(dpkgsources *self, PyObject *args) {
char *srcname;
dpkg_source *src;
if (!PyArg_ParseTuple(args, "s", &srcname)) return NULL;
src = lookup_sourcetbl(self->srcs->sources, srcname);
if (src) return Py_BuildValue("s", src->version);
else return Py_BuildValue("");
}
static PyObject *dpkgsources_getfield(dpkgsources *self, PyObject *args) {
char *srcname, *field;
dpkg_source *src;
int i;
dpkg_paragraph *para;
if (!PyArg_ParseTuple(args, "ss", &srcname, &field)) return NULL;
src = lookup_sourcetbl(self->srcs->sources, srcname);
if (!src) {
PyErr_SetString(PyExc_ValueError, "Not a valid source package");
return NULL;
}
para = src->details;
if (para) {
for (i = 0; i < para->n_entries; i++) {
if (strcasecmp(para->entry[i].name, field) == 0) {
return Py_BuildValue("s", para->entry[i].value);
}
}
}
return Py_BuildValue("");
}
static PyObject *dpkgsources_ispresent(dpkgsources *self, PyObject *args) {
char *srcname;
if (!PyArg_ParseTuple(args, "s", &srcname)) return NULL;
if (lookup_sourcetbl(self->srcs->sources, srcname)) {
return Py_BuildValue("i", 1);
} else {
return Py_BuildValue("i", 0);
}
}
static PyObject *dpkgsources_binaries(dpkgsources *self, PyObject *args) {
char *srcname, *arch;
int archnum;
dpkg_source *src;
PyObject *res;
ownedpackagelist *p;
if (!PyArg_ParseTuple(args, "ss", &srcname, &arch)) return NULL;
for (archnum = 0; archnum < self->srcs->n_arches; archnum++) {
if (strcmp(arch, self->srcs->archname[archnum]) == 0) break;
}
if (archnum == self->srcs->n_arches) {
PyErr_SetString(PyExc_ValueError, "Not a valid architecture");
return NULL;
}
src = lookup_sourcetbl(self->srcs->sources, srcname);
if (src == NULL) {
PyErr_SetString(PyExc_ValueError, "Not a valid source package");
return NULL;
}
MAKE_PY_LIST(res, p = src->packages[archnum], p, p = p->next,
("s", p->value->package)
);
return res;
}
static PyObject *dpkgsources_getattr(dpkgsources *self, char *name) {
static struct PyMethodDef dpkgsources_methods[] = {
{ "Packages", (binaryfunc) dpkgsources_packages,
METH_VARARGS, NULL },
{ "is_fake", (binaryfunc) dpkgsources_isfake,
METH_VARARGS, NULL },
{ "get_version", (binaryfunc) dpkgsources_getversion,
METH_VARARGS, NULL },
{ "get_field", (binaryfunc) dpkgsources_getfield,
METH_VARARGS, NULL },
{ "is_present", (binaryfunc) dpkgsources_ispresent,
METH_VARARGS, NULL },
{ "binaries", (binaryfunc) dpkgsources_binaries,
METH_VARARGS, NULL },
{ NULL, NULL, 0, NULL }
};
if (strcmp(name, "arches") == 0) {
PyObject *arches;
int i;
MAKE_PY_LIST(arches, i = 0, i < self->srcs->n_arches, i++,
("s", self->srcs->archname[i])
);
return arches;
} else if (strcmp(name, "sources") == 0) {
PyObject *sources;
sourcetbl_iter it;
MAKE_PY_LIST(sources,
it = first_sourcetbl(self->srcs->sources),
!done_sourcetbl(it), it = next_sourcetbl(it),
("s", it.k)
);
return sources;
}
return Py_FindMethod(dpkgsources_methods, (PyObject *)self, name);
}
static PyTypeObject Sources_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0, /* ob_size (0) */
"Sources", /* type name */
sizeof(dpkgsources), /* basicsize */
0, /* itemsize (0) */
(destructor) dpkgsources_dealloc,
(printfunc) 0,
(getattrfunc) dpkgsources_getattr,
(setattrfunc) 0,
(cmpfunc) 0,
(reprfunc) 0,
0, /* number methods */
0, /* sequence methods */
0, /* mapping methods */
(hashfunc) 0, /* dict[x] ?? */
(ternaryfunc) 0, /* x() */
(reprfunc) 0 /* str(x) */
};
/**************************************************************************
* britney.SourcesNote -- dpkg_sourcesnote wrapper
*************************************************/
typedef struct {
PyObject_HEAD
dpkg_sources_note *srcsn;
PyObject *refs; /* list of referenced dpkgsources */
} dpkgsrcsn;
staticforward PyTypeObject SourcesNote_Type;
static PyObject *dpkgsrcsn_new(PyObject *self, PyObject *args) {
dpkgsrcsn *res = NULL;
PyObject *arches;
char **archesStr = NULL;
int i, count;
(void)self; /* unused */
if (!PyArg_ParseTuple(args, "O!", &PyList_Type, &arches)) {
goto end;
}
count = PyList_Size(arches);
if (count <= 0) {
PyErr_SetString(PyExc_TypeError, "No architectures specified");
goto end;
}
archesStr = malloc(sizeof(char *) * count);
if (!archesStr) {
PyErr_SetFromErrno(PyExc_MemoryError);
goto end;
}
for (i = 0; i < count; i++) {
PyObject *arch = PyList_GetItem(arches, i);
if (!PyString_Check(arch)) {
goto end;
}
archesStr[i] = PyString_AsString(arch);
}
res = PyObject_NEW(dpkgsrcsn, &SourcesNote_Type);
if (res == NULL) goto end;
res->refs = PyList_New(0);
res->srcsn = new_sources_note(count, archesStr);
if (!res->refs || !res->srcsn) {
Py_DECREF(res);
res = NULL;
goto end;
}
end:
if (archesStr) free(archesStr);
return (PyObject *) res;
}
static void dpkgsrcsn_dealloc(dpkgsrcsn *self) {
if (self->srcsn) free_sources_note(self->srcsn);
self->srcsn = NULL;
Py_XDECREF(self->refs);
self->refs = NULL;
PyMem_DEL(self);
}
static PyObject *dpkgsrcsn_removesource(dpkgsrcsn *self, PyObject *args) {
char *name;
if (!PyArg_ParseTuple(args, "s", &name)) return NULL;
remove_source(self->srcsn, name);
return Py_BuildValue("");
}
static PyObject *dpkgsrcsn_upgradesource(dpkgsrcsn *self, PyObject *args) {
char *name;
dpkgsources *srcs;
dpkg_source *src;
if (!PyArg_ParseTuple(args, "O!s", &Sources_Type, &srcs, &name))
return NULL;
src = lookup_sourcetbl(srcs->srcs->sources, name);
if (!src) {
PyErr_SetString(PyExc_ValueError, "Source does not exist");
return NULL;
}
if (!PySequence_In(self->refs, (PyObject *)srcs))
PyList_Append(self->refs, (PyObject *)srcs);
upgrade_source(self->srcsn, src);
return Py_BuildValue("");
}
static PyObject *dpkgsrcsn_upgradearch(dpkgsrcsn *self, PyObject *args) {
char *name, *arch;
dpkgsources *srcs;
dpkg_source *src;
if (!PyArg_ParseTuple(args, "O!ss", &Sources_Type, &srcs, &name, &arch))
return NULL;
src = lookup_sourcetbl(srcs->srcs->sources, name);
if (!src) {
PyErr_SetString(PyExc_ValueError, "Source does not exist");
return NULL;
}
if (!PySequence_In(self->refs, (PyObject *)srcs))
PyList_Append(self->refs, (PyObject *)srcs);
upgrade_arch(self->srcsn, src, arch);
return Py_BuildValue("");
}
static PyObject *dpkgsrcsn_undochange(dpkgsrcsn *self, PyObject *args) {
if (!PyArg_ParseTuple(args, "")) return NULL;
undo_change(self->srcsn);
return Py_BuildValue("");
}
static PyObject *dpkgsrcsn_commitchanges(dpkgsrcsn *self, PyObject *args) {
if (!PyArg_ParseTuple(args, "")) return NULL;
commit_changes(self->srcsn);
return Py_BuildValue("");
}
static PyObject *dpkgsrcsn_writenotes(dpkgsrcsn *self, PyObject *args) {
char *dir;
if (!PyArg_ParseTuple(args, "s", &dir)) return NULL;
write_notes(dir, self->srcsn);
return Py_BuildValue("");
}
static PyObject *dpkgsrcsn_packages(dpkgsrcsn *self, PyObject *args) {
char *arch;
int archnum;
if (!PyArg_ParseTuple(args, "s", &arch)) return NULL;
for (archnum = 0; archnum < self->srcsn->n_arches; archnum++) {
if (strcmp(arch, self->srcsn->archname[archnum]) == 0) break;
}
if (archnum == self->srcsn->n_arches) {
PyErr_SetString(PyExc_ValueError, "Not a valid architecture");
return NULL;
}
return dpkgpackages_new(self->srcsn->pkgs[archnum], DONTFREE,
(PyObject *) self);
}
static PyObject *dpkgsrcsn_getversion(dpkgsrcsn *self, PyObject *args) {
char *srcname;
dpkg_source_note *srcn;
if (!PyArg_ParseTuple(args, "s", &srcname)) return NULL;
srcn = lookup_sourcenotetbl(self->srcsn->sources, srcname);
if (srcn) return Py_BuildValue("s", srcn->source->version);
else return Py_BuildValue("");
}
static PyObject *dpkgsrcsn_getfield(dpkgsrcsn *self, PyObject *args) {
char *srcname, *field;
dpkg_source_note *srcn;
int i;
dpkg_paragraph *para;
if (!PyArg_ParseTuple(args, "ss", &srcname, &field)) return NULL;
srcn = lookup_sourcenotetbl(self->srcsn->sources, srcname);
if (!srcn) {
PyErr_SetString(PyExc_ValueError, "Not a valid source package");
return NULL;
}
para = srcn->source->details;
if (para) {
for (i = 0; i < para->n_entries; i++) {
if (strcasecmp(para->entry[i].name, field) == 0) {
return Py_BuildValue("s", para->entry[i].value);
}
}
}
return Py_BuildValue("");
}
static PyObject *dpkgsrcsn_ispresent(dpkgsrcsn *self, PyObject *args) {
char *srcname;
if (!PyArg_ParseTuple(args, "s", &srcname)) return NULL;
if (lookup_sourcenotetbl(self->srcsn->sources, srcname)) {
return Py_BuildValue("i", 1);
} else {
return Py_BuildValue("i", 0);
}
}
static PyObject *dpkgsrcsn_isfake(dpkgsrcsn *self, PyObject *args) {
char *srcname;
dpkg_source_note *srcn;
if (!PyArg_ParseTuple(args, "s", &srcname)) return NULL;
srcn = lookup_sourcenotetbl(self->srcsn->sources, srcname);
if (srcn) return Py_BuildValue("i", srcn->source->fake);
else return Py_BuildValue("");
}
static PyObject *dpkgsrcsn_binaries(dpkgsrcsn *self, PyObject *args) {
char *srcname, *arch;
int archnum;
dpkg_source_note *srcn;
PyObject *res;
packagelist *p;
if (!PyArg_ParseTuple(args, "ss", &srcname, &arch)) return NULL;
for (archnum = 0; archnum < self->srcsn->n_arches; archnum++) {
if (strcmp(arch, self->srcsn->archname[archnum]) == 0) break;
}
if (archnum == self->srcsn->n_arches) {
PyErr_SetString(PyExc_ValueError, "Not a valid architecture");
return NULL;
}
srcn = lookup_sourcenotetbl(self->srcsn->sources, srcname);
if (srcn == NULL) {
PyErr_SetString(PyExc_ValueError, "Not a valid source package");
return NULL;
}
MAKE_PY_LIST(res, p = srcn->binaries[archnum], p, p = p->next,
("s", p->value->package)
);
return res;
}
static PyObject *dpkgsrcsn_getattr(dpkgsrcsn *self, char *name) {
static struct PyMethodDef dpkgsrcsn_methods[] = {
{ "remove_source", (binaryfunc) dpkgsrcsn_removesource,
METH_VARARGS, NULL },
{ "upgrade_source", (binaryfunc) dpkgsrcsn_upgradesource,
METH_VARARGS, NULL },
{ "upgrade_arch", (binaryfunc) dpkgsrcsn_upgradearch,
METH_VARARGS, NULL },
{ "undo_change", (binaryfunc) dpkgsrcsn_undochange,
METH_VARARGS, NULL },
{ "commit_changes", (binaryfunc) dpkgsrcsn_commitchanges,
METH_VARARGS, NULL },
{ "write_notes", (binaryfunc) dpkgsrcsn_writenotes,
METH_VARARGS, NULL },
{ "Packages", (binaryfunc) dpkgsrcsn_packages,
METH_VARARGS, NULL },
{ "get_version", (binaryfunc) dpkgsrcsn_getversion,
METH_VARARGS, NULL },
{ "get_field", (binaryfunc) dpkgsrcsn_getfield,
METH_VARARGS, NULL },
{ "is_present", (binaryfunc) dpkgsrcsn_ispresent,
METH_VARARGS, NULL },
{ "is_fake", (binaryfunc) dpkgsrcsn_isfake,
METH_VARARGS, NULL },
{ "binaries", (binaryfunc) dpkgsrcsn_binaries,
METH_VARARGS, NULL },
{ NULL, NULL, 0, NULL }
};
if (strcmp(name, "arches") == 0) {
PyObject *arches;
int i;
MAKE_PY_LIST(arches, i = 0, i < self->srcsn->n_arches, i++,
("s", self->srcsn->archname[i])
);
return arches;
} else if (strcmp(name, "sources") == 0) {
PyObject *sources;
sourcenotetbl_iter it;
MAKE_PY_LIST(sources,
it = first_sourcenotetbl(self->srcsn->sources),
!done_sourcenotetbl(it),
it = next_sourcenotetbl(it),
("s", it.k)
);
return sources;
} else if (strcmp(name, "can_undo") == 0) {
if (can_undo(self->srcsn)) {
return Py_BuildValue("i", 1);
} else {
return Py_BuildValue("");
}
}
return Py_FindMethod(dpkgsrcsn_methods, (PyObject *)self, name);
}
static PyTypeObject SourcesNote_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0, /* ob_size (0) */
"SourcesNote", /* type name */
sizeof(dpkgsrcsn), /* basicsize */
0, /* itemsize (0) */
(destructor) dpkgsrcsn_dealloc,
(printfunc) 0,
(getattrfunc) dpkgsrcsn_getattr,
(setattrfunc) 0,
(cmpfunc) 0,
(reprfunc) 0,
0, /* number methods */
0, /* sequence methods */
0, /* mapping methods */
(hashfunc) 0, /* dict[x] ?? */
(ternaryfunc) 0, /* x() */
(reprfunc) 0 /* str(x) */
};
/**************************************************************************
* britney.versioncmp() -- apt version compare function
******************************************************/
static PyObject *apt_versioncmp(PyObject *self, PyObject *args) {
char *l, *r;
int res;
(void)self; /* unused */
if (!PyArg_ParseTuple(args, "ss", &l, &r)) {
return NULL;
}
res = versioncmp(l,r);
return Py_BuildValue("i", res);
}
/**************************************************************************
* module initialisation
***********************/
static PyMethodDef britneymethods[] = {
{ "Sources", dpkgsources_new, METH_VARARGS, NULL },
{ "SourcesNote", dpkgsrcsn_new, METH_VARARGS, NULL },
{ "versioncmp", apt_versioncmp, METH_VARARGS, NULL },
{ NULL, NULL, 0, NULL }
};
void initbritney(void) {
Py_InitModule("britney", britneymethods);
}

@ -0,0 +1,185 @@
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include "dpkg.h"
#if 0
static void checknewsrc(sourcetbl *srcstbl, dpkg_source *cur, void *data) {
dpkg_sources *oldsrc = data;
dpkg_source *old;
old = lookup_sourcetbl(oldsrc->sources, cur->package);
if (old == NULL) {
printf("New: %s (%s)\n", cur->package, cur->version );
} else if (strcmp(old->version, cur->version) != 0) {
printf("Updated: %s (%s, was %s)\n",
cur->package, cur->version, old->version );
} else {
dpkg_source *src2;
src2 = remove_sourcetbl(srcstbl, cur->package);
assert(cur == src2);
free_source(cur);
}
}
static void checkoldsrc(sourcetbl *oldsrctbl, dpkg_source *old, void *data) {
dpkg_sources *src = data;
dpkg_source *cur;
(void)oldsrctbl;
cur = lookup_sourcetbl(src->sources, old->package);
if (cur == NULL) {
printf("Removed: %s (was %s)\n", old->package, old->version );
}
}
static void checkuptodate(sourcetbl *srctbl, dpkg_source *src, void *data) {
int i;
int remove;
ownedpackagelist **p;
dpkg_sources *srcs = data;
(void)srctbl;
remove = 0;
for (i = 0; i < srcs->n_arches; i++) {
p = &src->packages[i];
while(*p != NULL) {
if (strcmp((*p)->value->source_ver, src->version) != 0) {
if (cmpversions((*p)->value->source_ver, GT, src->version)) {
printf("ALERT: old source: ");
} else {
printf("WARN: out of date: ");
}
printf("%s %s: %s binary: %s %s from %s\n",
src->package, src->version, srcs->archname[i],
(*p)->value->package, (*p)->value->version,
(*p)->value->source_ver);
delete_ownedpackagelist(p);
} else {
p = &(*p)->next;
}
}
if (src->packages[i] == NULL) {
printf("%s missing uptodate binaries for %s\n",
src->package, srcs->archname[i]);
remove = 1;
}
}
if (remove) {
dpkg_source *src2;
src2 = remove_sourcetbl(srcs->sources, src->package);
assert(src == src2);
free_source(src);
}
}
#endif
static void upgrade(sourcetbl *srctbl, dpkg_source *src, void *data) {
static int i = 0;
dpkg_sources_note *srcsn = data;
(void)srctbl;
i++; i %= 1000;
if (can_undo(srcsn)) {
if (i % 29 == 1 || i % 31 == 1 || i % 7 == 5)
undo_change(srcsn);
if (i % 33 == 0) commit_changes(srcsn);
}
upgrade_source(data, src);
}
static void checkpkgs(packagetbl *pkgtbl, dpkg_collected_package *cpkg,
void *data)
{
dpkg_packages *pkgs = data;
assert(pkgs->packages == pkgtbl);
printf("Trying %s (%s, %s)\n", cpkg->pkg->package, cpkg->pkg->version, pkgs->arch);
if (!checkinstallable2(pkgs, cpkg->pkg->package)) {
printf("Package: %s (%s, %s) is uninstallable\n",
cpkg->pkg->package, cpkg->pkg->version, pkgs->arch);
}
}
void print_memblock_summary(void);
int main(int argc, char **argv) {
dpkg_sources *src = NULL, *oldsrc = NULL;
dpkg_sources_note *srcsn;
dpkg_source *srcpkg;
dpkg_packages *pkgs[10];
int n_pkgs;
int i,j;
int reps;
if (argc < 3) {
printf("Usage: %s <reps> <arch>...\n", argv[0]);
exit(EXIT_FAILURE);
}
reps = atoi(argv[1]);
if (reps < 1) {
printf("reps must be >= 1\n");
exit(EXIT_FAILURE);
}
src = read_directory("cur", argc - 2, argv + 2);
oldsrc = read_directory("old", argc - 2, argv + 2);
srcsn = new_sources_note(argc - 2, argv + 2);
printf("FINISHED LOADING\n"); fflush(stdout); /* sleep(5); */
#if 0
iterate_sourcetbl(oldsrc->sources, checkoldsrc, src);
printf("FIRST\n");
iterate_sourcetbl(src->sources, checkuptodate, src);
printf("SECOND\n");
iterate_sourcetbl(src->sources, checkuptodate, src);
printf("END\n");
iterate_sourcetbl(src->sources, checknewsrc, oldsrc);
#endif
n_pkgs = 0;
for (i = argc - 1; i > 1; i--) {
pkgs[n_pkgs++] = get_architecture(oldsrc, argv[i]);
}
for (j = 0; j < reps; j++) {
printf("Round %d/%d starting...\n", j + 1, reps);
for (i = 0; i < n_pkgs; i++) {
iterate_packagetbl(pkgs[i]->packages, checkpkgs, pkgs[i]);
}
printf("Round %d ended.\n", j+1);
}
iterate_sourcetbl(src->sources, upgrade, srcsn);
iterate_sourcetbl(oldsrc->sources, upgrade, srcsn);
for (i = 0; i < n_pkgs; i++) {
free_packages(pkgs[i]);
}
srcpkg = lookup_sourcetbl(oldsrc->sources, "omirr");
if (srcpkg != NULL) {
printf("Adding old\n");
upgrade_source(srcsn, srcpkg);
}
srcpkg = lookup_sourcetbl(src->sources, "omirr");
if (srcpkg != NULL) {
printf("Adding cur\n");
upgrade_source(srcsn, srcpkg);
}
printf("FINISHED PROCESSING\n"); fflush(stdout); /* sleep(5); */
write_directory("out", oldsrc);
printf("FINISHED WRITING\n"); fflush(stdout); /* sleep(5); */
free_sources_note(srcsn);
free_sources(src);
free_sources(oldsrc);
DEBUG_ONLY( print_memblock_summary(); )
return 0;
}

@ -0,0 +1,34 @@
#include <apt-pkg/debversion.h>
extern "C" {
#include "dpkg.h"
int versioncmp(char *left, char *right) {
return debVS.CmpVersion(left, right);
}
int cmpversions(char *left, int op, char *right) {
int i = debVS.CmpVersion(left, right);
switch(op) {
case dr_LT: return i < 0;
case dr_LTEQ: return i <= 0;
case dr_EQ: return i == 0;
case dr_GTEQ: return i >= 0;
case dr_GT: return i > 0;
}
return 0;
}
}
#ifdef TESTBIN
int main(int argc, char **argv) {
if (argc != 3) { printf("Usage: %s <ver> <ver>\n", argv[0]); exit(1); }
printf("%d\n", versioncmp(argv[1], argv[2]));
return 0;
}
#endif

File diff suppressed because it is too large Load Diff

@ -0,0 +1,207 @@
#ifndef DPKG_H
#define DPKG_H
#include "templates.h"
#include "memory.h"
#include <stdio.h>
/**************************************************************************
* Coping with an rfc822-esque field
*/
typedef struct dpkg_entry dpkg_entry;
struct dpkg_entry {
char *name;
char *value;
};
typedef struct dpkg_paragraph dpkg_paragraph;
struct dpkg_paragraph {
int n_entries;
int n_allocated;
dpkg_entry *entry;
};
/**************************************************************************
* Coping with a package (or many pkgs) as an abstract entity
*/
typedef enum {dr_NOOP,dr_LT,dr_LTEQ,dr_EQ,dr_GTEQ,dr_GT} dependency_relation;
extern char *dependency_relation_sym[];
typedef struct dependency dependency;
struct dependency {
char *package;
dependency_relation op;
char *version;
};
LIST(deplist, dependency*);
LIST(deplistlist, deplist*);
LIST(packagenamelist, char*);
LIST(ownedpackagenamelist, char*);
typedef struct dpkg_package dpkg_package;
struct dpkg_package {
char *package;
char *version;
char *source;
char *source_ver;
int priority;
int arch_all;
deplistlist *depends[4];
deplist *conflicts;
ownedpackagenamelist *provides;
dpkg_paragraph *details;
};
LIST(packagelist, dpkg_package *);
LIST(ownedpackagelist, dpkg_package *);
typedef struct satisfieddep satisfieddep;
struct satisfieddep {
/* dependency *dep; */
deplist *depl;
packagelist *pkgs;
};
LIST(satisfieddeplist, satisfieddep *);
/**************************************************************************
* Coping with a source package (and collections thereof) as an abstract
* entity, owning a bunch of binary packages
*/
typedef struct dpkg_source dpkg_source;
struct dpkg_source {
char *package;
char *version;
int fake;
struct dpkg_sources *owner;
ownedpackagelist **packages; /* one for each architecture */
dpkg_paragraph *details;
};
HASH(sourcetbl,char *,dpkg_source *);
typedef struct dpkg_sources dpkg_sources;
struct dpkg_sources {
int n_arches;
char **archname;
sourcetbl *sources;
ownedpackagelist **unclaimedpackages; /* one for each arch */
};
/**************************************************************************
*/
typedef struct dpkg_collected_package dpkg_collected_package;
struct dpkg_collected_package {
dpkg_package *pkg;
int installed, conflicted;
enum { UNKNOWN, YES } installable;
packagenamelist *mayaffect;
/* on update, the installability_checked of each /mayaffect/ed package
* is cleared, and the mayaffect list is cleared.
*
* note that installable = NO couldn't be maintained over adding a package
* to testing. installable = YES can be, thanks to the mayaffect list
* (once a package is removed, everything it mayaffect must be set back
* to unknown, but everything else is okay)
*/
};
LIST(collpackagelist, dpkg_collected_package *);
/**************************************************************************
*/
typedef struct dpkg_provision dpkg_provision;
struct dpkg_provision {
char *version;
dpkg_collected_package *pkg;
};
LIST(virtualpkg, dpkg_provision);
HASH(virtualpkgtbl,char *,virtualpkg *);
HASH(packagetbl,char *,dpkg_collected_package *);
typedef struct dpkg_packages dpkg_packages;
struct dpkg_packages {
char *arch;
packagetbl *packages;
virtualpkgtbl *virtualpkgs;
};
typedef struct dpkg_source_note dpkg_source_note;
struct dpkg_source_note {
dpkg_source *source; /* unowned */
int n_arches;
packagelist **binaries; /* one for each arch */
};
HASH(sourcenotetbl, char *, dpkg_source_note *);
LIST(source_note_list, dpkg_source_note *);
/* contains a copy of the previous source_note */
LIST(source_note_listlist, source_note_list *);
/* contains a copy of all the source_notes modified by the last op */
typedef struct dpkg_sources_note dpkg_sources_note;
struct dpkg_sources_note {
unsigned long magic;
sourcenotetbl *sources;
int n_arches;
dpkg_packages **pkgs;
char **archname;
source_note_listlist *undo;
};
void free_packages(dpkg_packages *pkgs);
void free_sources(dpkg_sources *s);
dpkg_packages *get_architecture(dpkg_sources *srcs, char *arch);
/* parsing things */
int checkinstallable(dpkg_packages *pkgs, collpackagelist *instoneof);
int checkinstallable2(dpkg_packages *pkgs, char *pkgname);
satisfieddeplist *checkunsatisfiabledeps(dpkg_packages *pkgs,
deplistlist *deps);
dpkg_sources *read_directory(char *dir, int n_arches, char *archname[]);
void write_directory(char *dir, dpkg_sources *srcs);
void free_source(dpkg_source *s);
/* adding and deleting and stuff */
dpkg_sources_note *new_sources_note(int n_arches, char **archname);
void remove_source(dpkg_sources_note *srcsn, char *name);
void upgrade_source(dpkg_sources_note *srcsn, dpkg_source *src);
void upgrade_arch(dpkg_sources_note *srcsn, dpkg_source *src, char *arch);
void write_notes(char *dir, dpkg_sources_note *srcsn);
void free_sources_note(dpkg_sources_note *srcsn);
void free_source_note(dpkg_source_note *srcn);
void undo_change(dpkg_sources_note *srcsn);
int can_undo(dpkg_sources_note *srcsn);
void commit_changes(dpkg_sources_note *srcsn);
int versioncmp(char *left, char *right);
int cmpversions(char *left, int op, char *right);
#endif

@ -0,0 +1,188 @@
#include <stdio.h>
#include <stdlib.h>
#include "templates.h"
typedef unsigned long ul;
#define SIZE (sizeof(ul) * 8)
#define ROUND_DOWN(x) ((x) & ~(SIZE-1))
#define ROUND_UP(x) ROUND_DOWN((x) + (SIZE-1))
#define NEXT_UP(x) ROUND_DOWN((x) + SIZE)
#define NEXT_DOWN(x) ROUND_DOWN((x) - 1)
#define SETBIT(s,p) \
assert( (bits[(s)/SIZE] & (p)) == (setp ? 0 : (p)) ); \
if (setp) bits[(s)/SIZE] |= (p); \
else bits[(s)/SIZE] &= ~(p)
#define GETBIT(s) (bits[ROUND_DOWN(s)/SIZE] & (1ul << (NEXT_UP(s) - s - 1)))
size_t count_free_bits_back(ul *bits, size_t s) {
size_t cnt = 0;
ul w = ROUND_DOWN(s) / SIZE;
size_t add = s % SIZE;
ul off = (~0ul) << (SIZE - add);
ul H, d;
while ((bits[w] & off) == 0) {
cnt += add;
add = SIZE;
off = ~0ul;
if (w == 0)
return cnt;
w--;
}
H = add;
add = 0;
while ((d = (H - add) / 2) > 0) {
ul offM = (off >> d) & off;
if (bits[w] & offM) {
off = offM;
H = H - d;
} else {
add = H - d;
}
}
cnt += add;
return cnt;
}
size_t count_free_bits_after(ul *bits, size_t s, size_t end) {
size_t cnt = 0;
ul w = ROUND_DOWN(s) / SIZE;
size_t add = SIZE - s % SIZE;
ul off = (~0ul) >> (SIZE - add);
ul H, d;
end /= SIZE;
while ((bits[w] & off) == 0) {
cnt += add;
add = SIZE;
off = ~0ul;
w++;
if (w == end)
return cnt;
}
H = add;
add = 0;
while ((d = (H - add) / 2) > 0) {
ul offM = off << d;
if (bits[w] & offM) {
off = offM;
H = H - d;
} else {
add = H - d;
}
}
cnt += add;
return cnt;
}
void find_long_freebits(ul *bits, size_t s, ul *start, size_t *size) {
ul clen = 0;
ul bstart = 0, blen = 0;
ul i, k;
for (i = 0; i < s; i++) {
if (bits[i] == 0) {
clen++;
} else {
if (clen > blen) {
bstart = i - clen;
blen = clen;
}
clen = 0;
}
}
if (blen == 0) return;
bstart *= SIZE; blen *= SIZE;
k = count_free_bits_back(bits, bstart);
bstart -= k; blen += k;
blen += count_free_bits_after(bits, bstart + blen, s*SIZE);
*start = bstart; *size = blen;
}
void mark_bits(ul *bits, ul s, size_t size, int setp) {
ul e = s+size;
ul rds = ROUND_DOWN(s);
ul nus = rds + SIZE;
ul rue = ROUND_UP(e);
ul patl = (~0UL) >> (s % SIZE);
ul patr = (~0UL) << (rue - e);
assert(size > 0);
/* bits[s1..e1] get touched, but bits[s1], bits[e1] only partially
*
* if s1 == e1, then bits[s1] get touched from [s%SIZE, e%SIZE)
* else
* bits[s1] gets touched from [s%SIZE, SIZE)
* bits[s2..e1) get reset completely
* bits[e1] gets touched from [0, e%SIZE)
*/
if (nus >= e) {
/* ROUND_DOWN(s) <= s < e <= NEXT_UP(s) */
SETBIT(rds, patl & patr);
} else {
/* ROUND_DOWN(s) <= s < NEXT_UP(s) <= NEXT_DOWN(e) < e */
ul rde = ROUND_DOWN(e);
SETBIT(rds, patl);
SETBIT(rde, patr);
while (nus < rde) {
SETBIT(nus, ~0UL);
nus += SIZE;
}
}
}
void print_bits(ul *bits, ul s) {
ul i;
putchar(' ');
for (i = 0; i < s * SIZE; i++) {
putchar( GETBIT(i) ? '1' : '0' );
}
}
#ifdef TESTBIN
#define X 2
int main(void) {
ul memory[X];
ul l, r;
ul k = 5;
memset(memory, 0, sizeof(memory));
for (l = 0; l < X*SIZE; l += k) {
for (r = 1; l+(r*r) < X*SIZE; r++) {
printf("%lu %lu (%lu %lu", l, r*r,
(unsigned long) count_free_bits_back(memory, X*SIZE), (unsigned long) X*SIZE);
mark_bits(memory, l, r*r, 1);
printf("; %lu %lu %lu; %lu %lu %lu;): ",
(unsigned long) count_free_bits_back(memory, X*SIZE) + l + r*r,
(unsigned long) count_free_bits_after(memory, l + r*r, X*SIZE) + l + r*r,
(unsigned long) X*SIZE,
(unsigned long) count_free_bits_back(memory, l),
(unsigned long) count_free_bits_after(memory, 0, X*SIZE),
l);
print_bits(memory, X);
printf("\n");
mark_bits(memory, l, r*r, 0);
}
}
return 0;
}
#endif

@ -0,0 +1,14 @@
#ifndef FREELIST_H
#define FREELIST_H
#include <stdlib.h>
typedef unsigned long flb_t;
void mark_bits(flb_t *bits, flb_t s, size_t size, int setp);
size_t count_free_bits_back(flb_t *bits, size_t s);
size_t count_free_bits_after(flb_t *bits, size_t s, size_t end);
void find_long_freebits(flb_t *bits, flb_t s, flb_t *start, size_t *size);
#endif

@ -0,0 +1,18 @@
<a href="README">README</a><br>
<a href="Makefile">Makefile</a><br>
<a href="assert.c">assert.c</a><br>
<a href="britney-py.c">britney-py.c</a><br>
<a href="checklib.c">checklib.c</a><br>
<a href="dpkg.c">dpkg.c</a><br>
<a href="freelist.c">freelist.c</a><br>
<a href="memory.c">memory.c</a><br>
<a href="memory2.c">memory2.c</a><br>
<a href="memory3.c">memory3.c</a><br>
<a href="dpkg-lib.cpp">dpkg-lib.cpp</a><br>
<a href="dpkg.h">dpkg.h</a><br>
<a href="freelist.h">freelist.h</a><br>
<a href="memory.h">memory.h</a><br>
<a href="templates.h">templates.h</a><br>
<a href="check_out.py">check_out.py</a><br>
<a href="check_uptodate.py">check_uptodate.py</a><br>
<a href="update_out.py">update_out.py</a><br>

@ -0,0 +1,389 @@
#include <stdio.h>
#include <stdlib.h>
#include "memory.h"
#include "templates.h"
#include "freelist.h"
/**** THEORY
*
So, we have blocks with a freelist
XXX............XXXXXXX..XXXXX.....XXXXXX......
Within a block, we work with segments. A segment is...
^..........|
Every now and then we make sure we've got a decent sized segment.
We have multiple blocks. They're kept ordered by the size of their
current segment.
**********************************************/
#define ALIGN 4
#define FLBT_BITS (sizeof(flb_t)*8)
#define MEMBLOCKSIZE (1 << 22)
#define ALIGNEDSIZE(s) (((s) + ALIGN - 1) / ALIGN * ALIGN)
struct memblock {
struct memblock *next;
size_t n_bytes; /* index of free char */
size_t size; /* size of block after char */
unsigned n_used_chunks; /* number of unfreed blocks */
size_t n_used_bytes; /* number of bytes actually used */
size_t n_productive_bytes; /* number of bytes used usefully */
flb_t free[MEMBLOCKSIZE/ALIGN/FLBT_BITS + 1];
unsigned char mem[MEMBLOCKSIZE];
};
typedef struct memblock memblock;
static memblock *base = NULL;
#ifdef MDEBUG1
static int valid_memblock_mdebug1(struct memblock *mb) {
size_t cnt, i;
static int rarity = 0;
assert(mb->n_bytes + mb->size <= sizeof(mb->mem));
if (mb->n_used_chunks == 0) assert(mb->n_bytes == 0);
assert(((unsigned long)mb->mem + mb->n_bytes) % ALIGN == 0);
assert(mb->n_productive_bytes <= mb->n_used_bytes);
assert(mb->n_used_bytes + mb->size <= sizeof(mb->mem));
#define TWO(k) (1ul << (k))
#define CYCL(k) (~0ul / (1 + TWO(TWO(k))))
rarity++; rarity %= 25000;
if (rarity != 0) {
cnt = mb->n_used_bytes;
} else {
cnt = 0;
for (i = 0; i < sizeof(mb->mem)/ALIGN/FLBT_BITS+1; i++) {
unsigned long x = mb->free[i];
size_t s;
x = (x & CYCL(0)) + ((x >> TWO(0)) & CYCL(0));
x = (x & CYCL(1)) + ((x >> TWO(1)) & CYCL(1));
for (s = 2; (2u << s) <= FLBT_BITS; s++) {
x += x >> TWO(s);
x &= CYCL(s);
}
cnt += x * ALIGN;
}
}
#undef TWO
#undef CYCL
assert(cnt == mb->n_used_bytes);
return 1;
}
#endif
#if MDEBUG3
static int valid_memblock_mdebug3(struct memblock *mb) {
size_t offset, step, used;
unsigned chunk = 0;
offset = 0;
used = 0;
if ((unsigned long)mb->mem % ALIGN != 0)
offset = ALIGN - ((unsigned long)mb->mem % ALIGN);
while(offset < mb->n_bytes) {
step = *(size_t*)(mb->mem + offset);
assert(step % ALIGN == 0 || step % ALIGN == 1);
if (step % ALIGN == 1) step--; /* freed */
else used += step;
assert(step > 0);
offset += step;
chunk++;
}
assert(used == mb->n_used_bytes);
return 1;
}
#endif
inline static int valid_memblock(struct memblock *mb) {
(void)mb;
MDEBUG1_ONLY( if (!valid_memblock_mdebug1(mb)) return 0; )
MDEBUG3_ONLY( if (!valid_memblock_mdebug3(mb)) return 0; )
return 1;
}
void print_memblock_summary(void) {
struct memblock *mb;
unsigned long tused = 0, talloc = 0, tprod = 0, tavail = 0, nb = 0;
for (mb = base; mb != NULL; mb = mb->next) {
assert(valid_memblock(mb));
MDEBUG3_ONLY(
fprintf(stderr, "%p: [%d,%lu/%lu,%p,%p]\n", mb,
mb->n_used_chunks, (unsigned long)mb->n_used_bytes,
(unsigned long)mb->n_bytes, mb->next, mb->mem);
)
if (mb != base && mb->size * 50 < sizeof(mb->mem) - mb->n_used_bytes) {
flb_t k; size_t s;
k = mb->n_bytes / ALIGN;
s = mb->size / ALIGN;
find_long_freebits(mb->free,MEMBLOCKSIZE/ALIGN/FLBT_BITS+1,&k,&s);
k *= ALIGN; s *= ALIGN;
fprintf(stderr, "%p %lu: Wasted block "
"[%d chunks, %lu free bytes, %lu avail bytes, %2.2f%%], suggested [%ld,%ld] -> [%ld,%ld]\n",
mb->mem, nb, mb->n_used_chunks,
(unsigned long) sizeof(mb->mem) - mb->n_used_bytes,
(unsigned long) mb->size,
(float) 100.0 * mb->size / (sizeof(mb->mem) - mb->n_used_bytes),
(unsigned long) mb->n_bytes, (unsigned long) mb->size,
(unsigned long) k, (unsigned long) s);
if (s > mb->size * 4 || s * 25 > sizeof(mb->mem) - mb->n_used_bytes) {
mb->n_bytes = k;
mb->size = s;
}
}
nb++;
tprod += mb->n_productive_bytes;
tused += mb->n_used_bytes;
tavail += mb->size;
talloc += sizeof(memblock);
}
fprintf(stderr, "TOTAL: %lu %lu KiB alloc"
"(%lu/%lu available, %2.2f%%) (%lu KiB used, %2.2f%%) (%lu KiB useful, %2.2f%%)\n",
nb, talloc / 1024,
(unsigned long) (base ? base->size / 1024 : 0),
tavail / 1024, (talloc > 0 ? 100.0*tavail/talloc : 0.0),
tused / 1024, (talloc > 0 ? 100.0*tused/talloc : 0.0),
tprod / 1024, (talloc > 0 ? 100.0*tprod/talloc : 0.0));
}
MDEBUG1_ONLY(static int first_malloc = 0;)
#ifdef MDEBUG3
static void print_memblock_stats(void) {
struct memblock *mb;
size_t offset;
for (mb = base; mb != NULL; mb = mb->next) {
assert(valid_memblock(mb));
printf("%p: [%d,%lu/%lu/%lu,%p,%p:\n", mb,
mb->n_used_chunks, (unsigned long)mb->n_productive_bytes,
(unsigned long)mb->n_used_bytes, (unsigned long)mb->n_bytes,
mb->next, mb->mem);
offset = 0;
if ((unsigned long)mb->mem % ALIGN != 0)
offset = ALIGN - ((unsigned long)mb->mem % ALIGN);
while(offset < mb->n_bytes) {
size_t step = *(size_t*)(mb->mem + offset);
if (step % ALIGN == 1) {
step--;
printf(" (%d)", (int) step);
} else {
printf(" %d", (int) step);
}
offset += step;
}
printf("\n");
}
printf("\n");
return;
}
#endif
void *block_malloc(size_t size) {
memblock *where = base;
void *result;
size_t realsize = size;
MDEBUG3_ONLY( if (first_malloc) print_memblock_stats(); )
MDEBUG3_ONLY( first_malloc = 0; )
(void)assert(ALIGN >= sizeof(size_t)); /* ALIGN is set too small! */
MDEBUG2_ONLY(size += ALIGN;)
/* for the size, so the caller can be checked */
size = ALIGNEDSIZE(size);
assert(size > 0 && size < sizeof(where->mem));
assert(!where || ((unsigned long)where->mem + where->n_bytes) % ALIGN == 0);
if ( !where || where->size < size ) {
MDEBUG1_ONLY(print_memblock_summary();)
where = malloc(sizeof(memblock));
if (where == NULL) {
int i;
fprintf(stderr, "block_malloc: failed trying to allocate memblock\n");
i = 0; where = base; while(where) {i++; where = where->next;}
fprintf(stderr, "(had allocated %d blocks, each %lu bytes)\n", i,
(unsigned long)sizeof(memblock));
return NULL;
}
where->n_used_chunks = 0;
memset(where->free, 0, sizeof(where->free));
where->n_bytes = 0;
where->size = sizeof(where->mem);
assert( (unsigned long)where->mem % ALIGN == 0);
/* XXX: should be able to cope with this :( */
where->n_used_bytes = where->n_bytes;
where->n_productive_bytes = 0;
(where)->next = base;
base = where;
MDEBUG2_ONLY(memset(where->mem, 0xDD, sizeof(where->mem));)
}
result = where->mem + where->n_bytes;
assert( (unsigned long)where->mem % ALIGN == where->n_bytes % ALIGN );
assert( size % ALIGN == 0 );
mark_bits(where->free,
(unsigned long)((unsigned char*)result - where->mem) / ALIGN,
size / ALIGN, 1);
where->n_bytes += size;
where->size -= size;
where->n_used_bytes += size;
where->n_productive_bytes += realsize;
where->n_used_chunks++;
MDEBUG2_ONLY( memset(result, 0xEE, size); )
MDEBUG2_ONLY( *(size_t *)result = realsize; )
MDEBUG2_ONLY( result += ALIGN; )
assert(((unsigned long)where->mem + where->n_bytes) % ALIGN == 0);
assert(valid_memblock(where));
return result;
}
static memblock **find_memblock(unsigned char *mem) {
memblock **where;
for (where = &base; *where != NULL; where = &(*where)->next) {
memblock *mb = *where;
assert(valid_memblock(mb));
if (&mb->mem[0] <= mem && (size_t)(mem - mb->mem) < sizeof(mb->mem)) {
return where;
}
}
return NULL;
}
static void free_in_memblock(memblock *mb, unsigned char *mem, size_t size) {
MDEBUG2_ONLY(size_t *stmem = ((size_t*)mem) - 1;)
assert(mb && mem && size > 0);
mb->n_used_chunks--;
mb->n_used_bytes -= ALIGNEDSIZE(size);
mark_bits(mb->free, (unsigned long)(mem - mb->mem) / ALIGN,
ALIGNEDSIZE(size) / ALIGN, 0);
#ifdef MDEBUG2
mark_bits(mb->free, (unsigned long)(mem - mb->mem) / ALIGN - 1, 1, 0);
mb->n_used_bytes -= ALIGN;
#endif
if ((size_t)(mem - mb->mem) + ALIGNEDSIZE(size) == mb->n_bytes) {
size_t k = count_free_bits_back(mb->free, mb->n_bytes / ALIGN) * ALIGN;
mb->n_bytes -= k;
mb->size += k;
}
if ((size_t)(mem - mb->mem) == mb->n_bytes + mb->size) {
mb->size += count_free_bits_after(mb->free,
(mb->n_bytes + mb->size) / ALIGN,
sizeof(mb->mem) / ALIGN) * ALIGN;
}
mb->n_productive_bytes -= size;
if (mb->n_used_chunks == 0) {
assert(mb->n_productive_bytes == 0);
assert(mb->n_used_bytes == 0);
mb->n_bytes = 0;
mb->size = sizeof(mb->mem);
mb->n_used_bytes = 0;
mb->n_productive_bytes = 0;
}
MDEBUG2_ONLY( memset(mem, 0xAA, size); )
#ifdef MDEBUG2
assert((unsigned char*)stmem >= mb->mem && (unsigned char*)stmem < mb->mem + sizeof(mb->mem));
assert(*stmem % ALIGN == 0);
assert(*stmem == size);
#endif
assert(valid_memblock(mb));
}
void block_free(void *vmem, size_t size) {
memblock **where;
MDEBUG1_ONLY(static int free_count = 0;)
if (vmem == NULL) return;
MDEBUG1_ONLY(first_malloc = 1;)
where = find_memblock(vmem);
assert(where);
free_in_memblock(*where, vmem, size);
if ((*where)->n_used_chunks == 0 && *where != base) {
memblock *mb = *where;
MDEBUG1_ONLY( print_memblock_summary(); )
*where = (*where)->next;
free(mb);
MDEBUG1_ONLY( fprintf(stderr, "Freed memblock\n"); )
}
MDEBUG1_ONLY( free_count++; free_count %= 10000; )
MDEBUG1_ONLY( if (!free_count) print_memblock_summary(); )
}
void *block_realloc(void *vmem, size_t oldsize, size_t newsize) {
void *vnewmem;
if (vmem == NULL && newsize == 0) abort();
if (vmem == NULL) return block_malloc(newsize);
if (newsize == 0) {
block_free(vmem, oldsize);
return NULL;
}
vnewmem = block_malloc(newsize);
if (vnewmem) {
memcpy(vnewmem, vmem, (oldsize < newsize ? oldsize : newsize));
block_free(vmem, oldsize);
}
return vnewmem;
}
char *block_strdup(char *from) {
char *result;
if (!from) return NULL;
result = block_malloc(strlen(from) + 1);
strcpy(result, from);
return result;
}

@ -0,0 +1,47 @@
#ifndef MEMORY_H
#define MEMORY_H
#if 1
void *block_malloc(size_t size);
void *block_malloc2(size_t size, int pool);
void block_free(void *vmem, size_t size);
#if defined(MDEBUG)
#define MDEBUG1
#endif
#define MDEBUG1_ONLY(x)
#define MDEBUG2_ONLY(x)
#define MDEBUG3_ONLY(x)
#ifdef MDEBUG3
#define MDEBUG1
#define MDEBUG2
#undef MDEBUG3_ONLY
#define MDEBUG3_ONLY(x) x
#endif
#ifdef MDEBUG2
#define MDEBUG1
#undef MDEBUG2_ONLY
#define MDEBUG2_ONLY(x) x
#endif
#ifdef MDEBUG1
#undef MDEBUG1_ONLY
#define MDEBUG1_ONLY(x) x
#endif
MDEBUG1_ONLY( void print_memblock_summary(void); )
#else
#define block_malloc(x) malloc(x)
#define block_free(x, s) free(x)
static void print_memblock_summary(void) {}
#endif
#endif /* MEMORY_H */

@ -0,0 +1,20 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define MIN(x,y) ((x) < (y) ? (x) : (y))
#define M 16
void *block_malloc(size_t size) { return malloc(size); }
void block_free(void *vmem) { free(vmem); }
void *block_realloc(void *vmem, size_t newsize) { return realloc(vmem, newsize); }
char *block_strdup(char *from) {
char *d;
if (!from) return 0;
d = block_malloc(strlen(from+1));
if (d) strcpy(d, from);
return d;
}
void print_memblock_summary(void) { }

@ -0,0 +1,209 @@
#include <stdio.h>
#include <stdlib.h>
#include "memory.h"
#include "templates.h"
#include "freelist.h"
typedef struct chunk chunk;
struct chunk {
chunk *next; /* only used when in free_lists */
};
#define GRAN (sizeof (struct chunk))
#define ALLOC_SIZE (1 << 20)
#define MAX_CHUNK_SIZE 256
#define NUM_BLOCK_TYPES (MAX_CHUNK_SIZE / GRAN)
#ifdef MDEBUG1
#define MAX_POOLS 100
#else
#define MAX_POOLS 1
#endif
#ifdef MDEBUG1
static void freesize(void *p, size_t s) { (void)s; free(p); }
static void die(char *blah) { perror(blah); abort(); }
LIST(alloclist, chunk *);
LIST_IMPL(alloclist, chunk *, KEEP(chunk *), malloc, freesize);
void print_memblock_summary2(int size);
#endif
struct chunkpool {
chunk *ch;
MDEBUG1_ONLY( int pool_id; )
MDEBUG1_ONLY( alloclist *all; )
};
static struct chunkpool free_lists[NUM_BLOCK_TYPES][MAX_POOLS];
#ifdef MDEBUG1
static int total[NUM_BLOCK_TYPES][MAX_POOLS];
static int used[NUM_BLOCK_TYPES][MAX_POOLS];
static int allocs[NUM_BLOCK_TYPES][MAX_POOLS];
static int total_mallocs = 0;
static int total_alloc = 0;
#endif
void *block_malloc(size_t size) {
return block_malloc2(size, -1);
}
void *block_malloc2(size_t size, int pool_id) {
chunk **fl = NULL;
void *result;
int granmult;
int pool = 0;
if (size > MAX_CHUNK_SIZE || size % GRAN != 0) {
MDEBUG1_ONLY( total_mallocs++; )
return malloc(size);
}
granmult = size / GRAN;
#ifdef MDEBUG1
for (pool = 0; pool + 1 < MAX_POOLS; pool++) {
if (free_lists[granmult - 1][pool].pool_id == 0) {
free_lists[granmult - 1][pool].pool_id = pool_id;
}
if (free_lists[granmult - 1][pool].pool_id == pool_id) {
break;
}
}
#endif
fl = &free_lists[granmult - 1][pool].ch;
if (*fl == NULL)
{
chunk *new_block = malloc(ALLOC_SIZE);
chunk *p;
MDEBUG1_ONLY( int old_size = total[granmult-1][pool]; )
if (!new_block) return NULL;
MDEBUG1_ONLY( insert_alloclist(&free_lists[granmult - 1][pool].all, new_block); )
for (p = new_block; (char*)(p + granmult) <= ((char*)new_block) + ALLOC_SIZE; p += granmult) {
/* each iteration adds a new chunk to the list */
MDEBUG1_ONLY( total[granmult-1][pool]++; )
*fl = p;
fl = &p->next;
}
*fl = NULL;
fl = &free_lists[granmult - 1][pool].ch;
MDEBUG1_ONLY( assert((total[granmult-1][pool]-old_size)*size <= ALLOC_SIZE); )
MDEBUG1_ONLY( assert(total[granmult-1][pool]*(int)size - old_size > ALLOC_SIZE - (int) size); )
#ifdef MDEBUG1
// print some info
MDEBUG2_ONLY(
fprintf(stderr, "ALLOC: for size %2ld (%d:line %d), %4ld B of %4ld B used, total alloced is %8ld KiB\n", (long int) size, pool, pool_id, (long int) used[granmult-1][pool] * size, (long int) total[granmult-1][pool] * size, (long int) total_alloc / 1024);
)
assert( used[granmult-1][pool] <= (signed long) total[granmult-1][pool] );
total_alloc += ALLOC_SIZE;
#endif
}
#ifdef MDEBUG1
{
static unsigned long cnt = 0, cnt2 = 0;
if (++cnt % (1L << 20) == 0) {
if (++cnt2 % 10 == 0) {
print_memblock_summary2(0);
} else {
print_memblock_summary();
}
}
}
#endif
MDEBUG1_ONLY( used[granmult-1][pool]++; )
MDEBUG1_ONLY( allocs[granmult-1][pool]++; )
result = *fl;
*fl = (*fl)->next;
*(int *)result = ~0;
return result;
}
#ifdef MDEBUG1
static int find_closest(void *vmem, size_t size, chunk **ch, int *p) {
int pool;
*ch = NULL;
for (pool = 0; pool < MAX_POOLS; pool++) {
alloclist *a;
if (!free_lists[size/GRAN - 1][pool].all) break;
for (a = free_lists[size/GRAN - 1][pool].all; a; a = a->next) {
if (*ch < a->value && a->value <= (chunk*)vmem) {
*ch = a->value;
*p = pool;
}
}
}
assert((char*)*ch <= (char*)vmem);
if ((char*)vmem - (char*)*ch < ALLOC_SIZE) {
return 1;
} else {
return 0;
}
}
#endif
void block_free(void *vmem, size_t size) {
int pool = 0;
if (size > MAX_CHUNK_SIZE || size % GRAN != 0) {
free(vmem);
return;
}
#if MDEBUG1
{ chunk *closest;
if (!find_closest(vmem, size, &closest, &pool)) {
fprintf(stderr, "AIEE: %p + %lx < %p\n", closest, (unsigned long) ALLOC_SIZE, vmem);
assert(0);
}
}
#endif
MDEBUG1_ONLY( used[size/GRAN-1][pool]--; )
{
chunk **fl, *x;
fl = &free_lists[size/GRAN - 1][pool].ch;
x = (chunk *) vmem;
x->next = *fl;
*fl = x;
}
}
#ifdef MDEBUG1
void print_memblock_summary(void) {
print_memblock_summary2(5*1024*1024);
}
void print_memblock_summary2(int size) {
unsigned int i, j;
fprintf(stderr, "MEMORY SUMMARY:\n");
for (i = 0; i < NUM_BLOCK_TYPES; i++) {
for (j = 0; j < MAX_POOLS; j++) {
if (total[i][j] * GRAN * (i+1) < size) continue;
if (free_lists[i][j].all != NULL) {
fprintf(stderr, " pool %dB/%d:%d; %d used %d allocated (%0.1f%% of %d MiB, %0.2f%% current)\n",
(i+1) * GRAN, j, free_lists[i][j].pool_id,
used[i][j], total[i][j],
(100.0 * used[i][j]) / total[i][j],
total[i][j] * GRAN * (i+1) / 1024 / 1024,
(100.0 * used[i][j]) / allocs[i][j]);
}
}
}
}
#endif

@ -0,0 +1,277 @@
#ifndef TEMPLATE_H
#define TEMPLATE_H
#include <stdio.h>
#include <string.h>
#include "memory.h"
#undef assert
/* gcc-3.0 sucks */
#if defined(DEBUG) && defined(NDEBUG)
#error "Can't debug and notdebug both"
#endif
#if !defined(DEBUG) && !defined(NDEBUG)
#define NDEBUG
#endif
#ifdef NDEBUG
# define DEBUG_ONLY( stmt )
# define assert(x) (void)0
#else
# define DEBUG_ONLY( stmt ) stmt
# define assert(x) ((x) ? 1 : _myassertbug(__LINE__, __FILE__, #x))
extern int _myassertbug(int line, char *file, char *err);
#endif
#ifdef __STRICT_ANSI__
#define inline __inline__
#endif
static inline unsigned long strhash(const char *x, unsigned char pow) {
unsigned long i = 0;
while (*x) {
i = (i * 39 + *x) % (1UL << pow);
x++;
}
return i;
}
#define KEEP(TYPE) ((void(*)(TYPE))NULL)
#define LIST(NAME,TYPE) \
typedef struct NAME NAME; \
struct NAME { TYPE value; struct NAME *next; }; \
void insert_##NAME(NAME **where, TYPE v); \
void insert_l_##NAME(NAME **where, TYPE v, int line); \
TYPE remove_##NAME(NAME **where); \
void delete_##NAME(NAME **where); \
void free_##NAME(NAME *l)
#define LIST_IMPL_2(NAME,TYPE,FREE,LFREE) \
TYPE remove_##NAME(NAME **where) { \
NAME *next; \
TYPE res; \
assert(*where != NULL); \
next = (*where)->next; \
res = (*where)->value; \
LFREE(*where, sizeof(NAME)); \
*where = next; \
return res; \
} \
void delete_##NAME(NAME **where) { \
NAME *next; \
assert(*where != NULL); \
next = (*where)->next; \
if (FREE != NULL) (FREE)((*where)->value); \
LFREE(*where, sizeof(NAME)); \
*where = next; \
} \
void free_##NAME(NAME *l) { \
NAME *n; \
while (l != NULL) { \
n = l->next; \
if (FREE != NULL) (FREE)(l->value); \
LFREE(l, sizeof(NAME)); \
l = n; \
} \
}
#define LIST_IMPL(NAME,TYPE,FREE,LMALLOC,LFREE) \
void insert_##NAME(NAME **where, TYPE v) { \
NAME *n = *where; \
*where = LMALLOC(sizeof(NAME)); \
if (*where == NULL) \
die("insert_" #NAME " malloc:"); \
(*where)->value = v; \
(*where)->next = n; \
} \
LIST_IMPL_2(NAME,TYPE,FREE,LFREE)
#define LIST_IMPLX(NAME,TYPE,FREE) \
void insert_l_##NAME(NAME **where, TYPE v, int line) { \
NAME *n = *where; \
*where = block_malloc2(sizeof(NAME), line); \
if (*where == NULL) \
die("insert_" #NAME " malloc:"); \
(*where)->value = v; \
(*where)->next = n; \
} \
LIST_IMPL_2(NAME,TYPE,FREE,block_free)
#define HASH(TYPE, KEY, VALUE) \
typedef struct TYPE TYPE; \
typedef struct TYPE##_iter TYPE##_iter; \
struct TYPE##_iter { \
unsigned long i; TYPE *h; KEY k; VALUE v; \
}; \
TYPE *new_##TYPE(void); \
void free_##TYPE(TYPE *h); \
TYPE##_iter first_##TYPE(TYPE *h); \
TYPE##_iter next_##TYPE(TYPE##_iter i); \
int done_##TYPE(TYPE##_iter i); \
\
void iterate_##TYPE(TYPE *h, void (*itf)(TYPE*,VALUE,void*), \
void *data); \
VALUE lookup_##TYPE(TYPE *h, KEY k); \
void add_##TYPE(TYPE *h, KEY k, VALUE v); \
VALUE replace_##TYPE(TYPE *h, KEY k, VALUE v); \
VALUE remove_##TYPE(TYPE *h, KEY k)
#define HASH_MAGIC (0x22DEAD22)
#define HASH_IMPL(TYPE, KEY, VALUE, POW2, HASH, CMP, FREEK, FREEV) \
struct TYPE { \
unsigned long magic; \
unsigned long size; \
unsigned long n_used; \
unsigned long n_collisions; \
struct { KEY key; VALUE value; } *hash; \
}; \
TYPE *new_##TYPE(void) { \
size_t i; \
TYPE *h = malloc(sizeof(TYPE)); \
if (h == NULL) die("new_" #TYPE " malloc:"); \
\
h->magic = HASH_MAGIC; \
h->size = (1 << POW2); \
h->n_used = 0; \
h->n_collisions = 0; \
h->hash = malloc(sizeof(*h->hash) * h->size ); \
if (h == NULL) die("new_" #TYPE " hash malloc:"); \
\
for (i = 0; i < h->size; i++) { \
h->hash[i].key = NULL; \
h->hash[i].value = NULL; \
} \
\
return h; \
} \
\
void free_##TYPE(TYPE *h) { \
size_t i; \
if (h == NULL) return; \
assert(h->magic == HASH_MAGIC); \
/* printf("Freeing: size: %lu used: %lu coll: %lu\n", */ \
/* h->size, h->n_used, h->n_collisions); */ \
h->magic = ~HASH_MAGIC; \
for (i = 0; i < h->size; i++) { \
if (FREEK && h->hash[i].key) \
(FREEK)(h->hash[i].key); \
if (FREEV && h->hash[i].value) \
(FREEV)(h->hash[i].value); \
} \
free(h->hash); \
free(h); \
} \
\
void iterate_##TYPE(TYPE *h, void (*itf)(TYPE*,VALUE,void*), \
void *data) \
{ \
TYPE##_iter x; \
for (x = first_##TYPE(h); \
!done_##TYPE(x); \
x = next_##TYPE(x)) \
{ \
itf(h, x.v, data); \
} \
} \
\
TYPE##_iter first_##TYPE(TYPE *h) { \
TYPE##_iter i; \
i.i = 0; \
i.h = h; \
return next_##TYPE(i); \
} \
\
TYPE##_iter next_##TYPE(TYPE##_iter i) { \
assert(i.h->magic == HASH_MAGIC); \
while(i.i < i.h->size) { \
if (i.h->hash[i.i].value != NULL) { \
i.k = i.h->hash[i.i].key; \
i.v = i.h->hash[i.i].value; \
i.i++; \
return i; \
} \
i.i++; \
} \
i.h = NULL; \
return i; \
} \
\
int done_##TYPE(TYPE##_iter i) { \
assert(i.h == NULL || i.h->magic == HASH_MAGIC); \
assert(i.h == NULL || (i.k != NULL && i.v != NULL)); \
assert(i.h == NULL || (0 < i.i && i.i <= i.h->size)); \
return i.h == NULL; \
} \
\
VALUE lookup_##TYPE(TYPE *h, KEY k) { \
int i = HASH(k, POW2); \
assert(h->magic == HASH_MAGIC); \
assert(h->n_used < h->size); /* ensure termination */ \
while(h->hash[i].key) { \
if ((CMP)(h->hash[i].key, k) == 0) { \
if (h->hash[i].value != NULL) { \
return h->hash[i].value; \
} \
} \
i = (i + 1) % (1 << POW2); \
} \
return NULL; \
} \
\
void add_##TYPE(TYPE *h, KEY k, VALUE v) { \
int i = HASH(k, POW2); \
assert(h->magic == HASH_MAGIC); \
assert(h->n_used < h->size); /* ensure termination */ \
assert(v != NULL); \
while(h->hash[i].value) { \
assert((CMP)(h->hash[i].key, k) != 0); \
i = (i + 1) % (1 << POW2); \
h->n_collisions++; \
} \
if (FREEK != NULL && h->hash[i].key) \
FREEK(h->hash[i].key); \
h->n_used++; \
h->hash[i].key = k; \
h->hash[i].value = v; \
} \
\
VALUE replace_##TYPE(TYPE *h, KEY k, VALUE v) { \
VALUE tmp; \
int i = HASH(k,POW2); \
assert(h->magic == HASH_MAGIC); \
assert(v != NULL); \
while(h->hash[i].key) { \
if ((CMP)(h->hash[i].key, k) == 0) break; \
i = (i + 1) % (1 << POW2); \
} \
assert(h->hash[i].value != NULL); \
tmp = h->hash[i].value; \
h->hash[i].key = k; \
h->hash[i].value = v; \
return tmp; \
} \
\
VALUE remove_##TYPE(TYPE *h, KEY k) { \
VALUE tmp; \
int i = HASH(k, POW2); \
assert(h->magic == HASH_MAGIC); \
while(h->hash[i].key) { \
if ((CMP)(h->hash[i].key, k) == 0) break; \
i = (i + 1) % (1 << POW2); \
} \
tmp = h->hash[i].value; \
h->hash[i].value = NULL; \
if (tmp != NULL) h->n_used--; \
return tmp; \
}
#endif

@ -0,0 +1,13 @@
remove_source(name) source exists
remove_sourcetbl
remove the binaries?? but how?
upgrade_source(dpkg_source) source may exist
remove_source(src->name)
add the new source to the table thing
foreach arch, binary: add binary to arch pkgs
upgrade_architecture(dpkg_source, arch) source exists, binary may
find source
foreach binary in <arch>: remove it
foreach binary in new <arch>: add it
(remove_architecture, upgrade_source_only; could also be used, theoretically)
Loading…
Cancel
Save