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

Re: NO_CASE_GLOB and unreadable directories (Episode VI: A New Hope)



On Mon, Jan 25, 2021 at 6:06 AM Peter Stephenson
<p.w.stephenson@xxxxxxxxxxxx> wrote:
>
> > On 25 January 2021 at 00:52 Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx> wrote:
> > 2) Adopt (a CYGWIN-clean variant of) my patch from workers/47832, and
> > accept that some current usage of NO_CASE_GLOB will break.
> > 3) Add a setopt (CASE_DIRS ?) for the current behavior, and merge that
> > with workers/47832.
>
> I don't think 2) is so unreasonable in that only patterns with some
> form of case-insensitivity are involved.  This is something of a minefield
> at the best of times and getting something that looks natural on systems
> that are intrinsically case-insensitive, whether or not case-preserving,
> is difficult.  But with a new option it seems to provide a definite path
> forward in any case.

I interpret this as a stronger preference for #3 than for #2, so I've
taken a stab at it with the patch below.

> The only serious objection to that other that I
> can see is that it makes the code more complicated; the reply to that is
> if the code is simple there's a good chance it doesn't quite do what you
> need it to.

It's actually the documentation that gets more complicated, the code
is pretty simple.  I rewrote the paragraph I've added to options.yo
about seven times and I'm still not entirely happy with it.

What I elected was to keep the current behavior by default, and add an
option to get the behavior that termux wants.  I named it CASE_PATHS
for reasons I think the documentation paragraph make obvious.

Changing CASE_PATHS has no effect by itself; it only matters if
CASE_GLOB changes.

The default is CASE_GLOB + NO_CASE_PATHS, which gives you the normal
zsh behavior, but CASE_GLOB + CASE_PATHS is the same.

NO_CASE_GLOB + NO_CASE_PATHS gives the current behavior of NO_CASE_GLOB.

NO_CASE_GLOB + CASE_PATHS is the behavior required for descending
through protected directories, as needed by termux.

Attached again to avoid line wrap.  No tests yet.
diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index b3bf11f5c..714e8a1a1 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -474,6 +474,22 @@ item(tt(CASE_MATCH) <D>)(
 Make regular expressions using the tt(zsh/regex) module (including
 matches with tt(=~)) sensitive to case.
 )
+pindex(CASE_PATHS)
+pindex(NO_CASE_PATHS)
+pindex(CASEPATHS)
+pindex(NOCASEPATHS)
+cindex(case-sensitive globbing, option)
+item(tt(CASE_PATHS))(
+If tt(CASE_PATHS) is not set (the default), tt(CASE_GLOB) affects the
+interpretation of em(every) path component, whenever a special
+character appears in em(any) component.  When tt(CASE_PATHS) is set,
+file path components that do em(not) contain special filename
+generation characters are always sensitive to case, thus restricting
+tt(NO_CASE_GLOB) to components that contain globbing characters.
+
+Note that if the filesystem itself is not sensitive to case, then
+tt(CASE_PATHS) has no effect.
+)
 pindex(CSH_NULL_GLOB)
 pindex(NO_CSH_NULL_GLOB)
 pindex(CSHNULLGLOB)
diff --git a/Src/options.c b/Src/options.c
index fba021e7d..6ea6290e5 100644
--- a/Src/options.c
+++ b/Src/options.c
@@ -105,6 +105,7 @@ static struct optname optns[] = {
 {{NULL, "bsdecho",	      OPT_EMULATE|OPT_SH},	 BSDECHO},
 {{NULL, "caseglob",	      OPT_ALL},			 CASEGLOB},
 {{NULL, "casematch",	      OPT_ALL},			 CASEMATCH},
+{{NULL, "casepaths",	      0},			 CASEPATHS},
 {{NULL, "cbases",	      0},			 CBASES},
 {{NULL, "cprecedences",	      OPT_EMULATE|OPT_NONZSH},	 CPRECEDENCES},
 {{NULL, "cdablevars",	      OPT_EMULATE},		 CDABLEVARS},
diff --git a/Src/pattern.c b/Src/pattern.c
index c7c2c8bea..053d2a627 100644
--- a/Src/pattern.c
+++ b/Src/pattern.c
@@ -509,7 +509,7 @@ void
 patcompstart(void)
 {
     patcompcharsset();
-    if (isset(CASEGLOB))
+    if (isset(CASEGLOB) || isset(CASEPATHS))
 	patglobflags = 0;
     else
 	patglobflags = GF_IGNCASE;
@@ -632,6 +632,13 @@ patcompile(char *exp, int inflags, char **endexp)
     p->patmlen = len;
     p->patnpar = patnpar-1;
 
+#ifndef __CYGWIN__  /* The filesystem itself is case-insensitive on Cygwin */
+    if ((patflags & PAT_FILE) && !isset(CASEGLOB) && !(patflags & PAT_PURES)) {
+	p->globflags |= GF_IGNCASE;
+	p->globend |= GF_IGNCASE;
+    }
+#endif
+
     if (!strp) {
 	pscan = (Upat)(patout + startoff);
 
diff --git a/Src/zsh.h b/Src/zsh.h
index 6cf1b4186..5acbddea4 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -2387,6 +2387,7 @@ enum {
     BSDECHO,
     CASEGLOB,
     CASEMATCH,
+    CASEPATHS,
     CBASES,
     CDABLEVARS,
     CDSILENT,


Messages sorted by: Reverse Date, Date, Thread, Author