zsh-workers
 help / color / mirror / code / Atom feed
From: Sven Wischnowsky <wischnow@informatik.hu-berlin.de>
To: zsh-workers@sunsite.auc.dk
Subject: PATCH: suggestion for new glob modifiers
Date: Mon, 25 Jan 1999 12:06:56 +0100 (MET)	[thread overview]
Message-ID: <199901251106.MAA12163@beta.informatik.hu-berlin.de> (raw)


This implements something I missed a long time...

1) A new glob modifier that allows to make the resulting list sorted
   not only by name. The syntax is `Oc' where `c' is a character
   saying how the list should be sorted:

   `n'           - by name
   `L'           - by size (length)
   `l'           - by number of links
   `a', `m', ac' - by access, modification, or inode change time

   The modifiers `^' and `-' are respected, so `*(^OL^On)' gives you a 
   list sorted largest file first, with files with the same size being 
   sorted by name in ascending order.

2) The second change is that you can give subscripts in modifier lists 
   which say which matches you want to get. The subscripts are as for
   arrays *without* the flags. If you use flags, the globbing code
   will take the modifier list as a pattern and return something you
   probably won't want. Maybe we should make this return an error.
   Example: `*(^OL[1,3])' gives you the names of the three biggest
   files.

This patch should work with all versions that have associative arrays
(due to the hunks in params.c which are needed to allow the globbing
code to easily use getindex() with a struct value which contains no
param-pointer).

Any comments?

Bye
 Sven

*** os/glob.c	Mon Jan 25 10:22:39 1999
--- Src/glob.c	Mon Jan 25 11:52:16 1999
***************
*** 31,37 ****
  #include "glob.pro"
  
  /* flag for CSHNULLGLOB */
!  
  /**/
  int badcshglob;
   
--- 31,72 ----
  #include "glob.pro"
  
  /* flag for CSHNULLGLOB */
! 
! typedef struct gmatch *Gmatch; 
! 
! struct gmatch {
!     char *name;
!     long size;
!     long atime;
!     long mtime;
!     long ctime;
!     long links;
!     long _size;
!     long _atime;
!     long _mtime;
!     long _ctime;
!     long _links;
! };
! 
! #define GS_NAME   1
! #define GS_SIZE   2
! #define GS_ATIME  4
! #define GS_MTIME  8
! #define GS_CTIME 16
! #define GS_LINKS 32
! 
! #define GS_SHIFT  5
! #define GS__SIZE  (GS_SIZE << GS_SHIFT)
! #define GS__ATIME (GS_ATIME << GS_SHIFT)
! #define GS__MTIME (GS_MTIME << GS_SHIFT)
! #define GS__CTIME (GS_CTIME << GS_SHIFT)
! #define GS__LINKS (GS_LINKS << GS_SHIFT)
! 
! #define GS_DESC  2048
! 
! #define GS_NORMAL (GS_SIZE | GS_ATIME | GS_MTIME | GS_CTIME | GS_LINKS)
! #define GS_LINKED (GS_NORMAL << GS_SHIFT)
! 
  /**/
  int badcshglob;
   
***************
*** 42,49 ****
  static char *pathbuf;		/* pathname buffer                      */
  static int pathbufsz;		/* size of pathbuf			*/
  static int pathbufcwd;		/* where did we chdir()'ed		*/
! static char **matchbuf;		/* array of matches                     */
! static char **matchptr;		/* &matchbuf[matchct]                   */
  static char *colonmod;		/* colon modifiers in qualifier list    */
  
  typedef struct stat *Statptr;	 /* This makes the Ultrix compiler happy.  Go figure. */
--- 77,84 ----
  static char *pathbuf;		/* pathname buffer                      */
  static int pathbufsz;		/* size of pathbuf			*/
  static int pathbufcwd;		/* where did we chdir()'ed		*/
! static Gmatch matchbuf;		/* array of matches                     */
! static Gmatch matchptr;		/* &matchbuf[matchct]                   */
  static char *colonmod;		/* colon modifiers in qualifier list    */
  
  typedef struct stat *Statptr;	 /* This makes the Ultrix compiler happy.  Go figure. */
***************
*** 81,86 ****
--- 116,122 ----
  static int qualct, qualorct;
  static int range, amc, units;
  static int gf_nullglob, gf_markdirs, gf_noglobdots, gf_listtypes, gf_follow;
+ static int gf_sorts, gf_nsorts, gf_sortlist[11];
  
  /* Prefix, suffix for doing zle trickery */
  
***************
*** 213,218 ****
--- 249,255 ----
  
  	if (!statted && statfullpath(s, &buf, 1))
  	    return;
+ 	statted = 1;
  	qo = quals;
  	for (qn = qo; qn && qn->func;) {
  	    range = qn->range;
***************
*** 237,255 ****
  	    }
  	    qn = qn->next;
  	}
!     } else if (!checked && statfullpath(s, NULL, 1))
! 	return;
! 
      news = dyncat(pathbuf, news);
      if (colonmod) {
  	/* Handle the remainder of the qualifer:  e.g. (:r:s/foo/bar/). */
  	s = colonmod;
  	modify(&news, &s);
      }
!     *matchptr++ = news;
      if (++matchct == matchsz) {
! 	matchbuf = (char **)realloc((char *)matchbuf,
! 				    sizeof(char **) * (matchsz *= 2));
  
  	matchptr = matchbuf + matchct;
      }
--- 274,317 ----
  	    }
  	    qn = qn->next;
  	}
!     } else if (!checked) {
! 	if (statfullpath(s, NULL, 1))
! 	    return;
! 	statted = 1;
!     }
      news = dyncat(pathbuf, news);
      if (colonmod) {
  	/* Handle the remainder of the qualifer:  e.g. (:r:s/foo/bar/). */
  	s = colonmod;
  	modify(&news, &s);
      }
!     if (!statted && (gf_sorts & GS_NORMAL)) {
! 	statfullpath(s, &buf, 1);
! 	statted = 1;
!     }
!     if (statted != 2 && (gf_sorts & GS_LINKED)) {
! 	if (statted) {
! 	    if (!S_ISLNK(buf.st_mode) || statfullpath(s, &buf2, 0))
! 		memcpy(&buf2, &buf, sizeof(buf));
! 	} else if (statfullpath(s, &buf2, 0))
! 	    statfullpath(s, &buf2, 1);
!     }
!     matchptr->name = news;
!     matchptr->size = buf.st_size;
!     matchptr->atime = buf.st_atime;
!     matchptr->mtime = buf.st_mtime;
!     matchptr->ctime = buf.st_ctime;
!     matchptr->links = buf.st_nlink;
!     matchptr->_size = buf2.st_size;
!     matchptr->_atime = buf2.st_atime;
!     matchptr->_mtime = buf2.st_mtime;
!     matchptr->_ctime = buf2.st_ctime;
!     matchptr->_links = buf2.st_nlink;
!     matchptr++;
! 
      if (++matchct == matchsz) {
! 	matchbuf = (Gmatch )realloc((char *)matchbuf,
! 				    sizeof(struct gmatch) * (matchsz *= 2));
  
  	matchptr = matchbuf + matchct;
      }
***************
*** 961,966 ****
--- 1023,1076 ----
      return v;
  }
  
+ static int
+ gmatchcmp(Gmatch a, Gmatch b)
+ {
+     int i, *s;
+     long r;
+ 
+     for (i = gf_nsorts, s = gf_sortlist; i; i--, s++) {
+ 	switch (*s & ~GS_DESC) {
+ 	case GS_NAME:
+ 	    r = notstrcmp(&a->name, &b->name);
+ 	    break;
+ 	case GS_SIZE:
+ 	    r = b->size - a->size;
+ 	    break;
+ 	case GS_ATIME:
+ 	    r = b->atime - a->atime;
+ 	    break;
+ 	case GS_MTIME:
+ 	    r = b->mtime - a->mtime;
+ 	    break;
+ 	case GS_CTIME:
+ 	    r = b->ctime - a->ctime;
+ 	    break;
+ 	case GS_LINKS:
+ 	    r = b->links - a->links;
+ 	    break;
+ 	case GS__SIZE:
+ 	    r = b->_size - a->_size;
+ 	    break;
+ 	case GS__ATIME:
+ 	    r = b->_atime - a->_atime;
+ 	    break;
+ 	case GS__MTIME:
+ 	    r = b->_mtime - a->_mtime;
+ 	    break;
+ 	case GS__CTIME:
+ 	    r = b->_ctime - a->_ctime;
+ 	    break;
+ 	case GS__LINKS:
+ 	    r = b->_links - a->_links;
+ 	    break;
+ 	}
+ 	if (r)
+ 	    return (int) ((*s & GS_DESC) ? -r : r);
+     }
+     return 0;
+ }
+ 
  /* Main entry point to the globbing code for filename globbing. *
   * np points to a node in the list list which will be expanded  *
   * into a series of nodes.                                      */
***************
*** 976,982 ****
      Complist q;				/* pattern after parsing         */
      char *ostr = (char *)getdata(np);	/* the pattern before the parser */
  					/* chops it up                   */
! 
      MUSTUSEHEAP("glob");
      if (unset(GLOBOPT) || !haswilds(ostr)) {
  	untokenize(ostr);
--- 1086,1093 ----
      Complist q;				/* pattern after parsing         */
      char *ostr = (char *)getdata(np);	/* the pattern before the parser */
  					/* chops it up                   */
!     int first = 0, last = -1;		/* index of first/last match to  */
! 				        /* return */
      MUSTUSEHEAP("glob");
      if (unset(GLOBOPT) || !haswilds(ostr)) {
  	untokenize(ostr);
***************
*** 994,999 ****
--- 1105,1111 ----
      gf_markdirs = isset(MARKDIRS);
      gf_listtypes = gf_follow = 0;
      gf_noglobdots = unset(GLOBDOTS);
+     gf_sorts = gf_nsorts = 0;
  
      /* Check for qualifiers */
      if (isset(BAREGLOBQUAL) && str[sl - 1] == Outpar) {
***************
*** 1315,1320 ****
--- 1427,1477 ----
  			data = qgetnum(&s);
  			break;
  
+ 		    case 'O':
+ 			{
+ 			    int t;
+ 
+ 			    switch (*s) {
+ 			    case 'n': t = GS_NAME; break;
+ 			    case 'L': t = GS_SIZE; break;
+ 			    case 'l': t = GS_LINKS; break;
+ 			    case 'a': t = GS_ATIME; break;
+ 			    case 'm': t = GS_MTIME; break;
+ 			    case 'c': t = GS_CTIME; break;
+ 			    default:
+ 				zerr("unknown sort specifier", NULL, 0);
+ 				return;
+ 			    }
+ 			    if ((sense & 2) && t != GS_NAME)
+ 				t <<= GS_SHIFT;
+ 			    if (gf_sorts & t) {
+ 				zerr("doubled sort specifier", NULL, 0);
+ 				return;
+ 			    }
+ 			    gf_sorts |= t;
+ 			    gf_sortlist[gf_nsorts++] = t |
+ 				((sense & 1) ? GS_DESC : 0);
+ 			    s++;
+ 			    break;
+ 			}
+ 		    case '[':
+ 		    case Inbrack:
+ 			{
+ 			    char *os = --s;
+ 			    struct value v;
+ 
+ 			    v.isarr = SCANPM_WANTVALS;
+ 			    v.pm = NULL;
+ 			    v.b = -1;
+ 			    v.inv = 0;
+ 			    if (getindex(&s, &v) || s == os) {
+ 				zerr("invalid subscript", NULL, 0);
+ 				return;
+ 			    }
+ 			    first = v.a;
+ 			    last = v.b;
+ 			    break;
+ 			}
  		    default:
  			zerr("unknown file attribute", NULL, 0);
  			return;
***************
*** 1353,1362 ****
  	zerr("bad pattern: %s", ostr, 0);
  	return;
      }
! 
      /* Initialise receptacle for matched files, *
       * expanded by insert() where necessary.    */
!     matchptr = matchbuf = (char **)zalloc((matchsz = 16) * sizeof(char *));
      matchct = 0;
  
      /* The actual processing takes place here: matches go into  *
--- 1510,1523 ----
  	zerr("bad pattern: %s", ostr, 0);
  	return;
      }
!     if (!gf_nsorts) {
! 	gf_sortlist[0] = gf_sorts = GS_NAME;
! 	gf_nsorts = 1;
!     }
      /* Initialise receptacle for matched files, *
       * expanded by insert() where necessary.    */
!     matchptr = matchbuf = (Gmatch)zalloc((matchsz = 16) *
! 					 sizeof(struct gmatch));
      matchct = 0;
  
      /* The actual processing takes place here: matches go into  *
***************
*** 1375,1392 ****
  	    return;
  	} else {
  	    /* treat as an ordinary string */
! 	    untokenize(*matchptr++ = dupstring(ostr));
  	    matchct = 1;
  	}
      }
      /* Sort arguments in to lexical (and possibly numeric) order. *
       * This is reversed to facilitate insertion into the list.    */
!     qsort((void *) & matchbuf[0], matchct, sizeof(char *),
! 	       (int (*) _((const void *, const void *)))notstrcmp);
  
!     matchptr = matchbuf;
!     while (matchct--)		/* insert matches in the arg list */
! 	insertlinknode(list, node, *matchptr++);
      free(matchbuf);
  }
  
--- 1536,1567 ----
  	    return;
  	} else {
  	    /* treat as an ordinary string */
! 	    untokenize(matchptr->name = dupstring(ostr));
! 	    matchptr++;
  	    matchct = 1;
  	}
      }
      /* Sort arguments in to lexical (and possibly numeric) order. *
       * This is reversed to facilitate insertion into the list.    */
!     qsort((void *) & matchbuf[0], matchct, sizeof(struct gmatch),
! 	       (int (*) _((const void *, const void *)))gmatchcmp);
  
!     if (first < 0)
! 	first += matchct;
!     if (last < 0)
! 	last += matchct;
!     if (first < 0)
! 	first = 0;
!     if (last >= matchct)
! 	last = matchct - 1;
!     if (first <= last) {
! 	matchptr = matchbuf + matchct - 1 - last;
! 	last -= first;
! 	while (last-- >= 0) {		/* insert matches in the arg list */
! 	    insertlinknode(list, node, matchptr->name);
! 	    matchptr++;
! 	}
!     }
      free(matchbuf);
  }
  
*** os/params.c	Mon Jan 25 10:22:41 1999
--- Src/params.c	Mon Jan 25 11:52:16 1999
***************
*** 679,685 ****
      Comp c;
  
      /* first parse any subscription flags */
!     if (*s == '(' || *s == Inpar) {
  	int escapes = 0;
  	int waste;
  	for (s++; *s != ')' && *s != Outpar && s != *str; s++) {
--- 679,685 ----
      Comp c;
  
      /* first parse any subscription flags */
!     if (v->pm && *s == '(' || *s == Inpar) {
  	int escapes = 0;
  	int waste;
  	for (s++; *s != ')' && *s != Outpar && s != *str; s++) {
***************
*** 765,771 ****
  	} else if (rev) {
  	    v->isarr |= SCANPM_WANTVALS;
  	}
! 	if (!down && PM_TYPE(v->pm->flags) == PM_HASHED)
  	    v->isarr &= ~SCANPM_MATCHMANY;
  	*inv = ind;
      }
--- 765,771 ----
  	} else if (rev) {
  	    v->isarr |= SCANPM_WANTVALS;
  	}
! 	if (!down && v->pm && PM_TYPE(v->pm->flags) == PM_HASHED)
  	    v->isarr &= ~SCANPM_MATCHMANY;
  	*inv = ind;
      }
***************
*** 785,791 ****
      singsub(&s);
  
      if (!rev) {
! 	if (PM_TYPE(v->pm->flags) == PM_HASHED) {
  	    HashTable ht = v->pm->gets.hfn(v->pm);
  	    if (!ht) {
  		ht = newparamtable(17, v->pm->nam);
--- 785,791 ----
      singsub(&s);
  
      if (!rev) {
! 	if (v->pm && PM_TYPE(v->pm->flags) == PM_HASHED) {
  	    HashTable ht = v->pm->gets.hfn(v->pm);
  	    if (!ht) {
  		ht = newparamtable(17, v->pm->nam);
*** od/Zsh/expn.yo	Mon Jan 25 10:22:13 1999
--- Doc/Zsh/expn.yo	Mon Jan 25 11:52:17 1999
***************
*** 1122,1127 ****
--- 1122,1146 ----
  sets the tt(GLOB_DOTS) option for the current pattern
  pindex(GLOB_DOTS, setting in pattern)
  )
+ item(tt(O)var(c))(
+ specifies how the names of the files should be sorted. If var(c) is
+ tt(n) they are sorted by name (the default), if var(c) is tt(L) they
+ are sorted depending on the size (length) of the files, tt(l) makes
+ them be sorted by the number of links, and tt(a), tt(m), and tt(c)
+ make them be sorted by the time of the last access, modification, and
+ inode change respectively. Note that the modifiers tt(^) and tt(-) are 
+ used, so `tt(*(^-OL))' gives a list of all files sorted by file size in 
+ descending order working not on symbolic links but on the files they
+ point to.
+ )
+ item(tt([)var(beg)[tt(,)var(end)]tt(]))(
+ specifies which of the matched filenames should be included in the
+ returned list. The syntax is the same as for array
+ subscripts. var(beg) and the optional var(end) may be mathematical
+ expressions. As in parameter subscripting they may be negative to make 
+ them count from the last match backward. E.g.: `tt(*(^-OL[1,3]))'
+ gives a list of the names of three biggest files.
+ )
  enditem()
  
  More than one of these lists can be combined, separated by commas. The

--
Sven Wischnowsky                         wischnow@informatik.hu-berlin.de


             reply	other threads:[~1999-01-25 11:06 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
1999-01-25 11:06 Sven Wischnowsky [this message]
1999-01-25 12:51 ` Peter Stephenson
     [not found] <199901251328.OAA16371@beta.informatik.hu-berlin.de>
1999-01-25 13:34 ` Peter Stephenson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=199901251106.MAA12163@beta.informatik.hu-berlin.de \
    --to=wischnow@informatik.hu-berlin.de \
    --cc=zsh-workers@sunsite.auc.dk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).