summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoreik <eik@FreeBSD.org>2004-06-29 18:54:47 +0000
committereik <eik@FreeBSD.org>2004-06-29 18:54:47 +0000
commit7923356ae6b0c5daf724f0e5c8844ffec1bb4871 (patch)
tree96259c70ed86c0b116099b99afb26ba9fecc746e
parent649576111eab9cebc8bcde1eb574a9f3644fe2a6 (diff)
downloadFreeBSD-src-7923356ae6b0c5daf724f0e5c8844ffec1bb4871.zip
FreeBSD-src-7923356ae6b0c5daf724f0e5c8844ffec1bb4871.tar.gz
- match package version numbers with relational operators
- use glob patterns when matching packages by origin - csh-style {...} choices in glob matching - pkg_info: new flag -E (list matching package names only) - pkg_version: new flag -T (test if a given name matches a pattern) - new flag -X (interpret pattern as an extended regular expression) PR: 56961
-rw-r--r--usr.sbin/pkg_install/delete/main.c8
-rw-r--r--usr.sbin/pkg_install/delete/perform.c1
-rw-r--r--usr.sbin/pkg_install/delete/pkg_delete.113
-rw-r--r--usr.sbin/pkg_install/info/info.h2
-rw-r--r--usr.sbin/pkg_install/info/main.c14
-rw-r--r--usr.sbin/pkg_install/info/perform.c30
-rw-r--r--usr.sbin/pkg_install/info/pkg_info.124
-rw-r--r--usr.sbin/pkg_install/lib/lib.h3
-rw-r--r--usr.sbin/pkg_install/lib/match.c221
-rw-r--r--usr.sbin/pkg_install/version/main.c22
-rw-r--r--usr.sbin/pkg_install/version/perform.c77
-rw-r--r--usr.sbin/pkg_install/version/pkg_version.134
-rw-r--r--usr.sbin/pkg_install/version/version.h3
13 files changed, 403 insertions, 49 deletions
diff --git a/usr.sbin/pkg_install/delete/main.c b/usr.sbin/pkg_install/delete/main.c
index dcac1d6..c75d73a 100644
--- a/usr.sbin/pkg_install/delete/main.c
+++ b/usr.sbin/pkg_install/delete/main.c
@@ -28,7 +28,7 @@ __FBSDID("$FreeBSD$");
#include "lib.h"
#include "delete.h"
-static char Options[] = "adDfGhinp:rvx";
+static char Options[] = "adDfGhinp:rvxX";
char *Prefix = NULL;
Boolean CleanDirs = FALSE;
@@ -88,6 +88,10 @@ main(int argc, char **argv)
MatchType = MATCH_REGEX;
break;
+ case 'X':
+ MatchType = MATCH_EREGEX;
+ break;
+
case 'i':
Interactive = TRUE;
break;
@@ -151,7 +155,7 @@ static void
usage()
{
fprintf(stderr, "%s\n%s\n",
- "usage: pkg_delete [-dDfGinrvx] [-p prefix] pkg-name ...",
+ "usage: pkg_delete [-dDfGinrvxX] [-p prefix] pkg-name ...",
" pkg_delete -a [flags]");
exit(1);
}
diff --git a/usr.sbin/pkg_install/delete/perform.c b/usr.sbin/pkg_install/delete/perform.c
index dce1260..c1bc803 100644
--- a/usr.sbin/pkg_install/delete/perform.c
+++ b/usr.sbin/pkg_install/delete/perform.c
@@ -64,6 +64,7 @@ pkg_perform(char **pkgs)
case MATCH_ALL:
warnx("no packages installed");
return 0;
+ case MATCH_EREGEX:
case MATCH_REGEX:
warnx("no packages match pattern(s)");
return 1;
diff --git a/usr.sbin/pkg_install/delete/pkg_delete.1 b/usr.sbin/pkg_install/delete/pkg_delete.1
index fbcf752..9c7cc86 100644
--- a/usr.sbin/pkg_install/delete/pkg_delete.1
+++ b/usr.sbin/pkg_install/delete/pkg_delete.1
@@ -17,7 +17,7 @@
.\" @(#)pkg_delete.1
.\" $FreeBSD$
.\"
-.Dd November 25, 1994
+.Dd June 29, 2004
.Dt PKG_DELETE 1
.Os
.Sh NAME
@@ -25,7 +25,7 @@
.Nd a utility for deleting previously installed software package distributions
.Sh SYNOPSIS
.Nm
-.Op Fl dDfGinrvx
+.Op Fl dDfGinrvxX
.Op Fl p Ar prefix
.Ar pkg-name ...
.Nm
@@ -119,6 +119,12 @@ provided, in that case
.Nm
deletes all packages that match at least one
regular expression from the list.
+.It Fl X
+Like
+.Fl x ,
+but treats the
+.Ar pkg-name
+as an extended regular expression.
.It Fl r
Recursive removal. In addition to specified packages, delete all
packages that depend on those packages as well.
@@ -271,6 +277,7 @@ Default location of the installed package database.
.Sh AUTHORS
.An Jordan Hubbard
.Sh CONTRIBUTORS
-.An John Kohl Aq jtk@rational.com
+.An John Kohl Aq jtk@rational.com ,
+.An Oliver Eikemeier Aq eik@FreeBSD.org
.Sh BUGS
Sure to be some.
diff --git a/usr.sbin/pkg_install/info/info.h b/usr.sbin/pkg_install/info/info.h
index 21563ca..926ce2e 100644
--- a/usr.sbin/pkg_install/info/info.h
+++ b/usr.sbin/pkg_install/info/info.h
@@ -50,6 +50,8 @@
#define SHOW_CKSUM 0x04000
#define SHOW_FMTREV 0x08000
#define SHOW_PTREV 0x10000
+#define SHOW_DEPEND 0x20000
+#define SHOW_PKGNAME 0x40000
struct which_entry {
TAILQ_ENTRY(which_entry) next;
diff --git a/usr.sbin/pkg_install/info/main.c b/usr.sbin/pkg_install/info/main.c
index c4860ea..3c2fb44 100644
--- a/usr.sbin/pkg_install/info/main.c
+++ b/usr.sbin/pkg_install/info/main.c
@@ -26,7 +26,7 @@ __FBSDID("$FreeBSD$");
#include "info.h"
#include <err.h>
-static char Options[] = "abcdDe:fgGhiIkl:LmoO:pPqQrRst:vVW:x";
+static char Options[] = "abcdDe:EfgGhiIkl:LmoO:pPqQrRst:vVW:xX";
int Flags = 0;
match_t MatchType = MATCH_GLOB;
@@ -75,6 +75,10 @@ main(int argc, char **argv)
SHOW_DEINSTALL | SHOW_REQUIRE | SHOW_DISPLAY | SHOW_MTREE;
break;
+ case 'E':
+ Flags |= SHOW_PKGNAME;
+ break;
+
case 'I':
Flags |= SHOW_INDEX;
break;
@@ -170,6 +174,10 @@ main(int argc, char **argv)
MatchType = MATCH_REGEX;
break;
+ case 'X':
+ MatchType = MATCH_EREGEX;
+ break;
+
case 'e':
CheckPkg = optarg;
break;
@@ -220,7 +228,7 @@ main(int argc, char **argv)
* Don't try to apply heuristics if arguments are regexs or if
* the argument refers to an existing file.
*/
- if (MatchType != MATCH_REGEX && !isfile(*argv))
+ if (MatchType != MATCH_REGEX && MatchType != MATCH_EREGEX && !isfile(*argv))
while ((pkgs_split = strrchr(*argv, (int)'/')) != NULL) {
*pkgs_split++ = '\0';
/*
@@ -250,7 +258,7 @@ static void
usage()
{
fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
- "usage: pkg_info [-bcdDfgGiIkLmopPqQrRsvVx] [-e package] [-l prefix]",
+ "usage: pkg_info [-bcdDEfgGiIjLmopPqQrRsvVxX] [-e package] [-l prefix]",
" [-t template] -a | pkg-name ...",
" pkg_info [-qQ] -W filename",
" pkg_info [-qQ] -O origin",
diff --git a/usr.sbin/pkg_install/info/perform.c b/usr.sbin/pkg_install/info/perform.c
index f45f7c7..5511f41 100644
--- a/usr.sbin/pkg_install/info/perform.c
+++ b/usr.sbin/pkg_install/info/perform.c
@@ -31,6 +31,7 @@ static int find_pkg(struct which_head *);
static int cmp_path(const char *, const char *, const char *);
static char *abspath(const char *);
static int find_pkgs_by_origin(const char *);
+static int matched_packages(char **pkgs);
int
pkg_perform(char **pkgs)
@@ -42,7 +43,9 @@ pkg_perform(char **pkgs)
signal(SIGINT, cleanup);
/* Overriding action? */
- if (CheckPkg) {
+ if (Flags & SHOW_PKGNAME) {
+ return matched_packages(pkgs);
+ } else if (CheckPkg) {
return isinstalledpkg(CheckPkg) == TRUE ? 0 : 1;
/* Not reached */
} else if (!TAILQ_EMPTY(whead)) {
@@ -67,6 +70,7 @@ pkg_perform(char **pkgs)
return 0;
/* Not reached */
case MATCH_REGEX:
+ case MATCH_EREGEX:
warnx("no packages match pattern(s)");
return 1;
/* Not reached */
@@ -451,3 +455,27 @@ find_pkgs_by_origin(const char *origin)
return 0;
}
+
+/*
+ * List only the matching package names.
+ * Mainly intended for scripts.
+ */
+static int
+matched_packages(char **pkgs)
+{
+ char **matched;
+ int i, errcode;
+
+ matched = matchinstalled(MatchType == MATCH_GLOB ? MATCH_NGLOB : MatchType, pkgs, &errcode);
+
+ if (errcode != 0 || matched == NULL)
+ return 1;
+
+ for (i = 0; matched[i]; i++)
+ if (!Quiet)
+ printf("%s\n", matched[i]);
+ else if (QUIET)
+ printf("%s%s\n", InfoPrefix, matched[i]);
+
+ return 0;
+}
diff --git a/usr.sbin/pkg_install/info/pkg_info.1 b/usr.sbin/pkg_install/info/pkg_info.1
index 9500486..7dfe453 100644
--- a/usr.sbin/pkg_install/info/pkg_info.1
+++ b/usr.sbin/pkg_install/info/pkg_info.1
@@ -25,7 +25,7 @@
.Nd a utility for displaying information on software packages
.Sh SYNOPSIS
.Nm
-.Op Fl bcdDfgGiIkLmopPqQrRsvVx
+.Op Fl bcdDEfgGiIkLmopPqQrRsvVxX
.Op Fl e Ar package
.Op Fl l Ar prefix
.Op Fl t Ar template
@@ -54,6 +54,15 @@ The following command line options are supported:
The named packages are described. A package name may either be the name of
an installed package, the pathname to a package distribution file or a
URL to an FTP available package.
+Package version numbers can also be matched in a relational manner using the
+.Pa \*[Ge], \*[Le], \*[Gt]
+and
+.Pa \*[Lt]
+operators. For example,
+.Pa pkg_info 'portupgrade\*[Ge]20030723'
+will match versions 20030723 and later of the
+.Pa portupgrade
+package.
.It Fl a
Show all currently installed packages.
.It Fl b
@@ -140,12 +149,22 @@ expressions could be provided, in that case
.Nm
displays information about all packages that match at least one
regular expression from the list.
+.It Fl X
+Like
+.Fl x ,
+but treats the
+.Ar pkg-name
+as an extended regular expression.
.It Fl e Ar pkg-name
If the package identified by
.Ar pkg-name
is currently installed, return 0, otherwise return 1. This option
allows you to easily test for the presence of another (perhaps
prerequisite) package from a script.
+.It Fl E
+Show only matching package names. This option takes
+precedence over all other package formatting options.
+If any packages match, return 0, otherwise return 1.
.It Fl l Ar str
Prefix each information category header (see
.Fl q )
@@ -236,6 +255,7 @@ Default location of the installed package database.
.Sh AUTHORS
.An Jordan Hubbard
.Sh CONTRIBUTORS
-.An John Kohl Aq jtk@rational.com
+.An John Kohl Aq jtk@rational.com ,
+.An Oliver Eikemeier Aq eik@FreeBSD.org
.Sh BUGS
Sure to be some.
diff --git a/usr.sbin/pkg_install/lib/lib.h b/usr.sbin/pkg_install/lib/lib.h
index 5690314..50c3d40 100644
--- a/usr.sbin/pkg_install/lib/lib.h
+++ b/usr.sbin/pkg_install/lib/lib.h
@@ -105,7 +105,7 @@ enum _plist_t {
typedef enum _plist_t plist_t;
enum _match_t {
- MATCH_ALL, MATCH_EXACT, MATCH_GLOB, MATCH_REGEX
+ MATCH_ALL, MATCH_EXACT, MATCH_GLOB, MATCH_NGLOB, MATCH_EREGEX, MATCH_REGEX
};
typedef enum _match_t match_t;
@@ -206,6 +206,7 @@ int real_main(int, char **);
char **matchinstalled(match_t, char **, int *);
char **matchbyorigin(const char *, int *);
int isinstalledpkg(const char *name);
+int pattern_match(match_t MatchType, char *pattern, const char *pkgname);
/* Dependencies */
int sortdeps(char **);
diff --git a/usr.sbin/pkg_install/lib/match.c b/usr.sbin/pkg_install/lib/match.c
index 27db978..0cd9853 100644
--- a/usr.sbin/pkg_install/lib/match.c
+++ b/usr.sbin/pkg_install/lib/match.c
@@ -37,14 +37,15 @@ struct store {
char **store;
};
-static int rex_match(const char *, const char *);
+static int rex_match(const char *, const char *, int);
+static int csh_match(const char *, const char *, int);
struct store *storecreate(struct store *);
static int storeappend(struct store *, const char *);
static int fname_cmp(const FTSENT * const *, const FTSENT * const *);
/*
* Function to query names of installed packages.
- * MatchType - one of MATCH_ALL, MATCH_REGEX, MATCH_GLOB;
+ * MatchType - one of MATCH_ALL, MATCH_EREGEX, MATCH_REGEX, MATCH_GLOB, MATCH_NGLOB;
* patterns - NULL-terminated list of glob or regex patterns
* (could be NULL for MATCH_ALL);
* retval - return value (could be NULL if you don't want/need
@@ -108,22 +109,11 @@ matchinstalled(match_t MatchType, char **patterns, int *retval)
matched = f->fts_name;
else
for (i = 0; patterns[i]; i++) {
- switch (MatchType) {
- case MATCH_REGEX:
- errcode = rex_match(patterns[i], f->fts_name);
- if (errcode == 1) {
- matched = f->fts_name;
- errcode = 0;
- }
- break;
- case MATCH_GLOB:
- if (fnmatch(patterns[i], f->fts_name, 0) == 0) {
- matched = f->fts_name;
- lmatched[i] = TRUE;
- }
- break;
- default:
- break;
+ errcode = pattern_match(MatchType, patterns[i], f->fts_name);
+ if (errcode == 1) {
+ matched = f->fts_name;
+ lmatched[i] = TRUE;
+ errcode = 0;
}
if (matched != NULL || errcode != 0)
break;
@@ -153,6 +143,96 @@ matchinstalled(match_t MatchType, char **patterns, int *retval)
return store->store;
}
+int
+pattern_match(match_t MatchType, char *pattern, const char *pkgname)
+{
+ int errcode = 0;
+ const char *fname = pkgname;
+ char basefname[PATH_MAX];
+ char condchar = '\0';
+ char *condition;
+
+ /* do we have an appended condition? */
+ condition = strpbrk(pattern, "<>=");
+ if (condition) {
+ const char *ch;
+ /* yes, isolate the pattern from the condition ... */
+ if (condition > pattern && condition[-1] == '!')
+ condition--;
+ condchar = *condition;
+ *condition = '\0';
+ /* ... and compare the name without version */
+ ch = strrchr(fname, '-');
+ if (ch && ch - fname < PATH_MAX) {
+ strlcpy(basefname, fname, ch - fname + 1);
+ fname = basefname;
+ }
+ }
+
+ switch (MatchType) {
+ case MATCH_EREGEX:
+ case MATCH_REGEX:
+ errcode = rex_match(pattern, fname, MatchType == MATCH_EREGEX ? 1 : 0);
+ break;
+ case MATCH_NGLOB:
+ case MATCH_GLOB:
+ errcode = (csh_match(pattern, fname, 0) == 0) ? 1 : 0;
+ break;
+ case MATCH_EXACT:
+ errcode = (strcmp(pattern, fname) == 0) ? 1 : 0;
+ break;
+ case MATCH_ALL:
+ errcode = 1;
+ break;
+ default:
+ break;
+ }
+
+ /* loop over all appended conditions */
+ while (condition) {
+ /* restore the pattern */
+ *condition = condchar;
+ /* parse the condition (fun with bits) */
+ if (errcode == 1) {
+ char *nextcondition;
+ /* compare version numbers */
+ int match = 0;
+ if (*++condition == '=') {
+ match = 2;
+ condition++;
+ }
+ switch(condchar) {
+ case '<':
+ match |= 1;
+ break;
+ case '>':
+ match |= 4;
+ break;
+ case '=':
+ match |= 2;
+ break;
+ case '!':
+ match = 5;
+ break;
+ }
+ /* isolate the version number from the next condition ... */
+ nextcondition = strpbrk(condition, "<>=!");
+ if (nextcondition) {
+ condchar = *nextcondition;
+ *nextcondition = '\0';
+ }
+ /* and compare the versions (version_cmp removes the filename for us) */
+ if ((match & (1 << (version_cmp(pkgname, condition) + 1))) == 0)
+ errcode = 0;
+ condition = nextcondition;
+ } else {
+ break;
+ }
+ }
+
+ return errcode;
+}
+
/*
* Synopsis is similar to matchinstalled(), but use origin
* as a key for matching packages.
@@ -193,10 +273,8 @@ matchbyorigin(const char *origin, int *retval)
snprintf(tmp, PATH_MAX, "%s/%s", tmp, CONTENTS_FNAME);
fp = fopen(tmp, "r");
if (fp == NULL) {
- warn("%s", tmp);
- if (retval != NULL)
- *retval = 1;
- return NULL;
+ warnx("the package info for package '%s' is corrupt", installed[i]);
+ continue;
}
cmd = -1;
@@ -212,7 +290,7 @@ matchbyorigin(const char *origin, int *retval)
continue;
cmd = plist_cmd(tmp + 1, &cp);
if (cmd == PLIST_ORIGIN) {
- if (strcmp(origin, cp) == 0)
+ if (csh_match(origin, cp, FNM_PATHNAME) == 0)
storeappend(store, installed[i]);
break;
}
@@ -255,7 +333,7 @@ isinstalledpkg(const char *name)
* engine reported an error (usually invalid syntax).
*/
static int
-rex_match(const char *pattern, const char *pkgname)
+rex_match(const char *pattern, const char *pkgname, int extended)
{
char errbuf[128];
int errcode;
@@ -264,7 +342,7 @@ rex_match(const char *pattern, const char *pkgname)
retval = 0;
- errcode = regcomp(&rex, pattern, REG_BASIC | REG_NOSUB);
+ errcode = regcomp(&rex, pattern, (extended ? REG_EXTENDED : REG_BASIC) | REG_NOSUB);
if (errcode == 0)
errcode = regexec(&rex, pkgname, 0, NULL, 0);
@@ -282,6 +360,99 @@ rex_match(const char *pattern, const char *pkgname)
}
/*
+ * Match string by a csh-style glob pattern. Returns 0 on
+ * match and FNM_NOMATCH otherwise, to be compatible with
+ * fnmatch(3).
+ */
+static int
+csh_match(const char *pattern, const char *string, int flags)
+{
+ int ret = FNM_NOMATCH;
+
+
+ const char *nextchoice = pattern;
+ const char *current = NULL;
+
+ int prefixlen = -1;
+ int currentlen = 0;
+
+ int level = 0;
+
+ do {
+ const char *pos = nextchoice;
+ const char *postfix = NULL;
+
+ Boolean quoted = FALSE;
+
+ nextchoice = NULL;
+
+ do {
+ const char *eb;
+ if (!*pos) {
+ postfix = pos;
+ } else if (quoted) {
+ quoted = FALSE;
+ } else {
+ switch (*pos) {
+ case '{':
+ ++level;
+ if (level == 1) {
+ current = pos+1;
+ prefixlen = pos-pattern;
+ }
+ break;
+ case ',':
+ if (level == 1 && !nextchoice) {
+ nextchoice = pos+1;
+ currentlen = pos-current;
+ }
+ break;
+ case '}':
+ if (level == 1) {
+ postfix = pos+1;
+ if (!nextchoice)
+ currentlen = pos-current;
+ }
+ level--;
+ break;
+ case '[':
+ eb = pos+1;
+ if (*eb == '!' || *eb == '^')
+ eb++;
+ if (*eb == ']')
+ eb++;
+ while(*eb && *eb != ']')
+ eb++;
+ if (*eb)
+ pos=eb;
+ break;
+ case '\\':
+ quoted = TRUE;
+ break;
+ default:
+ ;
+ }
+ }
+ pos++;
+ } while (!postfix);
+
+ if (current) {
+ char buf[FILENAME_MAX];
+ snprintf(buf, sizeof(buf), "%.*s%.*s%s", prefixlen, pattern, currentlen, current, postfix);
+ ret = csh_match(buf, string, flags);
+ if (ret) {
+ current = nextchoice;
+ level = 1;
+ } else
+ current = NULL;
+ } else
+ ret = fnmatch(pattern, string, flags);
+ } while (current);
+
+ return ret;
+}
+
+/*
* Create an empty store, optionally deallocating
* any previously allocated space if store != NULL.
*/
diff --git a/usr.sbin/pkg_install/version/main.c b/usr.sbin/pkg_install/version/main.c
index cbc6a9e..39ea37f 100644
--- a/usr.sbin/pkg_install/version/main.c
+++ b/usr.sbin/pkg_install/version/main.c
@@ -25,11 +25,12 @@ __FBSDID("$FreeBSD$");
#include "version.h"
#include <err.h>
-static char Options[] = "dhl:L:s:tv";
+static char Options[] = "dhl:L:s:XtTv";
char *LimitChars = NULL;
char *PreventChars = NULL;
char *MatchName = NULL;
+Boolean RegexExtended = FALSE;
static void usage __P((void));
@@ -43,6 +44,10 @@ main(int argc, char **argv)
printf(cmp > 0 ? ">\n" : (cmp < 0 ? "<\n" : "=\n"));
exit(0);
}
+ else if (argc == 4 && !strcmp(argv[1], "-T")) {
+ cmp = version_match(argv[3], argv[2]);
+ exit(cmp == 1 ? 0 : 1);
+ }
else while ((ch = getopt(argc, argv, Options)) != -1) {
switch(ch) {
case 'v':
@@ -65,6 +70,14 @@ main(int argc, char **argv)
errx(2, "Invalid -t usage.");
break;
+ case 'T':
+ errx(2, "Invalid -T usage.");
+ break;
+
+ case 'X':
+ RegexExtended = TRUE;
+ break;
+
case 'h':
case '?':
default:
@@ -82,8 +95,9 @@ main(int argc, char **argv)
static void
usage()
{
- fprintf(stderr, "%s\n%s\n",
- "usage: pkg_version [-hv] [-l limchar] [-L limchar] [-s string] index",
- " pkg_version -t v1 v2");
+ fprintf(stderr, "%s\n%s\n%s\n",
+ "usage: pkg_version [-hv] [-l limchar] [-L limchar] [[-X] -s string] index",
+ " pkg_version -t v1 v2",
+ " pkg_version -T name pattern");
exit(1);
}
diff --git a/usr.sbin/pkg_install/version/perform.c b/usr.sbin/pkg_install/version/perform.c
index 8643dd2..df166f6 100644
--- a/usr.sbin/pkg_install/version/perform.c
+++ b/usr.sbin/pkg_install/version/perform.c
@@ -67,7 +67,7 @@ pkg_perform(char **indexarg)
if (MatchName != NULL) {
pat[0] = MatchName;
pat[1] = NULL;
- MatchType = MATCH_REGEX;
+ MatchType = RegexExtended ? MATCH_EREGEX : MATCH_REGEX;
patterns = pat;
}
else {
@@ -83,6 +83,7 @@ pkg_perform(char **indexarg)
case MATCH_ALL:
warnx("no packages installed");
return (0);
+ case MATCH_EREGEX:
case MATCH_REGEX:
warnx("no packages match pattern");
return (1);
@@ -308,6 +309,80 @@ show_version(const char *installed, const char *latest, const char *source)
}
}
+int
+version_match(char *pattern, const char *pkgname)
+{
+ int ret = 0;
+ int matchstream = 0;
+ FILE *fp = NULL;
+ Boolean isTMP = FALSE;
+
+ if (isURL(pkgname)) {
+ fp = fetchGetURL(pkgname, "");
+ isTMP = TRUE;
+ matchstream = 1;
+ if (fp == NULL)
+ errx(2, "Unable to open %s.", pkgname);
+ } else if (pkgname[0] == '/') {
+ fp = fopen(pkgname, "r");
+ isTMP = TRUE;
+ matchstream = 1;
+ if (fp == NULL)
+ errx(2, "Unable to open %s.", pkgname);
+ } else if (strcmp(pkgname, "-") == 0) {
+ fp = stdin;
+ matchstream = 1;
+ } else if (isURL(pattern)) {
+ fp = fetchGetURL(pattern, "");
+ isTMP = TRUE;
+ matchstream = -1;
+ if (fp == NULL)
+ errx(2, "Unable to open %s.", pattern);
+ } else if (pattern[0] == '/') {
+ fp = fopen(pattern, "r");
+ isTMP = TRUE;
+ matchstream = -1;
+ if (fp == NULL)
+ errx(2, "Unable to open %s.", pattern);
+ } else if (strcmp(pattern, "-") == 0) {
+ fp = stdin;
+ matchstream = -1;
+ } else {
+ ret = pattern_match(MATCH_GLOB, pattern, pkgname);
+ }
+
+ if (fp != NULL) {
+ size_t len;
+ char *line;
+ while ((line = fgetln(fp, &len)) != NULL) {
+ int match;
+ char *ch, ln[2048];
+ size_t lnlen;
+ if (len > 0 && line[len-1] == '\n')
+ len --;
+ lnlen = len;
+ if (lnlen > sizeof(ln)-1)
+ lnlen = sizeof(ln)-1;
+ memcpy(ln, line, lnlen);
+ ln[lnlen] = '\0';
+ if ((ch = strchr(ln, '|')) != NULL)
+ ch[0] = '\0';
+ if (matchstream > 0)
+ match = pattern_match(MATCH_GLOB, pattern, ln);
+ else
+ match = pattern_match(MATCH_GLOB, ln, pkgname);
+ if (match == 1) {
+ ret = 1;
+ printf("%.*s\n", (int)len, line);
+ }
+ }
+ if (isTMP)
+ fclose(fp);
+ }
+
+ return ret;
+}
+
void
cleanup(int sig)
{
diff --git a/usr.sbin/pkg_install/version/pkg_version.1 b/usr.sbin/pkg_install/version/pkg_version.1
index 3f03997..ac1ac91 100644
--- a/usr.sbin/pkg_install/version/pkg_version.1
+++ b/usr.sbin/pkg_install/version/pkg_version.1
@@ -24,7 +24,7 @@
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $FreeBSD$
-.Dd July 17, 1998
+.Dd June 29, 2004
.Dt PKG_VERSION 1
.Os
.Sh NAME
@@ -35,10 +35,15 @@
.Op Fl hv
.Op Fl l Ar limchar
.Op Fl L Ar limchar
-.Op Fl s Ar string
+.Oo
+.Op Fl X
+.Fl s Ar string
+.Oc
.Op Ar index
.Nm
.Op Fl t Ar version1 version2
+.Nm
+.Op Fl T Ar pkgname pattern
.Sh DESCRIPTION
The
.Nm
@@ -134,6 +139,10 @@ with single quotes.
.It Fl s
Limit the output to those packages whose names match a given
.Ar string .
+.It Fl X
+Interpret
+.Ar string
+as a extended regular expression.
.It Fl t
Test a pair of version number strings and exit.
The output consists of one of the single characters
@@ -144,6 +153,16 @@ The output consists of one of the single characters
.Li \&>
(left-hand number greater) on standard output.
This flag is mostly useful for scripts or for testing.
+.It Fl T
+Test whether
+.Ar pkgname
+is matched by
+.Ar pattern
+and set the exit code accordingly.
+.Fl T
+can also be used in `filter mode':
+When one of the arguments is `-', standard input is used, and lines
+with matching package names/patterns are echoed to standard output.
.It Fl v
Enable verbose output. Verbose output includes some English-text
interpretations of the version number comparisons, as well as the
@@ -157,7 +176,7 @@ URL understandable by
can be used here. If no
.Ar index
file is specified on the command line,
-.Pa /usr/ports/INDEX
+.Pa /usr/ports/INDEX-5
is used.
.El
.Sh COMPATIBILITY
@@ -171,8 +190,8 @@ option has been deprecated and is no longer supported.
.Xr pkg_delete 1 ,
.Xr pkg_info 1
.Sh FILES
-.Bl -tag -width /usr/ports/INDEX -compact
-.It Pa /usr/ports/INDEX
+.Bl -tag -width /usr/ports/INDEX-5 -compact
+.It Pa /usr/ports/INDEX-5
Default index file.
.El
.Sh EXAMPLES
@@ -186,7 +205,7 @@ index file:
The command below generates a report against
the version numbers in the on-line ports collection:
.Pp
-.Dl % pkg_version ftp://ftp.FreeBSD.org/pub/FreeBSD/branches/-current/ports/INDEX
+.Dl % pkg_version http://www.FreeBSD.org/ports/INDEX-5
.Pp
The following command compares two package version strings:
.Pp
@@ -203,4 +222,5 @@ partially based on a Perl script written by
.An Dominic Mitchell Aq dom@palmerharvey.co.uk ,
.An Mark Ovens Aq marko@FreeBSD.org ,
.An Doug Barton Aq DougB@gorean.org ,
-.An Akinori MUSHA Aq knu@FreeBSD.org
+.An Akinori MUSHA Aq knu@FreeBSD.org ,
+.An Oliver Eikemeier Aq eik@FreeBSD.org
diff --git a/usr.sbin/pkg_install/version/version.h b/usr.sbin/pkg_install/version/version.h
index daaebb0..3f3bcb8 100644
--- a/usr.sbin/pkg_install/version/version.h
+++ b/usr.sbin/pkg_install/version/version.h
@@ -40,5 +40,8 @@ SLIST_HEAD(index_head, index_entry);
extern char *LimitChars;
extern char *PreventChars;
extern char *MatchName;
+extern Boolean RegexExtended;
+
+extern int version_match(char *, const char *);
#endif /* _INST_VERSION_H_INCLUDE */
OpenPOWER on IntegriCloud