- Introduce find_best_matching_file and match_local_files. This replace

the functionality offered by findmatchingname and findbestmatching
  name. They optionally strip the suffix from the filename before
  matching it, instead of modifying the pattern directly.
  Drop the old functions.
- Fix a bug in pkg_order where the version strings where inverted
- Make pkg_admin lsbest and lsall use the new functions.
- Make ftpio use pkg_order directly.

Bump version to 20070812.
This commit is contained in:
joerg 2007-08-12 16:47:17 +00:00
parent 93e480f1ea
commit 7df87b070e
8 changed files with 214 additions and 201 deletions

View file

@ -1,4 +1,4 @@
/* $NetBSD: main.c,v 1.25 2007/08/10 21:18:31 joerg Exp $ */
/* $NetBSD: main.c,v 1.26 2007/08/12 16:47:17 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
@ -8,7 +8,7 @@
#include <sys/cdefs.h>
#endif
#ifndef lint
__RCSID("$NetBSD: main.c,v 1.25 2007/08/10 21:18:31 joerg Exp $");
__RCSID("$NetBSD: main.c,v 1.26 2007/08/12 16:47:17 joerg Exp $");
#endif
/*
@ -436,17 +436,17 @@ checkpattern_fn(const char *pkg, void *vp)
}
static int
lspattern_fn(const char *pattern, const char *pkg, void *vp)
lspattern(const char *pkg, void *vp)
{
char *data = vp;
printf("%s/%s\n", data, pkg);
const char *dir = vp;
printf("%s/%s\n", dir, pkg);
return 0;
}
static int
lsbasepattern_fn(const char *pattern, const char *pkg, void *vp)
lsbasepattern(const char *pkg, void *vp)
{
printf("%s\n", pkg);
puts(pkg);
return 0;
}
@ -695,11 +695,9 @@ main(int argc, char *argv[])
int rc;
const char *basep, *dir;
char cwd[MaxPathSize];
char base[MaxPathSize];
dir = lsdirp ? lsdirp : dirname_of(*argv);
basep = basename_of(*argv);
snprintf(base, sizeof(base), "%s%s", basep, sfx);
fchdir(saved_wd);
rc = chdir(dir);
@ -710,11 +708,11 @@ main(int argc, char *argv[])
err(EXIT_FAILURE, "getcwd");
if (show_basename_only)
rc = findmatchingname(cwd, base, lsbasepattern_fn, cwd);
rc = match_local_files(cwd, use_default_sfx, basep, lsbasepattern, NULL);
else
rc = findmatchingname(cwd, base, lspattern_fn, cwd);
rc = match_local_files(cwd, use_default_sfx, basep, lspattern, cwd);
if (rc == -1)
errx(EXIT_FAILURE, "Error in findmatchingname(\"%s\", \"%s\", ...)",
errx(EXIT_FAILURE, "Error from match_local_files(\"%s\", \"%s\", ...)",
cwd, base);
argv++;
@ -734,24 +732,22 @@ main(int argc, char *argv[])
while (*argv != NULL) {
/* args specified */
int rc;
const char *basep, *dir;
char cwd[MaxPathSize];
char base[MaxPathSize];
char *p;
dir = lsdirp ? lsdirp : dirname_of(*argv);
basep = basename_of(*argv);
snprintf(base, sizeof(base), "%s%s", basep, sfx);
fchdir(saved_wd);
rc = chdir(dir);
if (rc == -1)
if (chdir(dir) == -1)
err(EXIT_FAILURE, "Cannot chdir to %s", dir);
if (getcwd(cwd, sizeof(cwd)) == NULL)
err(EXIT_FAILURE, "getcwd");
p = findbestmatchingname(cwd, base);
p = find_best_matching_file(cwd, basep, use_default_sfx);
if (p) {
if (show_basename_only)
printf("%s\n", p);

View file

@ -1,4 +1,4 @@
/* $NetBSD: file.c,v 1.19 2007/04/16 12:55:35 joerg Exp $ */
/* $NetBSD: file.c,v 1.20 2007/08/12 16:47:17 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
@ -17,7 +17,7 @@
#if 0
static const char *rcsid = "from FreeBSD Id: file.c,v 1.29 1997/10/08 07:47:54 charnier Exp";
#else
__RCSID("$NetBSD: file.c,v 1.19 2007/04/16 12:55:35 joerg Exp $");
__RCSID("$NetBSD: file.c,v 1.20 2007/08/12 16:47:17 joerg Exp $");
#endif
#endif
@ -324,8 +324,7 @@ resolvepattern1(const char *name)
return tmp; /* return expanded URL w/ corrent pkg */
}
else if (ispkgpattern(name)) {
cp = findbestmatchingname(
dirname_of(name), basename_of(name));
cp = find_best_matching_file(dirname_of(name), basename_of(name), 1);
if (cp) {
snprintf(tmp, sizeof(tmp), "%s/%s", dirname_of(name), cp);
free(cp);

View file

@ -1,4 +1,4 @@
/* $NetBSD: ftpio.c,v 1.23 2007/07/20 22:22:53 joerg Exp $ */
/* $NetBSD: ftpio.c,v 1.24 2007/08/12 16:47:18 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
@ -8,7 +8,7 @@
#include <sys/cdefs.h>
#endif
#ifndef lint
__RCSID("$NetBSD: ftpio.c,v 1.23 2007/07/20 22:22:53 joerg Exp $");
__RCSID("$NetBSD: ftpio.c,v 1.24 2007/08/12 16:47:18 joerg Exp $");
#endif
/*-
@ -655,10 +655,12 @@ ftp_expand_URL(const char *base, char *pattern)
char *s, buf[MaxPathSize];
char tmpname[MaxPathSize];
char best[MaxPathSize];
char s_best[MaxPathSize];
int rc, got_list, tfd, retry_tbz;
retry_tbz = 0;
best[0]='\0';
s_best[0]='\0';
rc = ftp_start(base);
if (rc == -1) {
@ -714,7 +716,6 @@ retry_with_tbz:
}
if (got_list == 1 && access(tmpname, R_OK)==0) {
int matches;
FILE *f;
char filename[MaxPathSize];
@ -724,7 +725,6 @@ retry_with_tbz:
unlink(tmpname); /* remove clutter */
return NULL;
}
matches=0;
/* The following loop is basically the same as the readdir() loop
* in findmatchingname() */
while (fgets(filename, sizeof(filename), f)) {
@ -742,22 +742,21 @@ retry_with_tbz:
strip_txz(s_filename, NULL, filename);
strip_txz(s_pattern, NULL, pattern);
if (pkg_match(s_pattern, s_filename)) {
matches++;
/* compare findbestmatchingname() */
findbestmatchingname_fn(pattern, filename, best);
if (pkg_order(s_pattern, s_filename,
s_best[0] != '\0' ? s_best : NULL) == 1) {
strlcpy(s_best, s_filename, sizeof(s_best));
strlcpy(best, filename, sizeof(best));
}
}
(void) fclose(f);
if (matches == 0 && Verbose)
warnx("nothing appropriate found");
}
if (retry_tbz)
goto retry_with_tbz;
if (best[0] == '\0' && Verbose)
warnx("nothing appropriate found");
unlink(tmpname);
if (best[0] == '\0')
@ -771,6 +770,7 @@ static char *
http_expand_URL(const char *base, char *pattern)
{
char best[MaxPathSize];
char s_best[MaxPathSize];
char line[BUFSIZ];
char filename[MaxPathSize];
FILE *fp;
@ -779,6 +779,7 @@ http_expand_URL(const char *base, char *pattern)
pid_t pid;
*best = '\0';
*s_best = '\0';
/* Set up a pipe for getting the file list */
if (pipe(pipefds) == -1) {
@ -828,10 +829,10 @@ http_expand_URL(const char *base, char *pattern)
offset += len;
strip_txz(s_filename, NULL, filename);
if (pkg_match(s_pattern, s_filename)) {
/* compare findbestmatchingname() */
findbestmatchingname_fn(pattern,
filename, best);
if (pkg_order(s_pattern, s_filename,
*s_best != '\0' ? s_best : NULL) == 1) {
strlcpy(best, filename, sizeof(best));
strlcpy(s_best, s_filename, sizeof(best));
}
}
}

View file

@ -65,14 +65,19 @@ iterate_pkg_generic_src(int (*matchiter)(const char *, void *),
return retval;
}
struct pkg_dir_iter_arg {
DIR *dirp;
int filter_suffix;
};
static const char *
pkg_dir_iter(void *cookie)
{
DIR *dirp = cookie;
struct pkg_dir_iter_arg *arg = cookie;
struct dirent *dp;
size_t len;
while ((dp = readdir(dirp)) != NULL) {
while ((dp = readdir(arg->dirp)) != NULL) {
#if defined(DT_UNKNOWN) && defined(DT_DIR)
if (dp->d_type != DT_UNKNOWN && dp->d_type != DT_REG)
continue;
@ -81,7 +86,8 @@ pkg_dir_iter(void *cookie)
/* .tbz or .tgz suffix length + some prefix*/
if (len < 5)
continue;
if (memcmp(dp->d_name + len - 4, ".tgz", 4) == 0 ||
if (arg->filter_suffix == 0 ||
memcmp(dp->d_name + len - 4, ".tgz", 4) == 0 ||
memcmp(dp->d_name + len - 4, ".tbz", 4) == 0)
return dp->d_name;
}
@ -92,18 +98,19 @@ pkg_dir_iter(void *cookie)
* Call matchiter for every package in the directory.
*/
int
iterate_local_pkg_dir(const char *dir, int (*matchiter)(const char *, void *),
void *cookie)
iterate_local_pkg_dir(const char *dir, int filter_suffix,
int (*matchiter)(const char *, void *), void *cookie)
{
DIR *dirp;
struct pkg_dir_iter_arg arg;
int retval;
if ((dirp = opendir(dir)) == NULL)
if ((arg.dirp = opendir(dir)) == NULL)
return -1;
retval = iterate_pkg_generic_src(matchiter, cookie, pkg_dir_iter, dirp);
arg.filter_suffix = filter_suffix;
retval = iterate_pkg_generic_src(matchiter, cookie, pkg_dir_iter, &arg);
if (closedir(dirp) == -1)
if (closedir(arg.dirp) == -1)
return -1;
return retval;
}
@ -326,3 +333,154 @@ match_installed_pkgs(const char *pattern, int (*cb)(const char *, void *),
return iterate_pkg_db(match_and_call, &arg);
}
struct best_file_match_arg {
const char *pattern;
char *best_current_match_filtered;
char *best_current_match;
int filter_suffix;
};
static int
match_best_file(const char *filename, void *cookie)
{
struct best_file_match_arg *arg = cookie;
const char *active_filename;
char *filtered_filename;
if (arg->filter_suffix) {
size_t len;
len = strlen(filename);
if (len < 5 ||
(memcmp(filename + len - 4, ".tgz", 4) != 0 &&
memcmp(filename + len - 4, ".tbz", 4) != 0)) {
warnx("filename %s does not contain a recognized suffix", filename);
return -1;
}
if ((filtered_filename = malloc(len - 4 + 1)) == NULL)
err(EXIT_FAILURE, "malloc failed");
memcpy(filtered_filename, filename, len - 4);
filtered_filename[len - 4] = '\0';
active_filename = filtered_filename;
} else {
filtered_filename = NULL;
active_filename = filename;
}
switch (pkg_order(arg->pattern, active_filename, arg->best_current_match_filtered)) {
case 0:
case 2:
/*
* Either current package doesn't match or
* the older match is better. Nothing to do.
*/
free(filtered_filename);
return 0;
case 1:
/* Current package is better, remember it. */
free(arg->best_current_match);
free(arg->best_current_match_filtered);
if ((arg->best_current_match = strdup(filename)) == NULL) {
arg->best_current_match_filtered = NULL;
free(filtered_filename);
return -1;
}
if (filtered_filename != NULL)
arg->best_current_match_filtered = filtered_filename;
else if ((arg->best_current_match_filtered = strdup(active_filename)) == NULL) {
free(arg->best_current_match);
return -1;
}
return 0;
default:
return -1;
}
}
/*
* Returns a copy of the name of best matching file.
* If no package matched the pattern or an error occured, return NULL.
*/
char *
find_best_matching_file(const char *dir, const char *pattern, int filter_suffix)
{
struct best_file_match_arg arg;
arg.filter_suffix = filter_suffix;
arg.pattern = pattern;
arg.best_current_match = NULL;
arg.best_current_match_filtered = NULL;
if (iterate_local_pkg_dir(dir, filter_suffix, match_best_file, &arg) == -1) {
warnx("could not process directory");
return NULL;
}
free(arg.best_current_match_filtered);
return arg.best_current_match;
}
struct call_matching_file_arg {
const char *pattern;
int (*call_fn)(const char *pkg, void *cookie);
void *cookie;
int filter_suffix;
};
static int
match_file_and_call(const char *filename, void *cookie)
{
struct call_matching_file_arg *arg = cookie;
const char *active_filename;
char *filtered_filename;
int ret;
if (arg->filter_suffix) {
size_t len;
len = strlen(filename);
if (len < 5 ||
(memcmp(filename + len - 4, ".tgz", 4) != 0 &&
memcmp(filename + len - 4, ".tbz", 4) != 0)) {
warnx("filename %s does not contain a recognized suffix", filename);
return -1;
}
if ((filtered_filename = malloc(len - 4 + 1)) == NULL)
err(EXIT_FAILURE, "malloc failed");
memcpy(filtered_filename, filename, len - 4);
filtered_filename[len - 4] = '\0';
active_filename = filtered_filename;
} else {
filtered_filename = NULL;
active_filename = filename;
}
ret = pkg_match(arg->pattern, active_filename);
free(filtered_filename);
if (ret == 1)
return (*arg->call_fn)(filename, arg->cookie);
else
return 0;
}
/*
* Find all packages that match the given pattern and call the function
* for each of them. Iteration stops if the callback return non-0.
* Returns -1 on error, 0 if the iteration finished or whatever the
* callback returned otherwise.
*/
int
match_local_files(const char *dir, int filter_suffix, const char *pattern,
int (*cb)(const char *, void *), void *cookie)
{
struct call_matching_file_arg arg;
arg.pattern = pattern;
arg.call_fn = cb;
arg.cookie = cookie;
arg.filter_suffix = filter_suffix;
return iterate_local_pkg_dir(dir, filter_suffix, match_file_and_call, &arg);
}

View file

@ -1,4 +1,4 @@
/* $NetBSD: lib.h,v 1.32 2007/08/09 23:18:31 joerg Exp $ */
/* $NetBSD: lib.h,v 1.33 2007/08/12 16:47:18 joerg Exp $ */
/* from FreeBSD Id: lib.h,v 1.25 1997/10/08 07:48:03 charnier Exp */
@ -273,10 +273,6 @@ typedef struct _lpkg_t {
TAILQ_HEAD(_lpkg_head_t, _lpkg_t);
typedef struct _lpkg_head_t lpkg_head_t;
/* Type of function to be handed to findmatchingname; return value of this
* is currently ignored */
typedef int (*matchfn) (const char *, const char *, void *);
/* This structure describes a pipe to a child process */
typedef struct {
int fds[2]; /* pipe, 0=child stdin, 1=parent output */
@ -328,25 +324,22 @@ const char *dirname_of(const char *);
const char *suffix_of(const char *);
int pkg_match(const char *, const char *);
int pkg_order(const char *, const char *, const char *);
int findmatchingname(const char *, const char *, matchfn, void *); /* doesn't really belong to "strings" */
char *findbestmatchingname(const char *, const char *); /* neither */
int ispkgpattern(const char *);
void strip_txz(char *, char *, const char *);
/* callback functions for findmatchingname */
int findbestmatchingname_fn(const char *, const char *, void *); /* neither */
/* Iterator functions */
int iterate_pkg_generic_src(int (*)(const char *, void *), void *,
const char *(*)(void *),void *);
int iterate_local_pkg_dir(const char *, int (*)(const char *, void *),
int iterate_local_pkg_dir(const char *, int, int (*)(const char *, void *),
void *);
int iterate_pkg_db(int (*)(const char *, void *), void *);
int add_installed_pkgs_by_basename(const char *, lpkg_head_t *);
int add_installed_pkgs_by_pattern(const char *, lpkg_head_t *);
char *find_best_matching_installed_pkg(const char *);
char *find_best_matching_file(const char *, const char *, int);
int match_installed_pkgs(const char *, int (*)(const char *, void *), void *);
int match_local_files(const char *, int, const char *, int (*cb)(const char *, void *), void *);
/* File */
Boolean fexists(const char *);

View file

@ -1,4 +1,4 @@
/* $NetBSD: opattern.c,v 1.2 2007/08/05 14:58:49 joerg Exp $ */
/* $NetBSD: opattern.c,v 1.3 2007/08/12 16:47:18 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
@ -11,7 +11,7 @@
#if 0
static const char *rcsid = "Id: str.c,v 1.5 1997/10/08 07:48:21 charnier Exp";
#else
__RCSID("$NetBSD: opattern.c,v 1.2 2007/08/05 14:58:49 joerg Exp $");
__RCSID("$NetBSD: opattern.c,v 1.3 2007/08/12 16:47:18 joerg Exp $");
#endif
#endif
@ -160,8 +160,8 @@ pkg_order(const char *pattern, const char *first_pkg, const char *second_pkg)
if (second_pkg == NULL)
return pkg_match(pattern, first_pkg) ? 1 : 0;
first_version = strrchr(second_pkg, '-');
second_version = strrchr(first_pkg, '-');
first_version = strrchr(first_pkg, '-');
second_version = strrchr(second_pkg, '-');
if (first_version == NULL || !pkg_match(pattern, first_pkg))
return pkg_match(pattern, second_pkg) ? 2 : 0;
@ -169,7 +169,7 @@ pkg_order(const char *pattern, const char *first_pkg, const char *second_pkg)
if (second_version == NULL || !pkg_match(pattern, second_pkg))
return pkg_match(pattern, first_pkg) ? 1 : 0;
if (dewey_cmp(first_version, DEWEY_GT, second_version))
if (dewey_cmp(first_version + 1, DEWEY_GT, second_version + 1))
return 1;
else
return 2;

View file

@ -1,4 +1,4 @@
/* $NetBSD: str.c,v 1.20 2007/08/08 22:33:39 joerg Exp $ */
/* $NetBSD: str.c,v 1.21 2007/08/12 16:47:18 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
@ -11,7 +11,7 @@
#if 0
static const char *rcsid = "Id: str.c,v 1.5 1997/10/08 07:48:21 charnier Exp";
#else
__RCSID("$NetBSD: str.c,v 1.20 2007/08/08 22:33:39 joerg Exp $");
__RCSID("$NetBSD: str.c,v 1.21 2007/08/12 16:47:18 joerg Exp $");
#endif
#endif
@ -117,61 +117,6 @@ str_lowercase(unsigned char *s)
}
}
/*
* Search dir for pattern, calling match(pkg_found, data) for every match.
* Returns -1 on error, 1 if found, 0 otherwise.
*/
int
findmatchingname(const char *dir, const char *pattern, matchfn match, void *data)
{
struct dirent *dp;
char tmp_pattern[PKG_PATTERN_MAX];
DIR *dirp;
int found;
char pat_sfx[PKG_SUFFIX_MAX], file_sfx[PKG_SUFFIX_MAX]; /* suffixes */
if (strlen(pattern) >= PKG_PATTERN_MAX)
errx(EXIT_FAILURE, "too long pattern '%s'", pattern);
found = 0;
if ((dirp = opendir(dir)) == (DIR *) NULL) {
/* warnx("can't opendir dir '%s'", dir); */
return -1;
}
/* chop any possible suffix off of 'pattern' and
* store it in pat_sfx
*/
strip_txz(tmp_pattern, pat_sfx, pattern);
while ((dp = readdir(dirp)) != (struct dirent *) NULL) {
char tmp_file[MaxPathSize];
if (strcmp(dp->d_name, ".") == 0 ||
strcmp(dp->d_name, "..") == 0)
continue;
/* chop any possible suffix off of 'tmp_file' and
* store it in file_sfx
*/
strip_txz(tmp_file, file_sfx, dp->d_name);
/* we need to match pattern and suffix separately, in case
* each is a different pattern class (e.g. dewey and
* character class (.t[bg]z)) */
if (pkg_match(tmp_pattern, tmp_file)
&& (pat_sfx[0] == '\0' || pkg_match(pat_sfx, file_sfx))) {
if (match) {
match(pattern, dp->d_name, data);
/* return value ignored for now */
}
found = 1;
}
}
(void) closedir(dirp);
return found;
}
/*
* Does the pkgname contain any of the special chars ("{[]?*<>")?
* If so, return 1, else 0
@ -182,85 +127,6 @@ ispkgpattern(const char *pkg)
return strpbrk(pkg, "<>[]?*{") != NULL;
}
/*
* Auxiliary function called by findbestmatchingname() if pkg > data
* Also called for FTP matching
*/
int
findbestmatchingname_fn(const char *pattern, const char *found, void *vp)
{
char *best = vp;
char *found_version, *best_version;
char found_no_sfx[PKG_PATTERN_MAX];
char best_no_sfx[PKG_PATTERN_MAX];
/* The same suffix-hack-off again, but we can't do it
* otherwise without changing the function call interface
*/
found_version = strrchr(found, '-');
if (found_version) {
/* skip '-', if any version found */
found_version++;
}
strip_txz(found_no_sfx, NULL, found_version);
found_version = found_no_sfx;
best_version=NULL;
if (best && best[0] != '\0') {
best_version = strrchr(best, '-');
if (best_version) {
/* skip '-' if any version found */
best_version++;
strip_txz(best_no_sfx, NULL, best_version);
best_version = best_no_sfx;
} else {
/* how did this end up in 'best'?
* Shouldn't happen... */
fprintf(stderr,
"'%s' has no usable package(version)\n",
best);
found_version = NULL; /* error out cheaply */
}
}
if (found_version == NULL) {
fprintf(stderr, "'%s' is not a usable package(version)\n",
found);
} else {
/* if best_version==NULL only if best==NULL
* (or best[0]='\0') */
if (best != NULL) {
if (best[0] == '\0' ||
pkg_order(pattern, found_no_sfx, best) == 1) {
/* found pkg(version) is bigger than current "best"
* version - remember! */
strcpy(best, found);
}
}
}
return 0;
}
/*
* Find best matching filename, i.e. the pkg with the highest
* matching(!) version.
* Returns pointer to pkg name (which can be free(3)ed),
* or NULL if no match is available.
*/
char *
findbestmatchingname(const char *dir, const char *pattern)
{
char buf[MaxPathSize];
buf[0] = '\0';
if (findmatchingname(dir, pattern, findbestmatchingname_fn, buf) > 0
&& buf[0] != '\0') {
return strdup(buf);
}
return NULL;
}
/*
* Strip off any .tgz, .tbz or .t[bg]z suffix from fname,
* and copy into buffer "buf", the suffix is stored in "sfx"

View file

@ -1,4 +1,4 @@
/* $NetBSD: version.h,v 1.75 2007/08/10 21:18:32 joerg Exp $ */
/* $NetBSD: version.h,v 1.76 2007/08/12 16:47:19 joerg Exp $ */
/*
* Copyright (c) 2001 Thomas Klausner. All rights reserved.
@ -33,6 +33,6 @@
#ifndef _INST_LIB_VERSION_H_
#define _INST_LIB_VERSION_H_
#define PKGTOOLS_VERSION "20070810"
#define PKGTOOLS_VERSION "20070812"
#endif /* _INST_LIB_VERSION_H_ */