Date: Tue, 06 Feb 2001 17:50:10 +0200 From: Maxim Sobolev <sobomax@FreeBSD.org> To: Jordan Hubbard <jkh@winston.osd.bsdi.com>, Peter Pentchev <roam@orbitel.bg>, ports@FreeBSD.org, jkh@FreeBSD.org, Edwin Groothuis <mavetju@chello.nl> Subject: Re: Request for comments [Fwd: bin/24695: [patch] pkg_info: prefix search for a package] Message-ID: <3A801D32.DE73F780@FreeBSD.org> References: <10197.981450491@winston.osd.bsdi.com> <3A7FC36A.1434D2CC@FreeBSD.org>
next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format. --------------3B04EE5576164C2D792A2419 Content-Type: text/plain; charset=koi8-r Content-Transfer-Encoding: 7bit Maxim Sobolev wrote: > Jordan Hubbard wrote: > > > > but was away from e-mail) ;). What do you think if I reimplement 'fuzzy' and > > > 'prefix' options from original proposal into `glob' and `regex' options? So > > > regex kidz would be able say "-x .*foo.*", while glob-lovers "-g *foo*". > > > > I love it. You could even make -g "implicit", e.g. I don't see any > > reason why "pkg_info emacs*" shouldn't just work, right? The only > > time you really need to pass a flag is to indicate a particular type > > of globbing, e.g. regex. > > Agreed. I already have globbing in place, so expect patches soon ;). Here it is. With this patch pkg_install treats any arguments as shell globs by default and as regexs with -x, so for example the following is equivalent: $ pkg_info foo\* $ pkg_info -x ^foo.\* Please let me know what do you think about those patches. -Maxim --------------3B04EE5576164C2D792A2419 Content-Type: text/plain; charset=koi8-r; name="pkg_info-glob+regex.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="pkg_info-glob+regex.diff" Index: info.h =================================================================== RCS file: /home/ncvs/src/usr.sbin/pkg_install/info/info.h,v retrieving revision 1.16 diff -d -u -r1.16 info.h --- info.h 2001/02/05 09:56:52 1.16 +++ info.h 2001/02/06 15:17:39 @@ -47,12 +47,18 @@ #define SHOW_ORIGIN 0x2000 #define SHOW_CKSUM 0x4000 +enum _match_t { + MATCH_ALL, MATCH_EXACT, MATCH_GLOB, MATCH_REGEX +}; + +typedef enum _match_t match_t; + extern int Flags; -extern Boolean AllInstalled; extern Boolean Quiet; extern char *InfoPrefix; extern char PlayPen[]; extern char *CheckPkg; +extern match_t MatchType; extern void show_file(char *, char *); extern void show_plist(char *, Package *, plist_t); Index: main.c =================================================================== RCS file: /home/ncvs/src/usr.sbin/pkg_install/info/main.c,v retrieving revision 1.28 diff -d -u -r1.28 main.c --- main.c 2001/02/03 20:56:32 1.28 +++ main.c 2001/02/06 15:17:39 @@ -28,9 +28,10 @@ "$FreeBSD$"; #endif -static char Options[] = "acdDe:fghiIkl:LmopqrRst:v"; +static char Options[] = "acdDe:fgGhiIkl:LmopqrRst:vx"; int Flags = 0; +match_t MatchType = MATCH_GLOB; Boolean AllInstalled = FALSE; Boolean Quiet = FALSE; char *InfoPrefix = ""; @@ -54,7 +55,7 @@ else while ((ch = getopt(argc, argv, Options)) != -1) { switch(ch) { case 'a': - AllInstalled = TRUE; + MatchType = MATCH_ALL; break; case 'v': @@ -92,6 +93,10 @@ Flags |= SHOW_CKSUM; break; + case 'G': + MatchType = MATCH_EXACT; + break; + case 'i': Flags |= SHOW_INSTALL; break; @@ -116,9 +121,9 @@ Flags |= SHOW_MTREE; break; - case 's': - Flags |= SHOW_SIZE; - break; + case 's': + Flags |= SHOW_SIZE; + break; case 'o': Flags |= SHOW_ORIGIN; @@ -136,6 +141,10 @@ strcpy(PlayPen, optarg); break; + case 'x': + MatchType = MATCH_REGEX; + break; + case 'e': CheckPkg = optarg; break; @@ -157,18 +166,22 @@ /* Get all the remaining package names, if any */ while (*argv) { - while ((pkgs_split = strrchr(*argv, (int)'/')) != NULL) { - *pkgs_split++ = '\0'; - /* - * If character after the '/' is alphanumeric, then we've found the - * package name. Otherwise we've come across a trailing '/' and - * need to continue our quest. - */ - if (isalpha(*pkgs_split)) { - *argv = pkgs_split; - break; + /* Don't try to apply heuristics if arguments are regexs */ + if (MatchType != MATCH_REGEX) + while ((pkgs_split = strrchr(*argv, (int)'/')) != NULL) { + *pkgs_split++ = '\0'; + /* + * If character after the '/' is alphanumeric or shell + * metachar, then we've found the package name. Otherwise + * we've come across a trailing '/' and need to continue our + * quest. + */ + if (isalpha(*pkgs_split) || ((MatchType == MATCH_GLOB) && \ + strpbrk(pkgs_split, "*?[]") != NULL)) { + *argv = pkgs_split; + break; + } } - } *pkgs++ = *argv++; } Index: perform.c =================================================================== RCS file: /home/ncvs/src/usr.sbin/pkg_install/info/perform.c,v retrieving revision 1.33 diff -d -u -r1.33 perform.c --- perform.c 2001/02/03 20:56:32 1.33 +++ perform.c 2001/02/06 15:17:39 @@ -26,12 +26,16 @@ #include "lib.h" #include "info.h" +#include <sys/types.h> +#include <err.h> +#include <glob.h> #include <fts.h> +#include <regex.h> #include <signal.h> -#include <err.h> static int fname_cmp(const FTSENT **, const FTSENT **); static int pkg_do(char *); +static int rexs_match(char **, char *); int pkg_perform(char **pkgs) @@ -50,31 +54,93 @@ snprintf(buf, FILENAME_MAX, "%s/%s", tmp, CheckPkg); return abs(access(buf, R_OK)); + /* Not reached */ } - else if (AllInstalled) { - FTS *ftsp; - FTSENT *f; - char *paths[2]; - if (!isdir(tmp)) - return 1; - paths[0] = tmp; - paths[1] = NULL; - ftsp = fts_open(paths, FTS_LOGICAL | FTS_NOCHDIR | FTS_NOSTAT, - fname_cmp); - if (ftsp != NULL) { - while ((f = fts_read(ftsp)) != NULL) { - if (f->fts_info == FTS_D && f->fts_level == 1) { - err_cnt += pkg_do(f->fts_name); - fts_set(ftsp, f, FTS_SKIP); + switch (MatchType) { + case MATCH_ALL: + case MATCH_REGEX: + { + FTS *ftsp; + FTSENT *f; + char *paths[2]; + int errcode; + + if (!isdir(tmp)) + return 1; + paths[0] = tmp; + paths[1] = NULL; + ftsp = fts_open(paths, FTS_LOGICAL | FTS_NOCHDIR | FTS_NOSTAT, + fname_cmp); + if (ftsp != NULL) { + while ((f = fts_read(ftsp)) != NULL) { + if (f->fts_info == FTS_D && f->fts_level == 1) { + fts_set(ftsp, f, FTS_SKIP); + if (MatchType == MATCH_REGEX) { + errcode = rexs_match(pkgs, f->fts_name); + if (errcode == -1) { + err_cnt += 1; + break; + } + else if (errcode == 0) + continue; + } + err_cnt += pkg_do(f->fts_name); + } } + fts_close(ftsp); } - fts_close(ftsp); } - } - else + break; + case MATCH_GLOB: + { + glob_t g; + char *gexpr; + char *cp; + int gflags; + int prev_matchc; + + gflags = GLOB_ERR; + prev_matchc = 0; + for (i = 0; pkgs[i]; i++) { + asprintf(&gexpr, "%s/%s", tmp, pkgs[i]); + + if (glob(gexpr, gflags, NULL, &g) != 0) { + warn("%s: error encountered when matching glob", pkgs[i]); + return 1; + } + + /* + * If glob doesn't match try to use pkgs[i] directly - it + * could be name of the tarball. + */ + if (g.gl_matchc == prev_matchc) + err_cnt += pkg_do(pkgs[i]); + + prev_matchc = g.gl_matchc; + gflags |= GLOB_APPEND; + free(gexpr); + } + + for (i = 0; i < g.gl_matchc; i++) { + cp = strrchr(g.gl_pathv[i], '/'); + if (cp == NULL) + cp = g.gl_pathv[i]; + else + cp++; + + err_cnt += pkg_do(cp); + } + + globfree(&g); + } + break; + default: for (i = 0; pkgs[i]; i++) err_cnt += pkg_do(pkgs[i]); + break; + } + return err_cnt; } @@ -227,7 +293,7 @@ if (!in_cleanup) { in_cleanup = 1; - leave_playpen(); + leave_playpen(); } if (sig) exit(1); @@ -237,4 +303,53 @@ fname_cmp(const FTSENT **a, const FTSENT **b) { return strcmp((*a)->fts_name, (*b)->fts_name); +} + +/* + * Return 1 if specified pkgname matches at least one + * of the RE from patterns. Otherwise return 0 if no + * matches were found or -1 if RE engine reported an + * error (usually invalid syntax). + */ +static int +rexs_match(char **patterns, char *pkgname) +{ + Boolean matched; + char errbuf[128]; + int i; + int errcode; + int retval; + regex_t rex; + + errcode = 0; + retval = 0; + matched = FALSE; + for (i = 0; patterns[i]; i++) { + errcode = regcomp(&rex, patterns[i], REG_BASIC | REG_NOSUB); + if (errcode != 0) + break; + + errcode = regexec(&rex, pkgname, 0, NULL, 0); + if (errcode == 0) { + matched = TRUE; + retval = 1; + break; + } + else if (errcode != REG_NOMATCH) + break; + + regfree(&rex); + errcode = 0; + } + + if (errcode != 0) { + regerror(errcode, &rex, errbuf, sizeof(errbuf)); + warnx("%s: %s", patterns[i], errbuf); + retval = -1; + } + + if ((errcode != 0) || (matched == TRUE)) + regfree(&rex); + + return retval; } Index: pkg_info.1 =================================================================== RCS file: /home/ncvs/src/usr.sbin/pkg_install/info/pkg_info.1,v retrieving revision 1.33 diff -d -u -r1.33 pkg_info.1 --- pkg_info.1 2001/02/03 20:56:32 1.33 +++ pkg_info.1 2001/02/06 15:17:39 @@ -25,7 +25,7 @@ .Nd a utility for displaying information on software packages .Sh SYNOPSIS .Nm -.Op Fl cdDfgiIkLmopqrRsv +.Op Fl cdDfgGiIkLmopqrRsvx .Op Fl e Ar package .Op Fl l Ar prefix .Op Fl t Ar template @@ -98,6 +98,23 @@ package was generated, is located in the .Fx .Em "Ports Collection" . +.It Fl G +Do not try to expand shell glob patterns in the +.Ar pkg-name +when selecting packages to be displayed (by default +.Nm +automatically expands shell glob patterns in the +.Ar pkg-name +). +.It Fl x +Treat the +.Ar pkg-name +as a regular expression and display information only for packages +matching that regular expression. Multiple regular 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 e Ar pkg-name If the package identified by .Ar pkg-name --------------3B04EE5576164C2D792A2419-- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-ports" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?3A801D32.DE73F780>