Skip site navigation (1)Skip section navigation (2)
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>