Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Re: PATCH: Re: :r modifier
- X-seq: zsh-workers 13280
- From: Alexandre Duret-Lutz <duret_g@xxxxxxxxxxxxx>
- To: <zsh-workers@xxxxxxxxxxxxxx>
- Subject: Re: PATCH: Re: :r modifier
- Date: 15 Dec 2000 12:53:30 +0100
- In-reply-to: Alexandre Duret-Lutz's message of "14 Dec 2000 19:18:59 +0100"
- Mailing-list: contact zsh-workers-help@xxxxxxxxxxxxxx; run by ezmlm
- Organization: LRDE/EPITA http://www.lrde.epita.fr/
- References: <000a01c065dc$2ea4d9e0$21c9ca95@xxxxxxxxxxxxxx> <mvbzohy6f3g.fsf@xxxxxxxxxxxxxxxxxxxx>
- Sender: Alexandre Duret-Lutz <adl@xxxxxxxx>
>>> "adl" == Alexandre Duret-Lutz <duret_g@xxxxxxxxxxxxx> writes:
[...]
adl> Here is my proposal.
It was broken (since :h ignore trailing slashes, :t should to
likewise). I have also modified :h to works on filenames without
pathname: `dirname a.b' return `.', so :h does that too, the
point is that $x:h/$x:t should designate the same file as
$x (as `dirname $x`/`basename $x` would), and $x:r.$x:e likewise.
Here are the results on some error-prone inputs:
% for x in a.b//c //e ///g.h /i/j/k/ l.m ..
for> print "$x\t root=$x:r\text=$x:e,\thead=$x:h,\ttail=$x:t"
a.b//c root=a.b//c ext=, head=a.b, tail=c
//e root=//e ext=, head=//, tail=e
///g.h root=///g ext=h, head=/, tail=g.h
/i/j/k/ root=/i/j/k/ ext=, head=/i/j, tail=k
l.m root=l ext=m, head=., tail=l.m
.. root=. ext=, head=., tail=..
For comparison, here is tcsh:
12> foreach x ( a.b//c //e ///g.h /i/j/k/ l.m )
foreach? echo "$x\t root=$x:r\text=$x:e,\thead=$x:h,\ttail=$x:t"
foreach? end
a.b//c root=a.b//c ext=, head=a.b/, tail=c
//e root=//e ext=, head=/, tail=e
///g.h root=///g ext=h, head=//, tail=g.h
/i/j/k/ root=/i/j/k/ ext=, head=/i/j/k, tail=
l.m root=l ext=m, head=l.m, tail=l.m
and unpatched zsh:
% for x in a.b//c //e ///g.h /i/j/k/ l.m ..
for> print "$x\t root=$x:r\text=$x:e,\thead=$x:h,\ttail=$x:t"
a.b//c root=a ext=b//c, head=a.b/, tail=c
//e root=//e ext=//e, head=/, tail=e
///g.h root=///g ext=h, head=//, tail=g.h
/i/j/k/ root=/i/j/k/ ext=/i/j/k/, head=/i/j/k, tail=
l.m root=l ext=m, head=l.m, tail=l.m
.. root=. ext=, head=.., tail=..
Index: Doc/Zsh/expn.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/expn.yo,v
retrieving revision 1.24
diff -u -r1.24 expn.yo
--- Doc/Zsh/expn.yo 2000/10/05 08:41:37 1.24
+++ Doc/Zsh/expn.yo 2000/12/15 11:30:35
@@ -202,16 +202,19 @@
startitem()
item(tt(h))(
-Remove a trailing pathname component, leaving the head.
+Remove a trailing pathname component, leaving the head. This works
+like `tt(dirname)'.
)
item(tt(r))(
-Remove a trailing suffix of the form `tt(.)var(xxx)', leaving the basename.
+Remove a filename extension of the form `tt(.)var(xxx)', leaving
+the root name.
)
item(tt(e))(
-Remove all but the suffix.
+Remove all but the extension.
)
item(tt(t))(
-Remove all leading pathname components, leaving the tail.
+Remove all leading pathname components, leaving the tail. This works
+like `tt(basename)'.
)
item(tt(p))(
Print the new command but do not execute it. Only works with history
Index: Src/hist.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/hist.c,v
retrieving revision 1.20
diff -u -r1.20 hist.c
--- Src/hist.c 2000/10/21 03:15:36 1.20
+++ Src/hist.c 2000/12/15 11:30:36
@@ -1334,28 +1334,45 @@
int
remtpath(char **junkptr)
{
- char *str = *junkptr, *remcut;
+ char *str = strend(*junkptr);
- if ((remcut = strrchr(str, '/'))) {
- if (str != remcut)
- *remcut = '\0';
- else
- str[1] = '\0';
- return 1;
+ /* ignore trailing slashes */
+ while (str >= *junkptr && IS_DIRSEP(*str))
+ --str;
+ /* skip filename */
+ while (str >= *junkptr && !IS_DIRSEP(*str))
+ --str;
+ if (str < *junkptr) {
+ *junkptr = dupstring (".");
+ return 0;
}
- return 0;
+ /* repeated slashes are considered like a single slash */
+ while (str > *junkptr && IS_DIRSEP(str[-1]))
+ --str;
+ /* never erase the root slash */
+ if (str == *junkptr) {
+ ++str;
+ /* Leading doubled slashes (`//') have a special meaning on cygwin
+ and some old flavor of UNIX, so we do not assimilate them to
+ a single slash. However a greater number is ok to squeeze. */
+ if (IS_DIRSEP(*str) && !IS_DIRSEP(str[1]))
+ ++str;
+ }
+ *str = '\0';
+ return 1;
}
/**/
int
remtext(char **junkptr)
{
- char *str = *junkptr, *remcut;
+ char *str;
- if ((remcut = strrchr(str, '.')) && remcut != str) {
- *remcut = '\0';
- return 1;
- }
+ for (str = strend(*junkptr); str >= *junkptr && !IS_DIRSEP(*str); --str)
+ if (*str == '.') {
+ *str = '\0';
+ return 1;
+ }
return 0;
}
@@ -1363,12 +1380,15 @@
int
rembutext(char **junkptr)
{
- char *str = *junkptr, *remcut;
+ char *str;
- if ((remcut = strrchr(str, '.')) && remcut != str) {
- *junkptr = dupstring(remcut + 1); /* .xx or xx? */
- return 1;
- }
+ for (str = strend(*junkptr); str >= *junkptr && !IS_DIRSEP(*str); --str)
+ if (*str == '.') {
+ *junkptr = dupstring(str + 1); /* .xx or xx? */
+ return 1;
+ }
+ /* no extension */
+ *junkptr = dupstring ("");
return 0;
}
@@ -1376,13 +1396,20 @@
mod_export int
remlpaths(char **junkptr)
{
- char *str = *junkptr, *remcut;
+ char *str = strend(*junkptr);
- if ((remcut = strrchr(str, '/'))) {
- *remcut = '\0';
- *junkptr = dupstring(remcut + 1);
- return 1;
- }
+ if (IS_DIRSEP(*str)) {
+ /* remove trailing slashes */
+ while (str >= *junkptr && IS_DIRSEP(*str))
+ --str;
+ str[1] = '\0';
+ }
+ for (; str >= *junkptr; --str)
+ if (IS_DIRSEP(*str)) {
+ *str = '\0';
+ *junkptr = dupstring(str + 1);
+ return 1;
+ }
return 0;
}
Index: Src/string.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/string.c,v
retrieving revision 1.3
diff -u -r1.3 string.c
--- Src/string.c 2000/09/27 19:31:48 1.3
+++ Src/string.c 2000/12/15 11:30:36
@@ -79,7 +79,7 @@
char *ptr;
size_t l1 = strlen(s1);
size_t l2 = strlen(s2);
-
+
ptr = (char *)zhalloc(l1 + l2 + strlen(s3) + 1);
strcpy(ptr, s1);
strcpy(ptr + l1, s2);
@@ -132,4 +132,16 @@
appstr(char *base, char const *append)
{
return strcat(realloc(base, strlen(base) + strlen(append) + 1), append);
+}
+
+/* Return a pointer to the last character of a string,
+ unless the string is empty. */
+
+/**/
+mod_export char *
+strend(char *str)
+{
+ if (*str == '\0')
+ return str;
+ return str + strlen (str) - 1;
}
Index: Src/system.h
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/system.h,v
retrieving revision 1.11
diff -u -r1.11 system.h
--- Src/system.h 2000/09/18 14:22:48 1.11
+++ Src/system.h 2000/12/15 11:30:37
@@ -657,3 +657,9 @@
#ifndef MAILDIR_SUPPORT
#define mailstat(X,Y) stat(X,Y)
#endif
+
+#ifdef __CYGWIN__
+# define IS_DIRSEP(c) ((c) == '/' || (c) == '\\')
+#else
+# define IS_DIRSEP(c) ((c) == '/')
+#endif
--
Alexandre Duret-Lutz
Messages sorted by:
Reverse Date,
Date,
Thread,
Author