2010-11-20 12:29:18 +02:00
|
|
|
/*
|
|
|
|
* prereq.c - Determine prerequisite packages
|
|
|
|
*
|
|
|
|
* Written 2010 by Werner Almesberger
|
|
|
|
* Copyright 2010 Werner Almesberger
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2010-11-19 19:00:15 +02:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#include "id.h"
|
|
|
|
#include "qpkg.h"
|
|
|
|
#include "util.h"
|
2010-11-20 01:51:49 +02:00
|
|
|
#include "prereq.h"
|
2010-11-19 19:00:15 +02:00
|
|
|
|
|
|
|
|
|
|
|
struct list {
|
|
|
|
const struct ref *refs;
|
|
|
|
struct list *next;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static struct pkg **best = NULL;
|
qpkg: rearrange things in prereq.c to free the stack paradigm for other uses
- prereq.c (stack, epoch, push, pop, resolve, prereq): renamed to
"installs"
- prereq.c (n_stack, stack_max, push, pop, resolve, prereq): changed
"stack" to "install"
- prereq.c (push): renamed "push" to "append_install"
- prereq.c (pop): renamed "pop" to "backtrack"
2010-11-21 13:12:14 +02:00
|
|
|
static struct pkg **installs = NULL;
|
2010-11-19 19:00:15 +02:00
|
|
|
static int n_best; /* undefined if best == NULL */
|
qpkg: rearrange things in prereq.c to free the stack paradigm for other uses
- prereq.c (stack, epoch, push, pop, resolve, prereq): renamed to
"installs"
- prereq.c (n_stack, stack_max, push, pop, resolve, prereq): changed
"stack" to "install"
- prereq.c (push): renamed "push" to "append_install"
- prereq.c (pop): renamed "pop" to "backtrack"
2010-11-21 13:12:14 +02:00
|
|
|
static int n_install = 0;
|
|
|
|
static int install_max = 0;
|
2010-11-19 19:00:15 +02:00
|
|
|
|
|
|
|
|
|
|
|
static int epoch(const char **s, const struct id *id)
|
|
|
|
{
|
|
|
|
const char *end = id->s+id->len;
|
|
|
|
int n = 0;
|
|
|
|
|
|
|
|
while (*s != end && isdigit(**s)) {
|
|
|
|
n = 10*n+**s-'0';
|
|
|
|
(*s)++;
|
|
|
|
}
|
|
|
|
if (*s == id->s || (*s != end && **s == ':'))
|
|
|
|
return n;
|
|
|
|
*s = id->s;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int comp_versions(const struct id *va, const struct id *vb)
|
|
|
|
{
|
|
|
|
int epoch_a = 0, epoch_b = 0;
|
|
|
|
const char *a = va->s;
|
|
|
|
const char *b = vb->s;
|
|
|
|
const char *ea = a+va->len;
|
|
|
|
const char *eb = b+vb->len;
|
|
|
|
|
|
|
|
epoch_a = epoch(&a, va);
|
|
|
|
epoch_b = epoch(&b, vb);
|
|
|
|
if (epoch_a != epoch_b)
|
|
|
|
return epoch_a-epoch_b;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
if (a == ea || b == eb)
|
|
|
|
return (a != ea)-(b != eb);
|
|
|
|
if (isdigit(*a) && isdigit(*b)) {
|
|
|
|
int na = 0, nb = 0;
|
|
|
|
|
|
|
|
while (a != ea && isdigit(*a)) {
|
|
|
|
na = na*10+*a-'0';
|
|
|
|
a++;
|
|
|
|
}
|
|
|
|
while (b != eb && isdigit(*b)) {
|
|
|
|
nb = nb*10+*b-'0';
|
|
|
|
b++;
|
|
|
|
}
|
|
|
|
if (na == nb)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
return na-nb;
|
|
|
|
}
|
|
|
|
if (*a > *b)
|
|
|
|
return 1;
|
|
|
|
if (*a < *b)
|
|
|
|
return 1;
|
|
|
|
a++;
|
|
|
|
b++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void done(void)
|
|
|
|
{
|
|
|
|
int size;
|
|
|
|
|
qpkg: rearrange things in prereq.c to free the stack paradigm for other uses
- prereq.c (stack, epoch, push, pop, resolve, prereq): renamed to
"installs"
- prereq.c (n_stack, stack_max, push, pop, resolve, prereq): changed
"stack" to "install"
- prereq.c (push): renamed "push" to "append_install"
- prereq.c (pop): renamed "pop" to "backtrack"
2010-11-21 13:12:14 +02:00
|
|
|
if (best && n_best <= n_install)
|
2010-11-19 19:00:15 +02:00
|
|
|
return;
|
|
|
|
free(best);
|
qpkg: rearrange things in prereq.c to free the stack paradigm for other uses
- prereq.c (stack, epoch, push, pop, resolve, prereq): renamed to
"installs"
- prereq.c (n_stack, stack_max, push, pop, resolve, prereq): changed
"stack" to "install"
- prereq.c (push): renamed "push" to "append_install"
- prereq.c (pop): renamed "pop" to "backtrack"
2010-11-21 13:12:14 +02:00
|
|
|
size = sizeof(*installs)*(n_install+1);
|
2010-11-19 19:00:15 +02:00
|
|
|
best = alloc_size(size);
|
qpkg: rearrange things in prereq.c to free the stack paradigm for other uses
- prereq.c (stack, epoch, push, pop, resolve, prereq): renamed to
"installs"
- prereq.c (n_stack, stack_max, push, pop, resolve, prereq): changed
"stack" to "install"
- prereq.c (push): renamed "push" to "append_install"
- prereq.c (pop): renamed "pop" to "backtrack"
2010-11-21 13:12:14 +02:00
|
|
|
memcpy(best, installs, sizeof(*installs)*n_install);
|
|
|
|
n_best = n_install;
|
2010-11-19 19:00:15 +02:00
|
|
|
best[n_best] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
qpkg: rearrange things in prereq.c to free the stack paradigm for other uses
- prereq.c (stack, epoch, push, pop, resolve, prereq): renamed to
"installs"
- prereq.c (n_stack, stack_max, push, pop, resolve, prereq): changed
"stack" to "install"
- prereq.c (push): renamed "push" to "append_install"
- prereq.c (pop): renamed "pop" to "backtrack"
2010-11-21 13:12:14 +02:00
|
|
|
static void append_install(struct pkg *pkg)
|
2010-11-19 19:00:15 +02:00
|
|
|
{
|
2010-11-21 08:25:53 +02:00
|
|
|
//fprintf(stderr, "push %.*s\n", ID2PF(pkg->id));
|
qpkg: rearrange things in prereq.c to free the stack paradigm for other uses
- prereq.c (stack, epoch, push, pop, resolve, prereq): renamed to
"installs"
- prereq.c (n_stack, stack_max, push, pop, resolve, prereq): changed
"stack" to "install"
- prereq.c (push): renamed "push" to "append_install"
- prereq.c (pop): renamed "pop" to "backtrack"
2010-11-21 13:12:14 +02:00
|
|
|
if (n_install == install_max) {
|
|
|
|
install_max = (install_max+1)*2;
|
|
|
|
installs = realloc(installs, sizeof(*installs)*install_max);
|
|
|
|
if (!installs) {
|
2010-11-19 19:00:15 +02:00
|
|
|
perror("realloc");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
qpkg: rearrange things in prereq.c to free the stack paradigm for other uses
- prereq.c (stack, epoch, push, pop, resolve, prereq): renamed to
"installs"
- prereq.c (n_stack, stack_max, push, pop, resolve, prereq): changed
"stack" to "install"
- prereq.c (push): renamed "push" to "append_install"
- prereq.c (pop): renamed "pop" to "backtrack"
2010-11-21 13:12:14 +02:00
|
|
|
installs[n_install++] = pkg;
|
2010-11-20 17:25:45 +02:00
|
|
|
assert(!pkg->mark && !(pkg->flags & QPKG_INSTALLED));
|
2010-11-19 19:00:15 +02:00
|
|
|
pkg->mark = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
qpkg: rearrange things in prereq.c to free the stack paradigm for other uses
- prereq.c (stack, epoch, push, pop, resolve, prereq): renamed to
"installs"
- prereq.c (n_stack, stack_max, push, pop, resolve, prereq): changed
"stack" to "install"
- prereq.c (push): renamed "push" to "append_install"
- prereq.c (pop): renamed "pop" to "backtrack"
2010-11-21 13:12:14 +02:00
|
|
|
static void backtrack(void)
|
2010-11-19 19:00:15 +02:00
|
|
|
{
|
qpkg: rearrange things in prereq.c to free the stack paradigm for other uses
- prereq.c (stack, epoch, push, pop, resolve, prereq): renamed to
"installs"
- prereq.c (n_stack, stack_max, push, pop, resolve, prereq): changed
"stack" to "install"
- prereq.c (push): renamed "push" to "append_install"
- prereq.c (pop): renamed "pop" to "backtrack"
2010-11-21 13:12:14 +02:00
|
|
|
assert(n_install);
|
|
|
|
n_install--;
|
|
|
|
installs[n_install]->mark = 0;
|
2010-11-19 19:00:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int satisfies(const struct pkg *pkg, const struct ref *ref)
|
|
|
|
{
|
|
|
|
int cmp;
|
|
|
|
|
|
|
|
if (pkg->id != ref->pkg)
|
|
|
|
return 0;
|
|
|
|
if (!ref->version)
|
|
|
|
return 1;
|
|
|
|
assert(pkg->version);
|
|
|
|
cmp = comp_versions(pkg->version, ref->version);
|
|
|
|
//fprintf(stderr, "%.*s <%d> %.*s\n",
|
2010-11-21 08:25:53 +02:00
|
|
|
// ID2PF(pkg->version), cmp, ID2PF(ref->version));
|
2010-11-19 19:00:15 +02:00
|
|
|
switch (ref->relop) {
|
|
|
|
case rel_eq:
|
|
|
|
return !cmp;
|
|
|
|
case rel_ge:
|
|
|
|
return cmp >= 0;
|
|
|
|
case rel_lt:
|
|
|
|
return cmp < 0;
|
|
|
|
default:
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int conflicts(const struct pkg *pkg, const struct list *conf)
|
|
|
|
{
|
|
|
|
/* @@@ */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void resolve(struct list *next_dep, const struct ref *dep,
|
|
|
|
struct list *conf)
|
|
|
|
{
|
2010-11-19 20:26:24 +02:00
|
|
|
static int level = 0;
|
2010-11-19 19:00:15 +02:00
|
|
|
struct list more_deps;
|
|
|
|
struct list more_conf = {
|
|
|
|
.next = conf
|
|
|
|
};
|
|
|
|
struct pkg *pkg;
|
|
|
|
|
|
|
|
while (!dep) {
|
|
|
|
if (!next_dep) {
|
|
|
|
done();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
dep = next_dep->refs;
|
|
|
|
next_dep = next_dep->next;
|
|
|
|
}
|
2010-11-20 03:02:42 +02:00
|
|
|
for (pkg = dep->pkg->jrb->val; pkg; pkg = pkg->more) {
|
qpkg: rearrange things in prereq.c to free the stack paradigm for other uses
- prereq.c (stack, epoch, push, pop, resolve, prereq): renamed to
"installs"
- prereq.c (n_stack, stack_max, push, pop, resolve, prereq): changed
"stack" to "install"
- prereq.c (push): renamed "push" to "append_install"
- prereq.c (pop): renamed "pop" to "backtrack"
2010-11-21 13:12:14 +02:00
|
|
|
if (best && n_install == n_best)
|
2010-11-19 20:26:24 +02:00
|
|
|
return;
|
|
|
|
#if 0
|
|
|
|
fprintf(stderr, "%*s", level, "");
|
2010-11-21 08:25:53 +02:00
|
|
|
fprintf(stderr, "%.*s %p", ID2PF(pkg->id), pkg);
|
2010-11-19 20:26:24 +02:00
|
|
|
if (pkg->version)
|
2010-11-21 08:25:53 +02:00
|
|
|
fprintf(stderr, " %.*s", ID2PF(pkg->version));
|
2010-11-19 20:26:24 +02:00
|
|
|
if (pkg->mark) fprintf(stderr, " +");
|
2010-11-20 17:25:45 +02:00
|
|
|
if (pkg->flags & QPKG_INSTALLED) fprintf(stderr, " ***");
|
2010-11-19 20:26:24 +02:00
|
|
|
fprintf(stderr, "\n");
|
|
|
|
#endif
|
|
|
|
if (!satisfies(pkg, dep))
|
|
|
|
continue;
|
2010-11-20 17:25:45 +02:00
|
|
|
if ((pkg->flags & QPKG_INSTALLED) || pkg->mark) {
|
2010-11-19 20:26:24 +02:00
|
|
|
assert(!conflicts(pkg, conf));
|
2010-11-19 19:00:15 +02:00
|
|
|
resolve(next_dep, dep->next, conf);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (conflicts(pkg, conf))
|
|
|
|
continue;
|
2010-11-19 20:26:24 +02:00
|
|
|
level++;
|
qpkg: rearrange things in prereq.c to free the stack paradigm for other uses
- prereq.c (stack, epoch, push, pop, resolve, prereq): renamed to
"installs"
- prereq.c (n_stack, stack_max, push, pop, resolve, prereq): changed
"stack" to "install"
- prereq.c (push): renamed "push" to "append_install"
- prereq.c (pop): renamed "pop" to "backtrack"
2010-11-21 13:12:14 +02:00
|
|
|
append_install(pkg);
|
2010-11-19 19:00:15 +02:00
|
|
|
more_deps.refs = pkg->depends;
|
2010-11-19 19:25:33 +02:00
|
|
|
more_deps.next = next_dep;
|
2010-11-19 19:00:15 +02:00
|
|
|
more_conf.refs = pkg->conflicts;
|
|
|
|
more_conf.next = conf;
|
2010-11-19 19:25:33 +02:00
|
|
|
resolve(&more_deps, dep->next, &more_conf);
|
|
|
|
next_dep = more_deps.next;
|
qpkg: rearrange things in prereq.c to free the stack paradigm for other uses
- prereq.c (stack, epoch, push, pop, resolve, prereq): renamed to
"installs"
- prereq.c (n_stack, stack_max, push, pop, resolve, prereq): changed
"stack" to "install"
- prereq.c (push): renamed "push" to "append_install"
- prereq.c (pop): renamed "pop" to "backtrack"
2010-11-21 13:12:14 +02:00
|
|
|
backtrack();
|
2010-11-19 20:26:24 +02:00
|
|
|
level--;
|
2010-11-19 19:00:15 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct pkg **prereq(struct pkg *pkg)
|
|
|
|
{
|
|
|
|
struct list deps = {
|
|
|
|
.refs = pkg->depends,
|
|
|
|
.next = NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
/* @@@ make list of pre-existing conflicts */
|
|
|
|
resolve(&deps, NULL, NULL);
|
qpkg: rearrange things in prereq.c to free the stack paradigm for other uses
- prereq.c (stack, epoch, push, pop, resolve, prereq): renamed to
"installs"
- prereq.c (n_stack, stack_max, push, pop, resolve, prereq): changed
"stack" to "install"
- prereq.c (push): renamed "push" to "append_install"
- prereq.c (pop): renamed "pop" to "backtrack"
2010-11-21 13:12:14 +02:00
|
|
|
free(installs);
|
2010-11-19 19:00:15 +02:00
|
|
|
return best;
|
|
|
|
}
|