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…
Reference in new issue