1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-09-02 22:11:54 +02:00

Michael Hwang: 26731 with cosmetic changes: add "a" and "A" modifiers

26736: document the above
This commit is contained in:
Peter Stephenson 2009-03-15 01:17:05 +00:00
parent bf25c3a43f
commit 7733ade831
4 changed files with 190 additions and 19 deletions

View file

@ -1,3 +1,10 @@
2009-03-15 Peter Stephenson <p.w.stephenson@ntlworld.com>
* 26736: Doc/Zsh/expn.yo: document 26731.
* Michael Hwang: 26731 (with cosmetic changes): Src/hist.c,
Src/subst.c: add `a' and `A' modifiers.
2009-03-14 Wayne Davison <wayned@users.sourceforge.net>
* 26735: Src/Modules/files.c, Src/Modules/mapfile.c,
@ -11409,5 +11416,5 @@
*****************************************************
* This is used by the shell to define $ZSH_PATCHLEVEL
* $Revision: 1.4617 $
* $Revision: 1.4618 $
*****************************************************

View file

@ -216,20 +216,24 @@ of em(filename generation) and em(parameter expansion), except where
noted.
startitem()
item(tt(h))(
Remove a trailing pathname component, leaving the head. This works
like `tt(dirname)'.
item(tt(a))(
Turn a file name into an absolute path: prepends the current directory,
if necessary, and resolves any use of `tt(..)' and `tt(.)' in the path.
)
item(tt(r))(
Remove a filename extension of the form `tt(.)var(xxx)', leaving
the root name.
item(tt(A))(
As `tt(a)', but also resolve use of symbolic links where possible.
Note that resolution of `tt(..)' occurs em(before) resolution of symbolic
links.
)
item(tt(e))(
Remove all but the extension.
)
item(tt(t))(
Remove all leading pathname components, leaving the tail. This works
like `tt(basename)'.
item(tt(h))(
Remove a trailing pathname component, leaving the head. This works
like `tt(dirname)'.
)
item(tt(l))(
Convert the words to all lowercase.
)
item(tt(p))(
Print the new command but do not execute it. Only works with history
@ -244,15 +248,9 @@ by tt(eval).
item(tt(Q))(
Remove one level of quotes from the substituted words.
)
item(tt(x))(
Like tt(q), but break into words at whitespace. Does not work with
parameter expansion.
)
item(tt(l))(
Convert the words to all lowercase.
)
item(tt(u))(
Convert the words to all uppercase.
item(tt(r))(
Remove a filename extension of the form `tt(.)var(xxx)', leaving
the root name.
)
item(tt(s/)var(l)tt(/)var(r)[tt(/)])(
Substitute var(r) for var(l) as described below.
@ -272,6 +270,17 @@ immediately by a tt(g). In parameter expansion the tt(&) must appear
inside braces, and in filename generation it must be quoted with a
backslash.
)
item(tt(t))(
Remove all leading pathname components, leaving the tail. This works
like `tt(basename)'.
)
item(tt(u))(
Convert the words to all uppercase.
)
item(tt(x))(
Like tt(q), but break into words at whitespace. Does not work with
parameter expansion.
)
enditem()
The tt(s/l/r/) substitution works as follows. By default the left-hand

View file

@ -623,6 +623,21 @@ histsubchar(int c)
case 'p':
histdone = HISTFLAG_DONE | HISTFLAG_NOEXEC;
break;
case 'a':
if (!chabspath(&sline)) {
herrflush();
zerr("modifier failed: a");
return -1;
}
break;
case 'A':
if (!chrealpath(&sline)) {
herrflush();
zerr("modifier failed: A");
return -1;
}
break;
case 'h':
if (!remtpath(&sline)) {
herrflush();
@ -1482,6 +1497,132 @@ hcomsearch(char *str)
/* various utilities for : modifiers */
/**/
int
chabspath(char **junkptr)
{
char *current, *dest;
if (!**junkptr)
return 1;
if (**junkptr != '/') {
*junkptr = zhtricat(zgetcwd(), "/", *junkptr);
}
current = *junkptr;
dest = *junkptr;
#ifdef HAVE_SUPERROOT
while (*current == '/' && current[1] == '.' && current[2] == '.' &&
(!current[3] || current[3] == '/')) {
*dest++ = '/';
*dest++ = '.';
*dest++ = '.';
current += 3;
}
#endif
for (;;) {
if (*current == '/') {
#ifdef __CYGWIN__
if (current == *junkptr && current[1] == '/')
*dest++ = *current++;
#endif
*dest++ = *current++;
while (*current == '/')
current++;
} else if (!*current) {
while (dest > *junkptr + 1 && dest[-1] == '/')
dest--;
*dest = '\0';
break;
} else if (current[0] == '.' && current[1] == '.' &&
(!current[2] || current[2] == '/')) {
if (current == *junkptr || dest == *junkptr) {
*dest++ = '.';
*dest++ = '.';
current += 2;
} else if (dest > *junkptr + 2 &&
!strncmp(dest - 3, "../", 3)) {
*dest++ = '.';
*dest++ = '.';
current += 2;
} else if (dest > *junkptr + 1) {
*dest = '\0';
for (dest--;
dest > *junkptr + 1 && dest[-1] != '/';
dest--);
if (dest[-1] != '/')
dest--;
current += 2;
} else if (dest == *junkptr + 1) {
/* This might break with Cygwin's leading double slashes? */
current += 2;
} else {
return 0;
}
} else if (current[0] == '.' && (current[1] == '/' || !current[1])) {
while (*++current == '/');
} else {
while (*current != '/' && *current != '\0')
if ((*dest++ = *current++) == Meta)
dest[-1] = *current++ ^ 32;
}
}
return 1;
}
/**/
int
chrealpath(char **junkptr)
{
char *lastpos, *nonreal, real[PATH_MAX];
if (!**junkptr)
return 1;
/* Notice that this means ..'s are applied before symlinks are resolved! */
if (!chabspath(junkptr))
return 0;
/*
* Notice that this means you cannot pass relative paths into this
* function!
*/
if (**junkptr != '/')
return 0;
lastpos = strend(*junkptr);
nonreal = lastpos + 1;
while (!realpath(*junkptr, real)) {
if (errno == EINVAL || errno == ELOOP ||
errno == ENAMETOOLONG || errno == ENOMEM)
return 0;
if (nonreal == *junkptr) {
*real = '\0';
break;
}
while (*nonreal != '/' && nonreal >= *junkptr)
nonreal--;
*nonreal = '\0';
}
char *str = nonreal;
while (str <= lastpos) {
if (*str == '\0')
*str = '/';
str++;
}
*junkptr = bicat(real, nonreal);
return 1;
}
/**/
int
remtpath(char **junkptr)

View file

@ -3199,6 +3199,8 @@ modify(char **str, char **ptr)
for (; !c && **ptr;) {
switch (**ptr) {
case 'a':
case 'A':
case 'h':
case 'r':
case 'e':
@ -3337,6 +3339,12 @@ modify(char **str, char **ptr)
copy = dupstring(tt);
*e = tc;
switch (c) {
case 'a':
chabspath(&copy);
break;
case 'A':
chrealpath(&copy);
break;
case 'h':
remtpath(&copy);
break;
@ -3396,6 +3404,12 @@ modify(char **str, char **ptr)
} else {
switch (c) {
case 'a':
chabspath(str);
break;
case 'A':
chrealpath(str);
break;
case 'h':
remtpath(str);
break;