From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 18795 invoked from network); 15 Dec 2000 11:46:36 -0000 Received: from sunsite.dk (HELO sunsite.auc.dk) (130.225.51.30) by ns1.primenet.com.au with SMTP; 15 Dec 2000 11:46:36 -0000 Received: (qmail 11355 invoked by alias); 15 Dec 2000 11:46:30 -0000 Mailing-List: contact zsh-workers-help@sunsite.auc.dk; run by ezmlm Precedence: bulk X-No-Archive: yes X-Seq: 13280 Received: (qmail 11345 invoked from network); 15 Dec 2000 11:46:27 -0000 To: Subject: Re: PATCH: Re: :r modifier References: <000a01c065dc$2ea4d9e0$21c9ca95@mow.siemens.ru> From: Alexandre Duret-Lutz X-Home-Page: http://www.epita.fr/~duret_g/ X-Attribution: adl Organization: LRDE/EPITA http://www.lrde.epita.fr/ Date: 15 Dec 2000 12:53:30 +0100 In-Reply-To: Alexandre Duret-Lutz's message of "14 Dec 2000 19:18:59 +0100" Message-ID: User-Agent: Gnus/5.0807 (Gnus v5.8.7) Emacs/20.7 MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Sender: Alexandre Duret-Lutz >>> "adl" == Alexandre Duret-Lutz 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