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

size glob qualifier patch



In message #346, Subject: Re: zshexpn(1) doc suggestion,
Peter Stephenson <P.Stephenson@xxxxxxxxxxxxx> wrote:

>This is not exactly relevant, but I've always wanted the L (size)
>qualifier to accept k or m (or K or M) as modifiers.  I never seem to
>want to check for anything smaller than about 50k, in which case
>zeros proliferate.

This is maybe not exactly what you want, but it is easy to mimic
the behaviour of find(1)'s -size option, with modifiers similiar
to those used by the time glob qualifiers. The relevant part of
the zshexpn.1 man page would then read: 

              L[+|-]n
                     files  less  than  n  bytes (-), more than n
                     bytes (+), or exactly n bytes in length.  If
                     this flag is directly followed by a k (K), m
                     (M), or p (P) (e.g. Lk+50) the check is per-
                     formed  with kilobytes, megabytes, or blocks
                     (of 512 bytes) instead.

Since I'm used to the use of Kbyte (2^10) to denote the difference
to the SI-prefix k (10^3), it seems preferable to accept these
modifiers case-insensitive.

What this patch does. Data is passed to the qual*() functions by
means of parameter, and of a couple of static vars. Of those, which
are reloaded each time before a different function is called, `timef'
as time multiplier was renamed to `units' and serves now as size mul-
tiplier, too. In qualsize(), the range adjustment for e.g.

       `*(Lk1)' == `find . -size 1k' == 1 .. 1024 bytes

is done by adding factor-1 before the division by factor, thus re-
quiring an unsigned var. For size qualifier without unit modifier,
operation hasn't changed.

Side notes:

o  The size code has still a hard limit, in that it will break when
   there are filesizes greater than One Less Than Two Gigabytes
   (2^31-1) on machines with 32-bit longs. What about POSIX (off_t)?

o  Is it considered useful to have Yet Another Globbing Qualifier,
   e.g. B, for size globbing based on the real amount of disk space
   used, as opposed to the `length' of possibly sparse files now?
   Cf. du(1)

o  Would it be fun if there was a zsh shell function as a find(1)-
   compatible front-end, or converter, to zsh's globbing capabilities?
   That is, long option names are easier to remember than one-letter
   qualifiers.


This is for hzoli10.3, but should also apply to plain zsh-2.6-beta10.

*** Doc/zshexpn.1.ORIG	Wed Sep 20 16:33:57 1995
--- Doc/zshexpn.1	Fri Sep 22 15:27:48 1995
***************
*** 643,649 ****
  .TP
  \fBL\fI[+|-]n\fR
  files less than n bytes (-), more than n bytes (+), or
! exactly n bytes in length.
  .TP
  \fB^\fP
  negates all qualifiers following it
--- 643,652 ----
  .TP
  \fBL\fI[+|-]n\fR
  files less than n bytes (-), more than n bytes (+), or
! exactly n bytes in length. If this flag is directly followed by a \fBk\fP
! (\fBK\fP), \fBm\fP (\fBM\fP), or \fBp\fP (\fBP\fP) (e.g. \fBLk+50\fP)
! the check is performed with kilobytes, megabytes, or blocks (of 512 bytes)
! instead.
  .TP
  \fB^\fP
  negates all qualifiers following it
*** Src/glob.c.ORIG	Wed Sep 20 16:34:03 1995
--- Src/glob.c	Fri Sep 22 15:17:38 1995
***************
*** 49,60 ****
--- 49,67 ----
  typedef struct stat *Statptr;	 /* This makes the Ultrix compiler happy.  Go figure. */
  #endif
  
+ /* modifier for unit conversions */
+ 
  #define TT_DAYS 0
  #define TT_HOURS 1
  #define TT_MINS 2
  #define TT_WEEKS 3
  #define TT_MONTHS 4
  
+ #define TT_BYTES 0
+ #define TT_POSIX_BLOCKS 1
+ #define TT_KILOBYTES 2
+ #define TT_MEGABYTES 3
+ 
  /* max # of qualifiers */
  
  typedef int (*TestMatchFunc) _((struct stat *, long));
***************
*** 67,73 ****
      int sense;			/* Whether asserting or negating             */
      int amc;			/* Flag for which time to test (a, m, c)     */
      int range;			/* Whether to test <, > or = (as per signum) */
!     int timef;			/* Multiplier for time                       */
  };
  
  /* Qualifiers pertaining to current pattern */
--- 74,80 ----
      int sense;			/* Whether asserting or negating             */
      int amc;			/* Flag for which time to test (a, m, c)     */
      int range;			/* Whether to test <, > or = (as per signum) */
!     int units;			/* Multiplier for time or size, respectively */
  };
  
  /* Qualifiers pertaining to current pattern */
***************
*** 75,81 ****
  
  /* Other state values for current pattern */
  static int qualct, qualorct;
! static int range, amc, timef;
  static int gf_nullglob, gf_markdirs, gf_noglobdots, gf_listtypes;
  
  /* Prefix, suffix for doing zle trickery */
--- 82,88 ----
  
  /* Other state values for current pattern */
  static int qualct, qualorct;
! static int range, amc, units;
  static int gf_nullglob, gf_markdirs, gf_noglobdots, gf_listtypes;
  
  /* Prefix, suffix for doing zle trickery */
***************
*** 436,453 ****
  			/* File size (Length) in given range */
  			func = qualsize;
  			amc = -1;
  		      getrange:
- 			timef = TT_DAYS;
  			/* Get time multiplier */
! 			if (amc >= 0)
  			    if (*s == 'h')
! 				timef = TT_HOURS, ++s;
  			    else if (*s == 'm')
! 				timef = TT_MINS, ++s;
  			    else if (*s == 'w')
! 				timef = TT_WEEKS, ++s;
  			    else if (*s == 'M')
! 				timef = TT_MONTHS, ++s;
  			/* See if it's greater than, equal to, or less than */
  			if ((range = *s == '+' ? 1 : *s == '-' ? -1 : 0))
  			    ++s;
--- 443,469 ----
  			/* File size (Length) in given range */
  			func = qualsize;
  			amc = -1;
+ 			/* Get size multiplier */
+ 			units = TT_BYTES;
+ 			if (*s == 'p' || *s == 'P')
+ 			    units = TT_POSIX_BLOCKS, ++s;
+ 			else if (*s == 'k' || *s == 'K')
+ 			    units = TT_KILOBYTES, ++s;
+ 			else if (*s == 'm' || *s == 'M')
+ 			    units = TT_MEGABYTES, ++s;
  		      getrange:
  			/* Get time multiplier */
! 			if (amc >= 0) {
! 			    units = TT_DAYS;
  			    if (*s == 'h')
! 				units = TT_HOURS, ++s;
  			    else if (*s == 'm')
! 				units = TT_MINS, ++s;
  			    else if (*s == 'w')
! 				units = TT_WEEKS, ++s;
  			    else if (*s == 'M')
! 				units = TT_MONTHS, ++s;
! 			}
  			/* See if it's greater than, equal to, or less than */
  			if ((range = *s == '+' ? 1 : *s == '-' ? -1 : 0))
  			    ++s;
***************
*** 471,477 ****
  		    qn->sense = sense;
  		    qn->data = data;
  		    qn->range = range;
! 		    qn->timef = timef;
  		    qn->amc = amc;
  		    qn = NULL;
  		    qualct++;
--- 487,493 ----
  		    qn->sense = sense;
  		    qn->data = data;
  		    qn->range = range;
! 		    qn->units = units;
  		    qn->amc = amc;
  		    qn = NULL;
  		    qualct++;
***************
*** 656,662 ****
  		for (qn = qo; t && qn && qn->func; qn = qn->next) {
  		    range = qn->range;
  		    amc = qn->amc;
! 		    timef = qn->timef;
  		    if ((qn->sense & 2) && !statted) {
  			/* If (sense & 2), we're following links */
  			statted = 1;
--- 672,678 ----
  		for (qn = qo; t && qn && qn->func; qn = qn->next) {
  		    range = qn->range;
  		    amc = qn->amc;
! 		    units = qn->units;
  		    if ((qn->sense & 2) && !statted) {
  			/* If (sense & 2), we're following links */
  			statted = 1;
***************
*** 2239,2247 ****
  int
  qualsize(struct stat *buf, long size)
  {
!     return (range < 0 ? buf->st_size < size :
! 	    range > 0 ? buf->st_size > size :
! 	    buf->st_size == size);
  }
  
  /* time in required range? */
--- 2255,2280 ----
  int
  qualsize(struct stat *buf, long size)
  {
!     unsigned long scaled = buf->st_size;
! 
!     switch (units) {
!     case TT_POSIX_BLOCKS:
! 	scaled += 511l;
! 	scaled /= 512l;
! 	break;
!     case TT_KILOBYTES:
! 	scaled += 1023l;
! 	scaled /= 1024l;
! 	break;
!     case TT_MEGABYTES:
! 	scaled += 1048575l;
! 	scaled /= 1048576l;
! 	break;
!     }
! 
!     return (range < 0 ? scaled < size :
! 	    range > 0 ? scaled > size :
! 	    scaled == size);
  }
  
  /* time in required range? */
***************
*** 2256,2262 ****
      diff = now - (amc == 0 ? buf->st_atime : amc == 1 ? buf->st_mtime :
  		  buf->st_ctime);
      /* handle multipliers indicating units */
!     switch (timef) {
      case TT_DAYS:
  	diff /= 86400l;
  	break;
--- 2289,2295 ----
      diff = now - (amc == 0 ? buf->st_atime : amc == 1 ? buf->st_mtime :
  		  buf->st_ctime);
      /* handle multipliers indicating units */
!     switch (units) {
      case TT_DAYS:
  	diff /= 86400l;
  	break;

-- 
Thorsten Meinecke
<kaefer@xxxxxxxxxxxxxxx> 



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