Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

PATCH: zsh 3.x: <..> ranges in globbing

Geoff Wing wrote:
> Geoff Wing <mason@xxxxxxxxxxxxxxx> typed:
> :% touch 101 111 121
> :% ls <10-12>1
> :ls: <10-12>1: No such file or directory
> :Now, it's obvious why it's failing, since 101, 111 & 121 don't match the
> :10 to 12 range.  My opinion is that it probably shouldn't fail in this case,
> :but maybe a different operator or option/modifier should be used to get it
> :to match. since there may be cases where someone wants to match on, say,
> :``<1-50>foo'' and not get, say, ``100foo'' matching.
>  ``<1-50>*oo'' and ``100foo'' might be better examples.

This is the fix.  This is entirely consistent with the way globbing
usually works, I don't think a new operator is needed.  If you want to make 
<1-50>*oo avoid matching 100foo, you will need <1-50>([^0-9]*|)oo (to
be pedantic).  I don't think it's fair to force <a-b> to consider only
all the digits present, since it's not consistent with the usual pattern
rule 'use as many characters as possible without causing the match to
fail', even if it is the current behaviour.  Is anyone sure that
they rely on <1-50>*oo not matching 100foo?  The old behaviour is
tantamount to making * not match 0foo, which is counterintuitive.  As
far as I can remember I've always been careful to anchor the end of a
numeric range for just this reason, not realising there was a bug.

You should probably note that <100->0foo won't match 1000foo, since
the 1000 gets swallowed up before the shell even knows it's going
to have to match another digit next. This is a much more difficult
problem requiring backtracking.  I could make a special case so that
simple things like this work, but expressions like <100->(0|bar)foo would
require much more fiddling.  (Of course, <100-999>0foo works now.)

*** Src/glob.c.range	Mon Jan 12 10:41:46 1998
--- Src/glob.c	Mon Jan 12 10:41:57 1998
*** 2265,2270 ****
--- 2265,2271 ----
  	    } else {
  		/* Flag that there is no upper limit */
  		int not3 = 0;
+ 		char *opptr = pptr;
  		 * Form is <a-b>, where a or b are numbers or blank.
  		 * t1 = number supplied:  must be positive, so use
*** 2284,2289 ****
--- 2285,2299 ----
  		    t3 = (unsigned long)zstrtol(ptr + 1, &pat, 10);
  		DPUTS(*pat != Outang, "BUG: wrong internal range pattern");
+ 		/*
+ 		 * If the number found is too large for the pattern,
+ 		 * try matching just the first part.  This way
+ 		 * we always get the longest possible match.
+ 		 */
+ 		while (!not3 && t1 > t3 && pptr > opptr+1) {
+ 		  pptr--;
+ 		  t1 /= 10;
+ 		}
  		if (t1 < t2 || (!not3 && t1 > t3))

Peter Stephenson <pws@xxxxxx>       Tel: +39 50 911239
WWW:  http://www.ifh.de/~pws/
Gruppo Teorico, Dipartimento di Fisica
Piazza Torricelli 2, 56100 Pisa, Italy

Messages sorted by: Reverse Date, Date, Thread, Author