Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

PATCH: Re: :r modifier



>>> "Andrej" == Andrej Borsenkow <Andrej.Borsenkow@xxxxxxxxxxxxxx> writes:

[...]

 Andrej> I checked bash and it behaves the same as zsh.
 >> 
 >> Huh?  You aren't speaking about :h here, are you?
 >> 

 Andrej> I am speaking about :r and :e. What so special about
 Andrej> :h? 

Nothing, please dismiss my question...

[...]

Here is my proposal.  The following patch modifies :r, :e, :h, 
and :t to behave as I expect them to.  My point for doing so is that
  1) this seems natural and more useful (from the user point of 
     view) 
  2) that should not break anything because these modifiers are 
     usually used in places where you won't have any surprise
     with the old behavior  (e.g. you use :r when you *know* 
     that there is an extenstion to delete) and the behavior 
     is not changed in those places.

I don't know if you consider the compatibility with other shells
important on this point. I must confess I don't really do :),
the overall semantic is still the same, but at least there is no 
surprises in the results.

Leading double-slashes are handled, and backslashes too (under
Cygwin only).   remtpath() is also assuming that leading `//', 
`/\\', `\\/', and `\\\\' are equivalent under Cygwin, is this true?


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/14 17:38:40
@@ -202,13 +202,15 @@
 
 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.
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/14 17:38:40
@@ -1334,28 +1334,43 @@
 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)
+	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 slashes.  However a greater number is ok to squeeze. */
+	if (IS_DIRSEP(*str) && !IS_DIRSEP(str[1]))
+	    ++str;
     }
-    return 0;
+    *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 +1378,13 @@
 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;
+	}
     return 0;
 }
 
@@ -1376,13 +1392,14 @@
 mod_export int
 remlpaths(char **junkptr)
 {
-    char *str = *junkptr, *remcut;
+    char *str = *junkptr + strlen (*junkptr) - 1;
 
-    if ((remcut = strrchr(str, '/'))) {
-	*remcut = '\0';
-	*junkptr = dupstring(remcut + 1);
-	return 1;
-    }
+    for (str = strend(*junkptr); 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/14 17:38:40
@@ -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/14 17:38:41
@@ -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