From 7923356ae6b0c5daf724f0e5c8844ffec1bb4871 Mon Sep 17 00:00:00 2001 From: eik Date: Tue, 29 Jun 2004 18:54:47 +0000 Subject: [PATCH] - 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 --- usr.sbin/pkg_install/delete/main.c | 8 +- usr.sbin/pkg_install/delete/perform.c | 1 + usr.sbin/pkg_install/delete/pkg_delete.1 | 13 +- usr.sbin/pkg_install/info/info.h | 2 + usr.sbin/pkg_install/info/main.c | 14 +- usr.sbin/pkg_install/info/perform.c | 30 ++- usr.sbin/pkg_install/info/pkg_info.1 | 24 ++- usr.sbin/pkg_install/lib/lib.h | 3 +- usr.sbin/pkg_install/lib/match.c | 221 ++++++++++++++++++--- usr.sbin/pkg_install/version/main.c | 22 +- usr.sbin/pkg_install/version/perform.c | 77 ++++++- usr.sbin/pkg_install/version/pkg_version.1 | 34 +++- usr.sbin/pkg_install/version/version.h | 3 + 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 dcac1d67d384..c75d73a627a1 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 dce12607c73b..c1bc80352b18 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 fbcf752b9e9c..9c7cc86de629 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 21563ca0c0a1..926ce2e9c52d 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 c4860ea19f3a..3c2fb4444d79 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 -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 f45f7c7c6316..5511f418d9dd 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 95004869cc6f..7dfe453cb6d4 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 56903145a9cc..50c3d40ead49 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 27db97827d50..0cd98535c3b3 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); @@ -281,6 +359,99 @@ rex_match(const char *pattern, const char *pkgname) return retval; } +/* + * 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 cbc6a9e844c0..39ea37facb3d 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 -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 8643dd2b1fe0..df166f6d09de 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 3f0399765b3f..ac1ac91b1bf1 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 daaebb0e97b4..3f3bcb88c57d 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 */