- 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
This commit is contained in:
parent
136b0d0b52
commit
6372c5ec85
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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 **);
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user