mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-09-18 15:21:16 +02:00
Michael Hwang: 26731 with cosmetic changes: add "a" and "A" modifiers
26736: document the above
This commit is contained in:
parent
bf25c3a43f
commit
7733ade831
4 changed files with 190 additions and 19 deletions
|
@ -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>
|
2009-03-14 Wayne Davison <wayned@users.sourceforge.net>
|
||||||
|
|
||||||
* 26735: Src/Modules/files.c, Src/Modules/mapfile.c,
|
* 26735: Src/Modules/files.c, Src/Modules/mapfile.c,
|
||||||
|
@ -11409,5 +11416,5 @@
|
||||||
|
|
||||||
*****************************************************
|
*****************************************************
|
||||||
* This is used by the shell to define $ZSH_PATCHLEVEL
|
* This is used by the shell to define $ZSH_PATCHLEVEL
|
||||||
* $Revision: 1.4617 $
|
* $Revision: 1.4618 $
|
||||||
*****************************************************
|
*****************************************************
|
||||||
|
|
|
@ -216,20 +216,24 @@ of em(filename generation) and em(parameter expansion), except where
|
||||||
noted.
|
noted.
|
||||||
|
|
||||||
startitem()
|
startitem()
|
||||||
item(tt(h))(
|
item(tt(a))(
|
||||||
Remove a trailing pathname component, leaving the head. This works
|
Turn a file name into an absolute path: prepends the current directory,
|
||||||
like `tt(dirname)'.
|
if necessary, and resolves any use of `tt(..)' and `tt(.)' in the path.
|
||||||
)
|
)
|
||||||
item(tt(r))(
|
item(tt(A))(
|
||||||
Remove a filename extension of the form `tt(.)var(xxx)', leaving
|
As `tt(a)', but also resolve use of symbolic links where possible.
|
||||||
the root name.
|
Note that resolution of `tt(..)' occurs em(before) resolution of symbolic
|
||||||
|
links.
|
||||||
)
|
)
|
||||||
item(tt(e))(
|
item(tt(e))(
|
||||||
Remove all but the extension.
|
Remove all but the extension.
|
||||||
)
|
)
|
||||||
item(tt(t))(
|
item(tt(h))(
|
||||||
Remove all leading pathname components, leaving the tail. This works
|
Remove a trailing pathname component, leaving the head. This works
|
||||||
like `tt(basename)'.
|
like `tt(dirname)'.
|
||||||
|
)
|
||||||
|
item(tt(l))(
|
||||||
|
Convert the words to all lowercase.
|
||||||
)
|
)
|
||||||
item(tt(p))(
|
item(tt(p))(
|
||||||
Print the new command but do not execute it. Only works with history
|
Print the new command but do not execute it. Only works with history
|
||||||
|
@ -244,15 +248,9 @@ by tt(eval).
|
||||||
item(tt(Q))(
|
item(tt(Q))(
|
||||||
Remove one level of quotes from the substituted words.
|
Remove one level of quotes from the substituted words.
|
||||||
)
|
)
|
||||||
item(tt(x))(
|
item(tt(r))(
|
||||||
Like tt(q), but break into words at whitespace. Does not work with
|
Remove a filename extension of the form `tt(.)var(xxx)', leaving
|
||||||
parameter expansion.
|
the root name.
|
||||||
)
|
|
||||||
item(tt(l))(
|
|
||||||
Convert the words to all lowercase.
|
|
||||||
)
|
|
||||||
item(tt(u))(
|
|
||||||
Convert the words to all uppercase.
|
|
||||||
)
|
)
|
||||||
item(tt(s/)var(l)tt(/)var(r)[tt(/)])(
|
item(tt(s/)var(l)tt(/)var(r)[tt(/)])(
|
||||||
Substitute var(r) for var(l) as described below.
|
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
|
inside braces, and in filename generation it must be quoted with a
|
||||||
backslash.
|
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()
|
enditem()
|
||||||
|
|
||||||
The tt(s/l/r/) substitution works as follows. By default the left-hand
|
The tt(s/l/r/) substitution works as follows. By default the left-hand
|
||||||
|
|
141
Src/hist.c
141
Src/hist.c
|
@ -623,6 +623,21 @@ histsubchar(int c)
|
||||||
case 'p':
|
case 'p':
|
||||||
histdone = HISTFLAG_DONE | HISTFLAG_NOEXEC;
|
histdone = HISTFLAG_DONE | HISTFLAG_NOEXEC;
|
||||||
break;
|
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':
|
case 'h':
|
||||||
if (!remtpath(&sline)) {
|
if (!remtpath(&sline)) {
|
||||||
herrflush();
|
herrflush();
|
||||||
|
@ -1482,6 +1497,132 @@ hcomsearch(char *str)
|
||||||
|
|
||||||
/* various utilities for : modifiers */
|
/* 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
|
int
|
||||||
remtpath(char **junkptr)
|
remtpath(char **junkptr)
|
||||||
|
|
14
Src/subst.c
14
Src/subst.c
|
@ -3199,6 +3199,8 @@ modify(char **str, char **ptr)
|
||||||
|
|
||||||
for (; !c && **ptr;) {
|
for (; !c && **ptr;) {
|
||||||
switch (**ptr) {
|
switch (**ptr) {
|
||||||
|
case 'a':
|
||||||
|
case 'A':
|
||||||
case 'h':
|
case 'h':
|
||||||
case 'r':
|
case 'r':
|
||||||
case 'e':
|
case 'e':
|
||||||
|
@ -3337,6 +3339,12 @@ modify(char **str, char **ptr)
|
||||||
copy = dupstring(tt);
|
copy = dupstring(tt);
|
||||||
*e = tc;
|
*e = tc;
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
case 'a':
|
||||||
|
chabspath(©);
|
||||||
|
break;
|
||||||
|
case 'A':
|
||||||
|
chrealpath(©);
|
||||||
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
remtpath(©);
|
remtpath(©);
|
||||||
break;
|
break;
|
||||||
|
@ -3396,6 +3404,12 @@ modify(char **str, char **ptr)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
case 'a':
|
||||||
|
chabspath(str);
|
||||||
|
break;
|
||||||
|
case 'A':
|
||||||
|
chrealpath(str);
|
||||||
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
remtpath(str);
|
remtpath(str);
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in a new issue