parent
7051d5b0e9
commit
ea4e4493a2
@ -1,33 +0,0 @@
|
||||
|
||||
CC = gcc
|
||||
CXX = g++
|
||||
CFLAGS = -Wall -W -O2 -DNDEBUG -DMDEBUG0 -g -p -fPIC
|
||||
CXXFLAGS += -fPIC
|
||||
|
||||
all : britneymodule.so # checklib aptvercmp freelist 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
|
@ -1,32 +0,0 @@
|
||||
|
||||
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
|
@ -1,11 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
|
@ -1,299 +0,0 @@
|
||||
#include <python2.7/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 void dpkgpackages_dealloc(dpkgpackages *self) {
|
||||
if (self->freeme == FREE) free_packages(self->pkgs);
|
||||
Py_XDECREF(self->ref);
|
||||
self->pkgs = NULL;
|
||||
self->ref = NULL;
|
||||
PyObject_DEL(self);
|
||||
}
|
||||
|
||||
|
||||
static PyObject *dpkgpackages_isinstallable(dpkgpackages *self, PyObject *args)
|
||||
{
|
||||
char *pkgname;
|
||||
int r;
|
||||
if (!PyArg_ParseTuple(args, "s", &pkgname)) return NULL;
|
||||
if ((r=checkinstallable2(self->pkgs, pkgname))) {
|
||||
return Py_BuildValue("i", r);
|
||||
} else {
|
||||
return Py_BuildValue("");
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *dpkgpackages_remove_binary(dpkgpackages *self, PyObject *args) {
|
||||
char *pkg_name;
|
||||
|
||||
(void)self; /* unused */
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s", &pkg_name))
|
||||
return NULL;
|
||||
|
||||
dpkg_collected_package *cpkg = lookup_packagetbl(self->pkgs->packages, pkg_name);
|
||||
if (cpkg == NULL) return Py_BuildValue("i", 0);
|
||||
|
||||
remove_package(self->pkgs, cpkg);
|
||||
return Py_BuildValue("i", 1);
|
||||
}
|
||||
|
||||
static PyObject *dpkgpackages_add_binary(dpkgpackages *self, PyObject *args) {
|
||||
char *pkg_name;
|
||||
PyObject *value, *pyString;
|
||||
|
||||
(void)self; /* unused */
|
||||
|
||||
if (!PyArg_ParseTuple(args, "sO", &pkg_name, &value) ||
|
||||
!PyList_Check(value)) return NULL;
|
||||
|
||||
/* initialize the new package */
|
||||
dpkg_package *pkg;
|
||||
pkg = block_malloc(sizeof(dpkg_package));
|
||||
pkg->package = strdup(pkg_name);
|
||||
pkg->priority = 0;
|
||||
pkg->details = NULL;
|
||||
pkg->depends[1] = NULL;
|
||||
pkg->depends[2] = NULL;
|
||||
pkg->depends[3] = NULL;
|
||||
|
||||
pyString = PyList_GetItem(value, 0);
|
||||
if (pyString == NULL) return NULL;
|
||||
pkg->version = PyString_AsString(pyString);
|
||||
|
||||
pyString = PyList_GetItem(value, 2);
|
||||
if (pyString == NULL) return NULL;
|
||||
pkg->source = PyString_AsString(pyString);
|
||||
|
||||
pyString = PyList_GetItem(value, 3);
|
||||
if (pyString == NULL) return NULL;
|
||||
pkg->source_ver = PyString_AsString(pyString);
|
||||
|
||||
pyString = PyList_GetItem(value, 4);
|
||||
if (pyString == NULL) return NULL;
|
||||
pkg->arch_all = (pyString == Py_None || strcmp(PyString_AsString(pyString), "all") ? 0 : 1);
|
||||
|
||||
pyString = PyList_GetItem(value, 5);
|
||||
if (pyString == NULL) return NULL;
|
||||
if (pyString != Py_None) {
|
||||
pkg->multiarch = PyString_AsString(pyString);
|
||||
} else pkg->multiarch = NULL;
|
||||
|
||||
pyString = PyList_GetItem(value, 6);
|
||||
if (pyString == NULL) return NULL;
|
||||
if (pyString != Py_None) {
|
||||
pkg->depends[0] = read_dep_andor(PyString_AsString(pyString));
|
||||
} else pkg->depends[0] = NULL;
|
||||
|
||||
pyString = PyList_GetItem(value, 7);
|
||||
if (pyString == NULL) return NULL;
|
||||
if (pyString != Py_None) {
|
||||
pkg->conflicts = read_dep_and(PyString_AsString(pyString));
|
||||
} else pkg->conflicts = NULL;
|
||||
|
||||
pyString = PyList_GetItem(value, 8);
|
||||
if (pyString == NULL) return NULL;
|
||||
if (pyString != Py_None) {
|
||||
pkg->provides = read_packagenames(PyString_AsString(pyString));
|
||||
} else pkg->provides = NULL;
|
||||
|
||||
add_package(self->pkgs, pkg);
|
||||
|
||||
return Py_BuildValue("i", 1);
|
||||
}
|
||||
|
||||
static PyObject *dpkgpackages_getattr(dpkgpackages *self, char *name) {
|
||||
static struct PyMethodDef dpkgsources_methods[] = {
|
||||
{ "is_installable", (binaryfunc) dpkgpackages_isinstallable,
|
||||
METH_VARARGS, NULL },
|
||||
{ "remove_binary", (binaryfunc) dpkgpackages_remove_binary,
|
||||
METH_VARARGS, NULL },
|
||||
{ "add_binary", (binaryfunc) dpkgpackages_add_binary,
|
||||
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.buildSystem() -- build a fake package system, with the only purpose of
|
||||
* calling the is_installable method on the packages.
|
||||
******************************************************/
|
||||
|
||||
static PyObject *build_system(PyObject *self, PyObject *args) {
|
||||
Py_ssize_t pos = 0;
|
||||
char *arch;
|
||||
PyObject *pkgs, *key, *value, *pyString;
|
||||
|
||||
(void)self; /* unused */
|
||||
|
||||
if (!PyArg_ParseTuple(args, "sO", &arch, &pkgs) ||
|
||||
!PyDict_Check(pkgs)) return NULL;
|
||||
|
||||
/* Fields and positions for the binary package:
|
||||
# VERSION = 0
|
||||
# SECTION = 1
|
||||
# SOURCE = 2
|
||||
# SOURCEVER = 3
|
||||
# ARCHITECTURE = 4
|
||||
# MULTIARCH = 5
|
||||
# DEPENDS = 6
|
||||
# CONFLICTS = 7
|
||||
# PROVIDES = 8
|
||||
# RDEPENDS = 9
|
||||
# RCONFLICTS = 10
|
||||
*/
|
||||
|
||||
dpkg_packages *dpkg_pkgs = new_packages(arch);
|
||||
|
||||
/* loop on the dictionary keys to build the packages */
|
||||
while (PyDict_Next(pkgs, &pos, &key, &value)) {
|
||||
|
||||
/* initialize the new package */
|
||||
dpkg_package *pkg;
|
||||
pkg = block_malloc(sizeof(dpkg_package));
|
||||
pkg->package = strdup(PyString_AsString(key));
|
||||
pkg->priority = 0;
|
||||
pkg->details = NULL;
|
||||
pkg->depends[1] = NULL;
|
||||
pkg->depends[2] = NULL;
|
||||
pkg->depends[3] = NULL;
|
||||
|
||||
pyString = PyList_GetItem(value, 0);
|
||||
if (pyString == NULL) continue;
|
||||
pkg->version = PyString_AsString(pyString);
|
||||
|
||||
pyString = PyList_GetItem(value, 2);
|
||||
if (pyString == NULL) continue;
|
||||
pkg->source = PyString_AsString(pyString);
|
||||
|
||||
pyString = PyList_GetItem(value, 3);
|
||||
if (pyString == NULL) continue;
|
||||
pkg->source_ver = PyString_AsString(pyString);
|
||||
|
||||
pyString = PyList_GetItem(value, 4);
|
||||
if (pyString == NULL) continue;
|
||||
pkg->arch_all = (pyString == Py_None || strcmp(PyString_AsString(pyString), "all") ? 0 : 1);
|
||||
|
||||
pyString = PyList_GetItem(value, 5);
|
||||
if (pyString == NULL) continue;
|
||||
if (pyString != Py_None) {
|
||||
pkg->multiarch = PyString_AsString(pyString);
|
||||
} else pkg->multiarch = NULL;
|
||||
|
||||
pyString = PyList_GetItem(value, 6);
|
||||
if (pyString == NULL) continue;
|
||||
if (pyString != Py_None) {
|
||||
pkg->depends[0] = read_dep_andor(PyString_AsString(pyString));
|
||||
} else pkg->depends[0] = NULL;
|
||||
|
||||
pyString = PyList_GetItem(value, 7);
|
||||
if (pyString == NULL) continue;
|
||||
if (pyString != Py_None) {
|
||||
pkg->conflicts = read_dep_and(PyString_AsString(pyString));
|
||||
} else pkg->conflicts = NULL;
|
||||
|
||||
pyString = PyList_GetItem(value, 8);
|
||||
if (pyString == NULL) continue;
|
||||
if (pyString != Py_None) {
|
||||
pkg->provides = read_packagenames(PyString_AsString(pyString));
|
||||
} else pkg->provides = NULL;
|
||||
|
||||
add_package(dpkg_pkgs, pkg);
|
||||
}
|
||||
|
||||
dpkgpackages *res;
|
||||
res = PyObject_NEW(dpkgpackages, &Packages_Type);
|
||||
if (res == NULL) return NULL;
|
||||
|
||||
res->pkgs = dpkg_pkgs;
|
||||
res->freeme = FREE;
|
||||
res->ref = NULL;
|
||||
|
||||
return (PyObject *)res;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* module initialisation
|
||||
***********************/
|
||||
|
||||
static PyMethodDef britneymethods[] = {
|
||||
{ "buildSystem", build_system, METH_VARARGS, NULL },
|
||||
|
||||
{ NULL, NULL, 0, NULL }
|
||||
};
|
||||
|
||||
void initbritney(void) {
|
||||
Py_InitModule("britney", britneymethods);
|
||||
}
|
||||
|
@ -1,185 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
|
||||
#include <apt-pkg/debversion.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
#include "dpkg.h"
|
||||
|
||||
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
|
@ -1,966 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "dpkg.h"
|
||||
#include "memory.h"
|
||||
|
||||
// enlarge this if britney has issues parsing packages
|
||||
// (e.g. very slow installability checks)
|
||||
#define SIZEOFHASHMAP 16
|
||||
|
||||
/* #define DIAGNOSE 1 */
|
||||
|
||||
#define insert_packagenamelist(x,y) insert_l_packagenamelist(x,y,__LINE__)
|
||||
|
||||
static void free_dependency(dependency *dep);
|
||||
static void free_collected_package(dpkg_collected_package *pkg);
|
||||
static collpackagelist **get_matching_low(collpackagelist **addto,
|
||||
dpkg_packages *pkgs, dependency *dep, int line);
|
||||
static collpackagelist *get_matching(dpkg_packages *pkgs, deplist *depopts, int line);
|
||||
|
||||
static deplist *read_deplist(char **buf, char sep, char end);
|
||||
static dependency *read_dependency(char **buf, char *end);
|
||||
static void add_virtualpackage(virtualpkgtbl *vpkgs, char *package,
|
||||
char *version, char *multiarch,
|
||||
dpkg_collected_package *cpkg);
|
||||
static void remove_virtualpackage(virtualpkgtbl *vpkgs, char *pkgname,
|
||||
dpkg_collected_package *cpkg);
|
||||
static char *read_packagename(char **buf, char *end);
|
||||
static char *read_until_char(char **buf, char *end);
|
||||
static int checkinstallable(dpkg_packages *pkgs, collpackagelist *instoneof);
|
||||
|
||||
// implemented in dpkg-lib.c
|
||||
int cmpversions(char *left, int op, char *right);
|
||||
|
||||
|
||||
#define block_malloc(s) block_malloc2(s, __LINE__)
|
||||
|
||||
static int dependency_counts[] = { 1, 1, 0, 0 };
|
||||
|
||||
#define SMB_SIZE (1<<22)
|
||||
struct stringmemblock {
|
||||
struct stringmemblock *next;
|
||||
size_t last;
|
||||
char mem[SMB_SIZE];
|
||||
};
|
||||
static struct stringmemblock *stringmemory = NULL;
|
||||
static int stringmemorycount = 0;
|
||||
static const unsigned long stringmemblocksizekib = (unsigned long) sizeof(struct stringmemblock) / 1024;
|
||||
|
||||
static char *my_strdup(char *foo) {
|
||||
struct stringmemblock *which;
|
||||
size_t len;
|
||||
|
||||
if (!foo) return NULL;
|
||||
|
||||
len = strlen(foo) + 1;
|
||||
|
||||
if (len > SMB_SIZE) return strdup(foo);
|
||||
|
||||
for (which = stringmemory; which; which = which->next) {
|
||||
if (SMB_SIZE - which->last > len + 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!which) {
|
||||
which = malloc(sizeof(struct stringmemblock));
|
||||
if (!which) return NULL;
|
||||
MDEBUG1_ONLY(fprintf(stderr,
|
||||
"ALLOC: string memblock %d (%lu KiB, %lu KiB total)\n",
|
||||
stringmemorycount, stringmemblocksizekib,
|
||||
(stringmemorycount+1) * stringmemblocksizekib));
|
||||
memset(which->mem, 0, SMB_SIZE);
|
||||
which->last = 0;
|
||||
which->next = stringmemory;
|
||||
stringmemory = which;
|
||||
stringmemorycount++;
|
||||
}
|
||||
strcpy(&which->mem[which->last], foo);
|
||||
foo = &which->mem[which->last];
|
||||
which->last += len;
|
||||
return foo;
|
||||
}
|
||||
|
||||
/* DIE **/
|
||||
|
||||
static void die(char *orig_msg) {
|
||||
char *msg = my_strdup(orig_msg);
|
||||
if (*msg && msg[strlen(msg)-1] == ':') {
|
||||
msg[strlen(msg)-1] = '\0';
|
||||
perror(msg);
|
||||
} else {
|
||||
printf("%s\n", msg);
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* Basic Package Operations
|
||||
*/
|
||||
|
||||
static dpkg_collected_package *new_collected_package(dpkg_package *pkg) {
|
||||
dpkg_collected_package *result;
|
||||
|
||||
result = block_malloc(sizeof(dpkg_collected_package));
|
||||
if (result == NULL) die("new_collected_package alloc:");
|
||||
|
||||
result->pkg = pkg;
|
||||
|
||||
result->installed = 0;
|
||||
result->conflicted = 0;
|
||||
|
||||
result->installable = UNKNOWN;
|
||||
result->mayaffect = NULL;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void free_collected_package(dpkg_collected_package *cpkg) {
|
||||
if (cpkg == NULL) return;
|
||||
cpkg->pkg = NULL;
|
||||
free_packagenamelist(cpkg->mayaffect);
|
||||
cpkg->mayaffect = NULL;
|
||||
block_free(cpkg, sizeof(dpkg_collected_package));
|
||||
}
|
||||
|
||||
LIST_IMPL(deplist, dependency*, free_dependency, block_malloc, block_free);
|
||||
LIST_IMPL(deplistlist, deplist*, free_deplist, block_malloc, block_free);
|
||||
|
||||
LIST_IMPLX(packagenamelist, char*, KEEP(char*));
|
||||
|
||||
LIST_IMPL(ownedpackagenamelist, char*, KEEP(char*), block_malloc, block_free);
|
||||
/* ownedpackagenamelist stores the packagename in the string store */
|
||||
|
||||
static int packagecmp(dpkg_package *l, dpkg_package *r) {
|
||||
if (l->priority < r->priority) return -1;
|
||||
if (l->priority > r->priority) return +1;
|
||||
return strcmp(l->package, r->package);
|
||||
}
|
||||
|
||||
/* container for existing pkgs */
|
||||
LIST_IMPL(packagelist, dpkg_package *, KEEP(dpkg_package *), block_malloc, block_free);
|
||||
|
||||
LIST_IMPLX(collpackagelist, dpkg_collected_package *,
|
||||
KEEP(dpkg_collected_package *))
|
||||
#define insert_collpackagelist(x,y) insert_l_collpackagelist(x,y,__LINE__)
|
||||
|
||||
/*************************************************************************
|
||||
* Operations on distributions (collections of packages)
|
||||
*/
|
||||
|
||||
dpkg_packages *new_packages(char *arch) {
|
||||
dpkg_packages *result;
|
||||
|
||||
result = block_malloc(sizeof(dpkg_packages));
|
||||
if (result == NULL) die("new_packages alloc:");
|
||||
|
||||
result->arch = my_strdup(arch);
|
||||
result->packages = new_packagetbl();
|
||||
result->virtualpkgs = new_virtualpkgtbl();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void add_package(dpkg_packages *pkgs, dpkg_package *pkg)
|
||||
{
|
||||
ownedpackagenamelist *v;
|
||||
dpkg_collected_package *cpkg;
|
||||
|
||||
if (lookup_packagetbl(pkgs->packages, pkg->package) != NULL)
|
||||
return;
|
||||
|
||||
cpkg = new_collected_package(pkg);
|
||||
|
||||
add_packagetbl(pkgs->packages, cpkg->pkg->package, cpkg);
|
||||
|
||||
add_virtualpackage(pkgs->virtualpkgs, cpkg->pkg->package,
|
||||
cpkg->pkg->version, cpkg->pkg->multiarch, cpkg);
|
||||
for (v = cpkg->pkg->provides; v != NULL; v = v->next) {
|
||||
add_virtualpackage(pkgs->virtualpkgs, v->value, NULL, NULL, cpkg);
|
||||
}
|
||||
}
|
||||
|
||||
void remove_package(dpkg_packages *pkgs, dpkg_collected_package *cpkg) {
|
||||
ownedpackagenamelist *v;
|
||||
packagenamelist *aff;
|
||||
dpkg_collected_package *p;
|
||||
|
||||
for (aff = cpkg->mayaffect; aff != NULL; aff = aff->next) {
|
||||
p = lookup_packagetbl(pkgs->packages, aff->value);
|
||||
if (p == NULL) continue;
|
||||
p->installable = UNKNOWN;
|
||||
}
|
||||
|
||||
p = remove_packagetbl(pkgs->packages, cpkg->pkg->package);
|
||||
if (p != cpkg) return;
|
||||
|
||||
remove_virtualpackage(pkgs->virtualpkgs, cpkg->pkg->package, cpkg);
|
||||
for (v = cpkg->pkg->provides; v != NULL; v = v->next) {
|
||||
remove_virtualpackage(pkgs->virtualpkgs, v->value, cpkg);
|
||||
}
|
||||
|
||||
free_collected_package(cpkg);
|
||||
}
|
||||
|
||||
void free_packages(dpkg_packages *pkgs) {
|
||||
if (pkgs == NULL) return;
|
||||
/* block_free(pkgs->arch); */
|
||||
free_packagetbl(pkgs->packages);
|
||||
free_virtualpkgtbl(pkgs->virtualpkgs);
|
||||
block_free(pkgs, sizeof(dpkg_packages));
|
||||
}
|
||||
|
||||
|
||||
HASH_IMPL(packagetbl, char *, dpkg_collected_package *, SIZEOFHASHMAP, strhash, strcmp,
|
||||
KEEP(char*),free_collected_package);
|
||||
HASH_IMPL(virtualpkgtbl, char *, virtualpkg *, SIZEOFHASHMAP, strhash, strcmp,
|
||||
KEEP(char*), free_virtualpkg);
|
||||
|
||||
/* dpkg_provision refers to memory allocated elsewhere */
|
||||
LIST_IMPL(virtualpkg, dpkg_provision, KEEP(dpkg_provision), block_malloc, block_free);
|
||||
|
||||
static void remove_virtualpackage(virtualpkgtbl *vpkgs, char *pkgname,
|
||||
dpkg_collected_package *cpkg)
|
||||
{
|
||||
virtualpkg *list;
|
||||
virtualpkg **where;
|
||||
list = lookup_virtualpkgtbl(vpkgs, pkgname);
|
||||
assert(list != NULL);
|
||||
|
||||
where = &list;
|
||||
while((*where)->value.pkg != cpkg) {
|
||||
where = &(*where)->next;
|
||||
assert(*where != NULL);
|
||||
}
|
||||
|
||||
delete_virtualpkg(where);
|
||||
|
||||
if (list == NULL) {
|
||||
remove_virtualpkgtbl(vpkgs, pkgname);
|
||||
} else {
|
||||
replace_virtualpkgtbl(vpkgs, pkgname, list);
|
||||
}
|
||||
}
|
||||
|
||||
static void add_virtualpackage(virtualpkgtbl *vpkgs, char *package,
|
||||
char *version, char *multiarch,
|
||||
dpkg_collected_package *cpkg)
|
||||
{
|
||||
dpkg_provision value;
|
||||
virtualpkg *list, **addto;
|
||||
int shouldreplace;
|
||||
|
||||
value.pkg = cpkg;
|
||||
value.version = version;
|
||||
value.multiarch = multiarch;
|
||||
|
||||
list = lookup_virtualpkgtbl(vpkgs, package);
|
||||
shouldreplace = (list != NULL);
|
||||
|
||||
addto = &list;
|
||||
while (*addto != NULL
|
||||
&& packagecmp(cpkg->pkg, (*addto)->value.pkg->pkg) >= 0)
|
||||
{
|
||||
addto = &(*addto)->next;
|
||||
}
|
||||
insert_virtualpkg(addto, value);
|
||||
|
||||
if (shouldreplace) {
|
||||
replace_virtualpkgtbl(vpkgs, package, list);
|
||||
/* old list is included in new list, so we don't need to free */
|
||||
} else {
|
||||
add_virtualpkgtbl(vpkgs, package, list);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* Parsing Helper Functions
|
||||
*/
|
||||
|
||||
ownedpackagenamelist *read_packagenames(char *buf) {
|
||||
ownedpackagenamelist *result = NULL;
|
||||
ownedpackagenamelist **addto = &result;
|
||||
|
||||
DEBUG_ONLY( char *strend = buf + strlen(buf); )
|
||||
|
||||
char *sub;
|
||||
|
||||
while ((sub = my_strdup(read_packagename(&buf, ",")))) {
|
||||
insert_ownedpackagenamelist(addto, sub);
|
||||
addto = &(*addto)->next;
|
||||
|
||||
while(isspace(*buf)) buf++;
|
||||
if (*buf == ',') {
|
||||
buf++;
|
||||
continue;
|
||||
}
|
||||
if (*buf == '\0') {
|
||||
break;
|
||||
}
|
||||
|
||||
die("read_packagenames no/bad seperator");
|
||||
}
|
||||
|
||||
DEBUG_ONLY( assert(buf <= strend); )
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static char *read_until_char(char **buf, char *end) {
|
||||
static char *result = NULL;
|
||||
char *start;
|
||||
DEBUG_ONLY( char *strend = *buf + strlen(*buf); )
|
||||
int n;
|
||||
|
||||
while(isspace(**buf)) (*buf)++;
|
||||
|
||||
start = *buf;
|
||||
while (**buf && !isspace(**buf) && strchr(end, **buf) == NULL) {
|
||||
(*buf)++;
|
||||
}
|
||||
|
||||
n = *buf - start;
|
||||
if (n == 0) return NULL;
|
||||
|
||||
result = realloc(result, n + 1);
|
||||
if (result == NULL) die("read_until_char alloc:");
|
||||
|
||||
strncpy(result, start, n);
|
||||
result[n] = '\0';
|
||||
|
||||
while(isspace(**buf)) (*buf)++;
|
||||
|
||||
DEBUG_ONLY( assert(*buf <= strend); )
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static char *read_packagename(char **buf, char *end) {
|
||||
return read_until_char(buf, end);
|
||||
}
|
||||
|
||||
deplist *read_dep_and(char *buf) {
|
||||
return read_deplist(&buf, ',', '\0');
|
||||
}
|
||||
|
||||
static deplist *read_deplist(char **buf, char sep, char end) {
|
||||
deplist *result = NULL;
|
||||
deplist **addto = &result;
|
||||
|
||||
char separs[3] = { sep, end, '\0' };
|
||||
|
||||
DEBUG_ONLY( char *strend = *buf + strlen(*buf); )
|
||||
|
||||
dependency *sub;
|
||||
|
||||
while ((sub = read_dependency(buf, separs))) {
|
||||
insert_deplist(addto, sub);
|
||||
addto = &(*addto)->next;
|
||||
|
||||
while(isspace(**buf)) (*buf)++;
|
||||
if (**buf == sep) {
|
||||
(*buf)++;
|
||||
continue;
|
||||
}
|
||||
if (**buf == '\0' || **buf == end) {
|
||||
break;
|
||||
}
|
||||
|
||||
die("read_deplist no/bad seperator");
|
||||
}
|
||||
|
||||
DEBUG_ONLY( assert(*buf <= strend); )
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
deplistlist *read_dep_andor(char *buf) {
|
||||
deplistlist *result = NULL;
|
||||
deplistlist **addto = &result;
|
||||
|
||||
deplist *sub;
|
||||
|
||||
DEBUG_ONLY( char *strend = buf + strlen(buf); )
|
||||
|
||||
while ((sub = read_deplist(&buf, '|', ','))) {
|
||||
insert_deplistlist(addto, sub);
|
||||
addto = &(*addto)->next;
|
||||
|
||||
if (*buf == ',') buf++;
|
||||
}
|
||||
|
||||
DEBUG_ONLY( assert(buf <= strend); )
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static dependency *read_dependency(char **buf, char *end) {
|
||||
dependency *dep;
|
||||
char *name;
|
||||
char newend[11];
|
||||
DEBUG_ONLY( char *strend = *buf + strlen(*buf); )
|
||||
|
||||
assert(strlen(end) <= 8);
|
||||
newend[0] = '('; newend[1] = ':'; strcpy(newend + 2, end);
|
||||
|
||||
name = my_strdup(read_until_char(buf, newend));
|
||||
if (name == NULL) return NULL;
|
||||
|
||||
dep = block_malloc(sizeof(dependency));
|
||||
if (dep == NULL) die("read_dependency alloc 1:");
|
||||
|
||||
dep->package = name;
|
||||
|
||||
if (**buf == ':') {
|
||||
(*buf)++;
|
||||
dep->archqual = my_strdup(read_until_char(buf, newend));
|
||||
if (dep->archqual == NULL) return NULL;
|
||||
} else
|
||||
dep->archqual = NULL;
|
||||
|
||||
while(isspace(**buf)) (*buf)++;
|
||||
|
||||
if (**buf != '(') {
|
||||
dep->op = dr_NOOP;
|
||||
dep->version = NULL;
|
||||
} else {
|
||||
(*buf)++;
|
||||
while(isspace(**buf)) (*buf)++;
|
||||
/* << , <= , = , >= , >> */
|
||||
if (**buf == '<') {
|
||||
(*buf)++;
|
||||
if (**buf == '<') {
|
||||
dep->op = dr_LT;
|
||||
(*buf)++;
|
||||
} else if (**buf == '=') {
|
||||
dep->op = dr_LTEQ;
|
||||
(*buf)++;
|
||||
} else {
|
||||
/* The forms `<' and `>' were used to mean earlier/later or
|
||||
* equal, rather than strictly earlier/later, so they should
|
||||
* not appear in new packages (though `dpkg' still supports
|
||||
* them).
|
||||
*/
|
||||
dep->op = dr_LTEQ;
|
||||
}
|
||||
} else if (**buf == '>') {
|
||||
(*buf)++;
|
||||
if (**buf == '>') {
|
||||
dep->op = dr_GT;
|
||||
(*buf)++;
|
||||
} else if (**buf == '=') {
|
||||
dep->op = dr_GTEQ;
|
||||
(*buf)++;
|
||||
} else {
|
||||
dep->op = dr_GTEQ;
|
||||
}
|
||||
} else if (**buf == '=') {
|
||||
dep->op = dr_EQ;
|
||||
(*buf)++;
|
||||
if (**buf == '>') {
|
||||
dep->op = dr_GTEQ;
|
||||
(*buf)++;
|
||||
} else if (**buf == '<') {
|
||||
dep->op = dr_LTEQ;
|
||||
(*buf)++;
|
||||
}
|
||||
} else {
|
||||
/* treat it as an implicit = :( */
|
||||
dep->op = dr_EQ;
|
||||
/* would prefer to: die("read_dependency unknown version op"); */
|
||||
}
|
||||
|
||||
while (isspace(**buf)) (*buf)++;
|
||||
newend[0] = ')'; strcpy(newend + 1, end);
|
||||
dep->version = my_strdup(read_until_char(buf, newend));
|
||||
while (isspace(**buf)) (*buf)++;
|
||||
|
||||
if (dep->version == NULL) die("read_dependency: no version");
|
||||
if (**buf != ')') die("read_dependency: unterminated version");
|
||||
(*buf)++;
|
||||
}
|
||||
|
||||
DEBUG_ONLY( assert(*buf <= strend); )
|
||||
|
||||
return dep;
|
||||
}
|
||||
|
||||
static void free_dependency(dependency *dep) {
|
||||
if (dep == NULL) return;
|
||||
/* block_free(dep->package); */
|
||||
/* if (dep->version) block_free(dep->version); */
|
||||
block_free(dep, sizeof(dependency));
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* Installability Checking
|
||||
*/
|
||||
|
||||
static collpackagelist **get_matching_low(collpackagelist **addto,
|
||||
dpkg_packages *pkgs, dependency *dep, int line)
|
||||
{
|
||||
virtualpkg *vpkg;
|
||||
for (vpkg = lookup_virtualpkgtbl(pkgs->virtualpkgs, dep->package);
|
||||
vpkg != NULL;
|
||||
vpkg = vpkg->next)
|
||||
{
|
||||
int add;
|
||||
|
||||
add = 0;
|
||||
if (dep->op == dr_NOOP) {
|
||||
add = 1;
|
||||
} else if (vpkg->value.version != NULL) {
|
||||
if (cmpversions(vpkg->value.version, dep->op, dep->version)) {
|
||||
add = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (dep->archqual != NULL) {
|
||||
if (strcmp(dep->archqual, "any") == 0) {
|
||||
if (vpkg->value.multiarch == NULL || strcmp(vpkg->value.multiarch, "allowed") != 0)
|
||||
add = 0;
|
||||
} else
|
||||
add = 0;
|
||||
}
|
||||
|
||||
if (add) {
|
||||
insert_l_collpackagelist(addto, vpkg->value.pkg, line);
|
||||
addto = &(*addto)->next;
|
||||
}
|
||||
}
|
||||
|
||||
return addto;
|
||||
}
|
||||
|
||||
static collpackagelist *get_matching(dpkg_packages *pkgs, deplist *depopts, int line) {
|
||||
collpackagelist *list = NULL;
|
||||
collpackagelist **addto = &list;
|
||||
|
||||
for(; depopts != NULL; depopts = depopts->next) {
|
||||
addto = get_matching_low(addto, pkgs, depopts->value, line);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
typedef struct instonelist instonelist;
|
||||
struct instonelist {
|
||||
collpackagelist *curX;
|
||||
collpackagelist *instoneX;
|
||||
int expandedX;
|
||||
struct instonelist *nextX, *prevX, *cutoffX;
|
||||
};
|
||||
|
||||
#define I1CUR(i1) ((i1)->curX)
|
||||
#define I1INSTONE(i1) ((i1)->instoneX)
|
||||
#define I1CUTOFF(i1) ((i1)->cutoffX)
|
||||
#define I1NEXT(i1) ((i1)->nextX) /* can be modified ! */
|
||||
#define I1PREV(i1) ((i1)->prevX)
|
||||
#define I1EXPANDED(i1) ((i1)->expandedX)
|
||||
|
||||
static instonelist *insert_instonelist(instonelist *where, collpackagelist *instone);
|
||||
static void trim_instonelist_after(instonelist *first);
|
||||
static void free_instonelist(instonelist *l);
|
||||
|
||||
static instonelist *insert_instonelist(instonelist *old, collpackagelist *instone)
|
||||
{
|
||||
instonelist *n = block_malloc(sizeof(instonelist));
|
||||
if (n == NULL)
|
||||
die("insert_instonelist alloc:");
|
||||
|
||||
n->curX = NULL;
|
||||
n->instoneX = instone;
|
||||
n->cutoffX = NULL;
|
||||
n->nextX = (old ? old->nextX : NULL);
|
||||
n->prevX = old;
|
||||
n->expandedX = 0;
|
||||
|
||||
if (old) old->nextX = n;
|
||||
if (n->nextX) n->nextX->prevX = n;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static void trim_instonelist_after(instonelist *first) {
|
||||
if (!first->nextX) return;
|
||||
first->nextX->prevX = NULL;
|
||||
free_instonelist(first->nextX);
|
||||
first->nextX = NULL;
|
||||
}
|
||||
|
||||
static void free_instonelist(instonelist *l) {
|
||||
instonelist *p, *k;
|
||||
if (!l) return;
|
||||
for (p = l; p->nextX; p = p->nextX);
|
||||
do {
|
||||
k = p;
|
||||
p = k->prevX;
|
||||
free_collpackagelist(k->instoneX);
|
||||
block_free(k, sizeof(instonelist));
|
||||
} while (k != l);
|
||||
}
|
||||
|
||||
static int caninstall(dpkg_packages *pkgs, dpkg_collected_package *cpkg) {
|
||||
collpackagelist *conflicts;
|
||||
collpackagelist *conf;
|
||||
int okay;
|
||||
|
||||
if (cpkg->installed > 0) return 1;
|
||||
if (cpkg->conflicted > 0) return 0;
|
||||
|
||||
conflicts = get_matching(pkgs, cpkg->pkg->conflicts, __LINE__);
|
||||
|
||||
okay = 1;
|
||||
for (conf = conflicts; conf != NULL; conf = conf->next) {
|
||||
if (conf->value->installed > 0) {
|
||||
okay = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free_collpackagelist(conflicts);
|
||||
return okay;
|
||||
}
|
||||
|
||||
static void install(dpkg_packages *pkgs, dpkg_collected_package *cpkg) {
|
||||
if (cpkg->installed == 0) {
|
||||
collpackagelist *conflicts = get_matching(pkgs, cpkg->pkg->conflicts, __LINE__);
|
||||
collpackagelist *conf;
|
||||
for (conf = conflicts; conf != NULL; conf = conf->next) {
|
||||
if (conf->value == cpkg) continue;
|
||||
assert(conf->value->installed == 0);
|
||||
conf->value->conflicted++;
|
||||
}
|
||||
free_collpackagelist(conflicts);
|
||||
}
|
||||
assert(cpkg->conflicted == 0);
|
||||
cpkg->installed++;
|
||||
}
|
||||
|
||||
static void uninstall(dpkg_packages *pkgs, dpkg_collected_package *cpkg) {
|
||||
assert(cpkg->installed > 0);
|
||||
assert(cpkg->conflicted == 0);
|
||||
cpkg->installed--;
|
||||
if (cpkg->installed == 0) {
|
||||
collpackagelist *conflicts = get_matching(pkgs, cpkg->pkg->conflicts, __LINE__);
|
||||
collpackagelist *conf;
|
||||
for (conf = conflicts; conf != NULL; conf = conf->next) {
|
||||
if (conf->value == cpkg) continue;
|
||||
assert(conf->value->installed == 0);
|
||||
assert(conf->value->conflicted > 0);
|
||||
conf->value->conflicted--;
|
||||
}
|
||||
free_collpackagelist(conflicts);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int checkinstallable2(dpkg_packages *pkgs, char *pkgname) {
|
||||
dpkg_collected_package *cpkg = lookup_packagetbl(pkgs->packages, pkgname);
|
||||
collpackagelist *cpl = NULL;
|
||||
|
||||
if (cpkg == NULL) return 0;
|
||||
|
||||
insert_collpackagelist(&cpl, cpkg);
|
||||
/* cpl gets freed in checkinstallable :-/ */
|
||||
return checkinstallable(pkgs, cpl);
|
||||
}
|
||||
|
||||
static void debug_checkinstallable(FILE *out, instonelist *list,
|
||||
instonelist *last, instonelist *pointer)
|
||||
{
|
||||
instonelist *l;
|
||||
fprintf(out, "Status:");
|
||||
|
||||
/* codes: | = multiple options here
|
||||
* @ = no options can satisfy this dep
|
||||
* + = dependencies that can be expanded have been
|
||||
* * = nothing selected yet
|
||||
* > = where pointer points
|
||||
* ^ = the cut point for where we are
|
||||
*/
|
||||
|
||||
for (l = list; ; l = I1NEXT(l)) {
|
||||
fprintf(out, " ");
|
||||
if (l == pointer) fprintf(out, ">");
|
||||
if (l == I1CUTOFF(pointer)) fprintf(out, "^");
|
||||
if (I1INSTONE(l) == NULL) {
|
||||
fprintf(out, "@");
|
||||
} else {
|
||||
if (I1INSTONE(l)->next != NULL) {
|
||||
fprintf(out, "|");
|
||||
}
|
||||
if (I1EXPANDED(l)) {
|
||||
fprintf(out, "+");
|
||||
}
|
||||
if (I1CUR(l) == NULL) {
|
||||
fprintf(out, "*%s", I1INSTONE(l)->value->pkg->package);
|
||||
} else {
|
||||
fprintf(out, "%s", I1CUR(l)->value->pkg->package);
|
||||
}
|
||||
}
|
||||
if (l == last) break;
|
||||
}
|
||||
fprintf(out, " ###\n");
|
||||
fflush(out);
|
||||
}
|
||||
|
||||
static int checkinstallable(dpkg_packages *pkgs, collpackagelist *instoneof) {
|
||||
/* We use pkg->installed, pkg->conflicted to note how many
|
||||
* times we've used this pkg to satisfy a dependency or installed
|
||||
* a package that conflicts with it.
|
||||
* Thus: pkg->installed == 0, or pkg->conflicted == 0
|
||||
*
|
||||
* We assume these are okay initially, aren't being played with
|
||||
* concurrently elsewhere, and make sure they're still okay when
|
||||
* we return.
|
||||
*/
|
||||
|
||||
instonelist *list;
|
||||
instonelist *last;
|
||||
|
||||
instonelist *pointer;
|
||||
|
||||
unsigned long counter = 10000000;
|
||||
|
||||
{
|
||||
collpackagelist *cpkg;
|
||||
for (cpkg = instoneof; cpkg; cpkg = cpkg->next) {
|
||||
if (cpkg->value->installable == YES) {
|
||||
free_collpackagelist(instoneof);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list = insert_instonelist(NULL, instoneof);
|
||||
|
||||
last = list;
|
||||
pointer = list;
|
||||
|
||||
while(--counter > 0 && pointer) {
|
||||
deplistlist *dep;
|
||||
dpkg_collected_package *instpkg; /* convenient alias */
|
||||
int i;
|
||||
|
||||
#ifndef NDEBUG
|
||||
{
|
||||
instonelist *p;
|
||||
for (p = list; p != pointer; p = I1NEXT(p)) {
|
||||
assert(p != NULL);
|
||||
assert(I1CUR(p) != NULL);
|
||||
assert(I1CUR(p)->value != NULL);
|
||||
assert(I1CUR(p)->value->installed > 0);
|
||||
assert(I1CUR(p)->value->conflicted == 0);
|
||||
}
|
||||
if (I1NEXT(pointer) == NULL) {
|
||||
assert(pointer == last);
|
||||
} else {
|
||||
for (p = I1NEXT(pointer); p; p = I1NEXT(p)) {
|
||||
if (I1NEXT(p) == NULL) {
|
||||
assert(p == last);
|
||||
}
|
||||
assert(I1CUR(p) == NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DIAGNOSE
|
||||
debug_checkinstallable(stdout, list, last, pointer);
|
||||
#endif
|
||||
|
||||
if (I1CUR(pointer) == NULL) {
|
||||
I1CUR(pointer) = I1INSTONE(pointer);
|
||||
/* try to choose an already installed package if there is one */
|
||||
while (I1CUR(pointer) != NULL) {
|
||||
if (I1CUR(pointer)->value->installed != 0) {
|
||||
break;
|
||||
}
|
||||
I1CUR(pointer) = I1CUR(pointer)->next;
|
||||
}
|
||||
if (I1CUR(pointer) == NULL) {
|
||||
I1CUR(pointer) = I1INSTONE(pointer);
|
||||
}
|
||||
assert(I1CUR(pointer) || !I1INSTONE(pointer));
|
||||
|
||||
I1CUTOFF(pointer) = last;
|
||||
} else {
|
||||
uninstall(pkgs, I1CUR(pointer)->value);
|
||||
trim_instonelist_after(I1CUTOFF(pointer));
|
||||
last = I1CUTOFF(pointer);
|
||||
|
||||
if (I1CUR(pointer)->value->installed > 0) {
|
||||
/* this dependency isn't the issue -- even doing
|
||||
* nothing to satisfy it (ie, using an already
|
||||
* installed package) doesn't do any good. So give up.
|
||||
*/
|
||||
I1CUR(pointer) = NULL;
|
||||
} else {
|
||||
I1CUR(pointer) = I1CUR(pointer)->next;
|
||||
}
|
||||
}
|
||||
|
||||
while(I1CUR(pointer) && !caninstall(pkgs, I1CUR(pointer)->value)) {
|
||||
I1CUR(pointer) = I1CUR(pointer)->next;
|
||||
}
|
||||
|
||||
if (I1CUR(pointer) == NULL) {
|
||||
if (I1PREV(pointer) == NULL) break;
|
||||
pointer = I1PREV(pointer);
|
||||
continue;
|
||||
}
|
||||
|
||||
instpkg = I1CUR(pointer)->value;
|
||||
|
||||
install(pkgs, instpkg);
|
||||
|
||||
assert(instpkg->installed > 0);
|
||||
if (instpkg->installed == 1) {
|
||||
/* if it's been installed exactly once, then this must've been
|
||||
* the first time it was touched, so we need to look at the
|
||||
* dependencies. If it's the second or later, then we don't care
|
||||
* about them.
|
||||
*/
|
||||
|
||||
/* if any of the deps can't be satisfied, don't move on */
|
||||
int bother = 1;
|
||||
|
||||
int expanded = I1EXPANDED(pointer);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (!dependency_counts[i]) continue;
|
||||
for (dep = instpkg->pkg->depends[i];
|
||||
dep != NULL; dep = dep->next)
|
||||
{
|
||||
collpackagelist *thisdep = get_matching(pkgs, dep->value, __LINE__);
|
||||
|
||||
if (thisdep == NULL) {
|
||||
bother = 0;
|
||||
|
||||
} else if (thisdep != NULL && thisdep->next == NULL) {
|
||||
collpackagelist *x;
|
||||
|
||||
/* if there's only one way of fulfilling this dep,
|
||||
* do it "ASAP"
|
||||
*/
|
||||
|
||||
/* optimisation: if thisdep == foo, but the parent
|
||||
* was foo|bar, then we already know "foo" is not going
|
||||
* to work in this combination, and we can skip it.
|
||||
*
|
||||
* This deals with cases like X deps: Y|bar, bar deps: Y
|
||||
* where bar is a virtual package; cf xlibs
|
||||
*/
|
||||
for (x = I1INSTONE(pointer); x != I1CUR(pointer); x = x->next) {
|
||||
if (x->value == thisdep->value) {
|
||||
bother = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (I1INSTONE(pointer)->next == NULL) {
|
||||
/* the parent of this entry essentially depends
|
||||
* on this too, so we'll get it out of the way
|
||||
* ASAP, to reduce the degree of exponentiation
|
||||
* in bad cases.
|
||||
*
|
||||
* _However_ we only want to do this _once_ for
|
||||
* any particular node.
|
||||
*/
|
||||
if (expanded) {
|
||||
/* thisdep isn't used! */
|
||||
free_collpackagelist(thisdep);
|
||||
} else {
|
||||
insert_instonelist(pointer, thisdep);
|
||||
I1EXPANDED(pointer) = 1;
|
||||
}
|
||||
} else {
|
||||
insert_instonelist(I1CUTOFF(pointer), thisdep);
|
||||
}
|
||||
if (I1NEXT(last)) last = I1NEXT(last);
|
||||
assert(!I1NEXT(last));
|
||||
|
||||
} else {
|
||||
/* otherwise it's a multi possibility dep, so do it
|
||||
* at the end
|
||||
*/
|
||||
|
||||
last = insert_instonelist(last, thisdep);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!bother) {
|
||||
/* stay where we are, and try the next possibility */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
pointer = I1NEXT(pointer);
|
||||
}
|
||||
|
||||
if (counter == 0) {
|
||||
unsigned int package_count = 0;
|
||||
fprintf(stderr, "AIEEE: counter overflow:");
|
||||
assert(pointer != NULL);
|
||||
if (I1CUR(pointer) == NULL || I1CUR(pointer)->value == NULL) {
|
||||
/* we're not guaranteed that pointer will make sense here */
|
||||
pointer = I1PREV(pointer);
|
||||
}
|
||||
for (; pointer != NULL; pointer = I1PREV(pointer)) {
|
||||
if (I1CUR(pointer) == NULL) {
|
||||
/* should only happen at pointer, so not here */
|
||||
fprintf(stderr, " >> eep, no packages at pointer <<");
|
||||
continue;
|
||||
}
|
||||
if (I1CUR(pointer)->value == NULL) {
|
||||
/* should never happen */
|
||||
fprintf(stderr, " >> eep, no package selected <<");
|
||||
continue;
|
||||
}
|
||||
/* the full list is no as interesting as the "guilty" package,
|
||||
* display the number of involved packages instead */
|
||||
#if 0
|
||||
fprintf(stderr, " %s%s",
|
||||
(I1INSTONE(pointer)->next == NULL ? "" : "|"),
|
||||
I1CUR(pointer)->value->pkg->package);
|
||||
#endif
|
||||
package_count++;
|
||||
uninstall(pkgs, I1CUR(pointer)->value);
|
||||
}
|
||||
fprintf(stderr, " %u involved packages.\n", package_count);
|
||||
free_instonelist(list);
|
||||
/* let the caller know we hit a bad failure */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pointer == NULL) {
|
||||
dpkg_collected_package *cpkg = I1CUR(list)->value;
|
||||
assert(cpkg->installable != YES);
|
||||
cpkg->installable = YES;
|
||||
for (pointer = last; pointer != NULL; pointer = I1PREV(pointer)) {
|
||||
if (I1CUR(pointer)->value->installed == 1) {
|
||||
packagenamelist **p = &I1CUR(pointer)->value->mayaffect;
|
||||
#if 0
|
||||
while ( *p && (*p)->value < cpkg->pkg->package ) {
|
||||
p = &(*p)->next;
|
||||
}
|
||||
if (*p == NULL || (*p)->value > cpkg->pkg->package)
|
||||
#endif
|
||||
{
|
||||
insert_packagenamelist(p, cpkg->pkg->package);
|
||||
}
|
||||
}
|
||||
uninstall(pkgs, I1CUR(pointer)->value);
|
||||
}
|
||||
free_instonelist(list);
|
||||
return 1;
|
||||
} else {
|
||||
assert(I1CUR(list) == NULL);
|
||||
free_instonelist(list);
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -1,139 +0,0 @@
|
||||
#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;
|
||||
char *archqual;
|
||||
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 *multiarch;
|
||||
|
||||
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 *);
|
||||
|
||||
/**************************************************************************
|
||||
* Coping with a source package (and collections thereof) as an abstract
|
||||
* entity, owning a bunch of binary packages
|
||||
*/
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*/
|
||||
|
||||
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;
|
||||
char *multiarch;
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
// Used by britney-py.c
|
||||
|
||||
void add_package(dpkg_packages *pkgs, dpkg_package *pkg);
|
||||
void remove_package(dpkg_packages *pkgs, dpkg_collected_package *pkg);
|
||||
dpkg_packages *new_packages(char *arch);
|
||||
void free_packages(dpkg_packages *pkgs);
|
||||
|
||||
deplistlist *read_dep_andor(char *buf);
|
||||
deplist *read_dep_and(char *buf);
|
||||
ownedpackagenamelist *read_packagenames(char *buf);
|
||||
|
||||
int checkinstallable2(dpkg_packages *pkgs, char *pkgname);
|
||||
|
||||
|
||||
|
||||
#endif
|
@ -1,27 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
import britney
|
||||
|
||||
# VERSION = 0
|
||||
# SECTION = 1
|
||||
# SOURCE = 2
|
||||
# SOURCEVER = 3
|
||||
# ARCHITECTURE = 4
|
||||
# PREDEPENDS = 5
|
||||
# DEPENDS = 6
|
||||
# CONFLICTS = 7
|
||||
# PROVIDES = 8
|
||||
# RDEPENDS = 9
|
||||
# RCONFLICTS = 10
|
||||
|
||||
packages = {'phpldapadmin': ['1.0', 'web', 'phpldapadmin', '1.0', 'all', '', 'apache2 (>= 2.0)', '', '', [], []],
|
||||
'apache2': ['2.0', 'web', 'apache2', '2.0', 'i386', '', '', 'phpldapadmin (<= 1.0~)', '', [], []],
|
||||
}
|
||||
|
||||
system = britney.buildSystem('i386', packages)
|
||||
print system.is_installable('phpldapadmin'), system.packages
|
||||
system.remove_binary('apache2')
|
||||
print system.is_installable('phpldapadmin'), system.packages
|
||||
system.add_binary('apache2', ['2.0', 'web', 'apache2', '2.0', 'i386', '', '', 'phpldapadmin (<= 1.0~)', '', [], []])
|
||||
print system.is_installable('phpldapadmin'), system.packages
|
@ -1,188 +0,0 @@
|
||||
#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
|
@ -1,14 +0,0 @@
|
||||
|
||||
#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
|
@ -1,18 +0,0 @@
|
||||
<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>
|
@ -1,47 +0,0 @@
|
||||
#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 */
|
@ -1,209 +0,0 @@
|
||||
#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
|
@ -1,277 +0,0 @@
|
||||
#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
|
||||
|
||||
|
@ -1,13 +0,0 @@
|
||||
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