* Re: PATCH: suggestion for new glob modifiers
[not found] <199901251328.OAA16371@beta.informatik.hu-berlin.de>
@ 1999-01-25 13:34 ` Peter Stephenson
0 siblings, 0 replies; 3+ messages in thread
From: Peter Stephenson @ 1999-01-25 13:34 UTC (permalink / raw)
To: Zsh hackers list
Sven sent me this and suggested I forwarded it to the list...
Peter Stephenson wrote:
> ...
>
> One minor question is whether (Om) etc. should really be oldest first.
> I can see that's logical --- `time order' certainly implies oldest
> first --- but unfortunately it's the other way round from ls -t, which
> is the order I've grown to expect. I can easily get used to using ^,
> though.
Funny, I was worrying about this, too, and for the same reason
(comparison with `ls -t'). Maybe it's better to change it.
Bye
Sven
*** os/glob.c Mon Jan 25 12:07:41 1999
--- Src/glob.c Mon Jan 25 14:22:09 1999
***************
*** 1038,1050 ****
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;
--- 1038,1050 ----
r = b->size - a->size;
break;
case GS_ATIME:
! r = a->atime - b->atime;
break;
case GS_MTIME:
! r = a->mtime - b->mtime;
break;
case GS_CTIME:
! r = a->ctime - b->ctime;
break;
case GS_LINKS:
r = b->links - a->links;
***************
*** 1053,1065 ****
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;
--- 1053,1065 ----
r = b->_size - a->_size;
break;
case GS__ATIME:
! r = a->_atime - b->_atime;
break;
case GS__MTIME:
! r = a->_mtime - b->_mtime;
break;
case GS__CTIME:
! r = a->_ctime - b->_ctime;
break;
case GS__LINKS:
r = b->_links - a->_links;
*** od/Zsh/expn.yo Mon Jan 25 12:07:48 1999
--- Doc/Zsh/expn.yo Mon Jan 25 14:24:33 1999
***************
*** 1128,1134 ****
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.
--- 1128,1136 ----
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 tt(a), tt(m), and tt(c) compare
! the age with to the current time, so the first name in the list is the
! one of the youngest file. Also 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.
--
Sven Wischnowsky wischnow@informatik.hu-berlin.de
^ permalink raw reply [flat|nested] 3+ messages in thread
* PATCH: suggestion for new glob modifiers
@ 1999-01-25 11:06 Sven Wischnowsky
1999-01-25 12:51 ` Peter Stephenson
0 siblings, 1 reply; 3+ messages in thread
From: Sven Wischnowsky @ 1999-01-25 11:06 UTC (permalink / raw)
To: zsh-workers
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
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: PATCH: suggestion for new glob modifiers
1999-01-25 11:06 Sven Wischnowsky
@ 1999-01-25 12:51 ` Peter Stephenson
0 siblings, 0 replies; 3+ messages in thread
From: Peter Stephenson @ 1999-01-25 12:51 UTC (permalink / raw)
To: zsh-workers
Sven Wischnowsky wrote:
>
> 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.
This is excellent --- I've been using completion trickery for things
like this, but this is very much more flexible.
One minor question is whether (Om) etc. should really be oldest first.
I can see that's logical --- `time order' certainly implies oldest
first --- but unfortunately it's the other way round from ls -t, which
is the order I've grown to expect. I can easily get used to using ^,
though.
--
Peter Stephenson <pws@ibmth.df.unipi.it> Tel: +39 050 844536
WWW: http://www.ifh.de/~pws/
Dipartimento di Fisica, Via Buonarroti 2, 56127 Pisa, Italy
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~1999-01-25 13:34 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
[not found] <199901251328.OAA16371@beta.informatik.hu-berlin.de>
1999-01-25 13:34 ` PATCH: suggestion for new glob modifiers Peter Stephenson
1999-01-25 11:06 Sven Wischnowsky
1999-01-25 12:51 ` Peter Stephenson
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).