mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-02-13 11:42:21 +00:00
Add --globcasedetect shell option for globbing and completion
One of the best-kept secrets of libast/ksh93 is that the code includes support for case-insensitive file name generation (a.k.a. pathname expansion, a.k.a. globbing) as well as case-insensitive file name completion on interactive shells, depending on whether the file system is case-insensitive or not. This is transparently determined for each directory, so a path pattern that spans multiple file systems can be part case-sensitive and part case- insensitive. In more precise terms, each slash-separated path name component pattern P is treated as ~(i:P) if its parent directory exists on a case-insensitive file system. I recently discovered this while dealing with <https://github.com/ksh93/ksh/issues/223>. However, that support is dead code on almost all current systems. It depends on pathconf(2) having a _PC_PATH_ATTRIBUTES selector. The 'c' attribute is supposedly returned if the given directory is on a case insensitive file system. There are other attributes as well (at least 'l', see src/lib/libcmd/rm.c). However, I have been unable to find any system, current or otherwise, that has _PC_PATH_ATTRIBUTES. Google and mailing list searches yield no relevant results at all. If anyone knows of such a system, please add a comment to this commit on GitHub, or email me. An exception is Cygwin/Windows, on which the "c" attribute was simply hardcoded, so globbing/completion is always case- insensitive. As of Windows 10, that is wrong, as it added the possibility to mount case-sensitive file systems. On the other hand, this was never activated on the Mac, even though macOS has always used a case-insensitive file like Windows. But, being UNIX, it can also mount case-sensitive file systems. Finally, Linux added the possibility to create individual case- insensitive ext4 directories fairly recently, in version 5.2. https://www.collabora.com/news-and-blog/blog/2020/08/27/using-the-linux-kernel-case-insensitive-feature-in-ext4/ So, since this functionality latently exists in the code base, and three popular OSs now have relevant file system support, we might as well make it usable on those systems. It's a nice idea, as it intuitively makes sense for globbing and completion behaviour to auto-adapt to file system case insensitivity on a per-directory basis. No other shell does this, so it's a nice selling point, too. However, the way it is coded, this is activated unconditionally on supported systems. That is not a good idea. It will surprise users. Since globbing is used with commands like 'rm', we do not want surprises. So this commit makes it conditional upon a new shell option called 'globcasedetect'. This option is only compiled into ksh on systems where we can actually detect FS case insensitivity. To implement this, libast needs some public API additions first. *** libast changes *** src/lib/libast/features/lib: - Add probes for the linux/fs.h and sys/ioctl.h headers. Linux needs these to use ioctl(2) in pathicase(3) (see below). src/lib/libast/path/pathicase.c, src/lib/libast/include/ast.h, src/lib/libast/man/path.3, src/lib/libast/Mamfile: - Add new pathicase(3) public API function. This uses whatever OS-specific method it can detect at compile time to determine if a particular path is on a case-insensitive file system. If no method is available, it only sets errno to ENOSYS and returns -1. Currently known to work on: macOS, Cygwin, Linux 5.2+, QNX 7.0+. - On systems (if any) that have the mysterious _PC_PATH_ATTRIBUTES selector for pathconf(2), call astconf(3) and check for the 'c' attribute to determine case insensitivity. This should preserve compatibility with any such system. src/lib/libast/port/astconf.c: - dynamic[]: As case-insensitive globbing is now optional on all systems, do not set the 'c' attribute by default on _WINIX (Cygwin/Windows) systems. - format(): On systems that do not have _PC_PATH_ATTRIBUTES, call pathicase(3) to determine the value for the "c" (case insensitive) attribute only. This is for compatibility as it is more efficient to call pathicase(3) directly. src/lib/libast/misc/glob.c, src/lib/libast/include/glob.h: - Add new GLOB_DCASE public API flag to glob(3). This is like GLOB_ICASE (case-insensitive matching) except it only makes the match case-insensitive if the file system for the current pathname component is determined to be case-insensitive. - gl_attr(): For efficiency, call pathicase(3) directly instead of via astconf(3). - glob_dir(): Only call gl_attr() to determine file system case insensitivity if the GLOB_DCASE flag was passed. This makes case insensitive globbing optional on all systems. - glob(): The options bitmask needs to be widened to fit the new GLOB_DCASE option. Define this centrally in a new GLOB_FLAGMASK macro so it is easy to change it along with GLOB_MAGIC (which uses the remaining bits for a sanity check bit pattern). src/lib/libast/path/pathexists.c: - For efficiency, call pathicase(3) directly instead of via astconf(3). *** ksh changes *** src/cmd/ksh93/features/options, src/cmd/ksh93/SHOPT.sh: - Add new SHOPT_GLOBCASEDET compile-time option. Set it to probe (empty) by default so that the shell option is compiled in on supported systems only, which is determined by new iffe feature test that checks if pathicase(3) returns an ENOSYS error. src/cmd/ksh93/data/options.c, src/cmd/ksh93/include/shell.h: - Add -o globcasedetect shell option if compiling with SHOPT_GLOBCASEDET. src/cmd/ksh93/sh/expand.c: path_expand(): - Pass the new GLOB_DCASE flag to glob(3) if the globcasedetect/SH_GLOBCASEDET shell option is set. src/cmd/ksh93/edit/completion.c: - While file listing/completion is based on globbing and automatically becomes case-insensitive when globbing does, it needs some additional handling to make a string comparison case-insensitive in corresponding cases. Otherwise, partial completions may be deleted from the command line upon pressing tab. This code was already in ksh 93u+ and just needs to be made conditional upon SHOPT_GLOBCASEDET and globcasedetect. - For efficiency, call pathicase(3) directly instead of via astconf(3). src/cmd/ksh93/sh.1: - Document the new globcasedetect shell option.
This commit is contained in:
parent
71bfe0283d
commit
71934570bf
18 changed files with 192 additions and 17 deletions
16
NEWS
16
NEWS
|
@ -3,6 +3,22 @@ For full details, see the git log at: https://github.com/ksh93/ksh
|
|||
|
||||
Any uppercase BUG_* names are modernish shell bug IDs.
|
||||
|
||||
2021-03-22:
|
||||
|
||||
- A new --globcasedetect shell option is added to ksh on OSs where we can check
|
||||
for a case-insensitive file system (currently macOS, Windows/Cygwin, Linux
|
||||
5.2+, and QNX 7.0+). When this option is turned on, file name generation
|
||||
(globbing), as well as file name tab completion on interactive shells,
|
||||
automatically become case-insensitive on file systems where the difference
|
||||
between upper- and lowercase is ignored for file names. This is transparently
|
||||
determined for each directory, so a path pattern that spans multiple file
|
||||
systems can be part case-sensitive and part case-insensitive.
|
||||
The option is not compiled into ksh on systems where we do not know of a
|
||||
method to check for file system case insensitivity. The shell option can be
|
||||
force-compiled by setting SHOPT_GLOBCASEDET to 1 in src/cmd/ksh93/SHOPT.sh,
|
||||
but it won't have any effect on non-supported systems, so this is not
|
||||
recommended. It can be removed from ksh by setting SHOPT_GLOBCASEDET to 0.
|
||||
|
||||
2021-03-17:
|
||||
|
||||
- Fixed a bug with file name completion on the interactive shell in multibyte
|
||||
|
|
|
@ -20,6 +20,7 @@ SHOPT EDPREDICT=1 # predictive editing
|
|||
SHOPT ESH=1 # emacs/gmacs edit mode
|
||||
SHOPT FILESCAN=1 # fast file scan
|
||||
SHOPT FIXEDARRAY=1 # fixed dimension indexed array
|
||||
SHOPT GLOBCASEDET= # -o globcasedetect: adapt globbing/completion to case-insensitive file systems
|
||||
SHOPT HISTEXPAND=1 # csh-style history file expansions
|
||||
SHOPT KIA= # ksh -R <outfile> <script> generates cross-ref database from script
|
||||
SHOPT MULTIBYTE=1 # multibyte character handling
|
||||
|
|
|
@ -43,6 +43,9 @@ const Shtable_t shtab_options[] =
|
|||
"errexit", SH_ERREXIT,
|
||||
"noexec", SH_NOEXEC,
|
||||
"noglob", SH_NOGLOB,
|
||||
#if SHOPT_GLOBCASEDET
|
||||
"globcasedetect", SH_GLOBCASEDET,
|
||||
#endif
|
||||
"globstar", SH_GLOBSTARS,
|
||||
#if SHOPT_ESH
|
||||
"gmacs", SH_GMACS,
|
||||
|
|
|
@ -59,6 +59,9 @@ static char *fmtx(const char *string)
|
|||
return(stakptr(offset));
|
||||
}
|
||||
|
||||
#if !SHOPT_GLOBCASEDET
|
||||
#define charcmp(a,b,dummy) (a==b)
|
||||
#else
|
||||
static int charcmp(int a, int b, int nocase)
|
||||
{
|
||||
if(nocase)
|
||||
|
@ -78,6 +81,7 @@ static int charcmp(int a, int b, int nocase)
|
|||
}
|
||||
return(a==b);
|
||||
}
|
||||
#endif /* !SHOPT_GLOBCASEDET */
|
||||
|
||||
/*
|
||||
* overwrites <str> to common prefix of <str> and <newstr>
|
||||
|
@ -384,8 +388,10 @@ int ed_expand(Edit_t *ep, char outbuff[],int *cur,int *eol,int mode, int count)
|
|||
*dir = 0;
|
||||
saveout = begin;
|
||||
}
|
||||
if(saveout=astconf("PATH_ATTRIBUTES",saveout,(char*)0))
|
||||
nocase = (strchr(saveout,'c')!=0);
|
||||
#if SHOPT_GLOBCASEDET
|
||||
if(sh_isoption(SH_GLOBCASEDET))
|
||||
nocase = (pathicase(saveout) > 0);
|
||||
#endif
|
||||
if(dir)
|
||||
*dir = c;
|
||||
/* just expand until name is unique */
|
||||
|
|
|
@ -54,3 +54,18 @@ cat{
|
|||
# undef SHOPT_MULTIBYTE
|
||||
#endif
|
||||
}end
|
||||
|
||||
tst note{ can we probe file system case insensitivity }end output{
|
||||
#include <ast.h>
|
||||
#include <error.h>
|
||||
#include <stdio.h>
|
||||
static char *o = "SHOPT_GLOBCASEDET";
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
int r;
|
||||
r = pathicase("/");
|
||||
r = (r > -1 || errno != ENOSYS);
|
||||
printf("#ifndef %s\n# define %s\t%d\n#endif\n", o, o, r);
|
||||
return !r;
|
||||
}
|
||||
}end
|
||||
|
|
|
@ -133,6 +133,9 @@ typedef union Shnode_u Shnode_t;
|
|||
#define SH_DICTIONARY 30
|
||||
#define SH_PIPEFAIL 32
|
||||
#define SH_GLOBSTARS 33
|
||||
#if SHOPT_GLOBCASEDET
|
||||
#define SH_GLOBCASEDET 34
|
||||
#endif
|
||||
#define SH_RC 35
|
||||
#define SH_SHOWME 36
|
||||
#define SH_LETOCTAL 37
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
#define SH_RELEASE_FORK "93u+m" /* only change if you develop a new ksh93 fork */
|
||||
#define SH_RELEASE_SVER "1.0.0-alpha" /* semantic version number: https://semver.org */
|
||||
#define SH_RELEASE_DATE "2021-03-17" /* must be in this format for $((.sh.version)) */
|
||||
#define SH_RELEASE_DATE "2021-03-22" /* must be in this format for $((.sh.version)) */
|
||||
#define SH_RELEASE_CPYR "(c) 2020-2021 Contributors to ksh " SH_RELEASE_FORK
|
||||
|
||||
/* Scripts sometimes field-split ${.sh.version}, so don't change amount of whitespace. */
|
||||
|
|
|
@ -2771,7 +2771,9 @@ currently implemented.
|
|||
The remainder of the pattern uses System V regular expression syntax.
|
||||
.TP
|
||||
.B i
|
||||
Treat the match as case insensitive.
|
||||
Always treat the match as case-insensitive, regardless of the
|
||||
.B globcasedetect
|
||||
shell option.
|
||||
.TP
|
||||
.B g
|
||||
File the longest match (greedy). This is the default.
|
||||
|
@ -6008,7 +6010,7 @@ omitted, then \f2type\^\fP must be an indexed array variable with at
|
|||
least two elements and the values are taken from this array variable.
|
||||
If
|
||||
.B -i
|
||||
is specified the values are case insensitive.
|
||||
is specified the values are case-insensitive.
|
||||
Declaration commands are created as special builtins that cannot be
|
||||
removed or overridden by shell functions.
|
||||
.TP
|
||||
|
@ -7122,6 +7124,22 @@ style in-line editor for command entry.
|
|||
Same as
|
||||
.BR \-e .
|
||||
.TP 8
|
||||
.B globcasedetect
|
||||
When this option is turned on, globbing (see
|
||||
.I "File Name Generation\^"
|
||||
above) and
|
||||
file name listing and completion (see
|
||||
.I "In-line Editing Options\^"
|
||||
above) automatically become case-insensitive on file systems where the
|
||||
difference between upper- and lowercase is ignored for file names. This is
|
||||
transparently determined for each directory, so a path pattern that spans
|
||||
multiple file systems can be part case-sensitive and part case-insensitive.
|
||||
In more precise terms, each slash-separated path name component pattern \fIp\fR
|
||||
is treated as \fB~(i:\fR\fIp\fR\fB)\fR
|
||||
if its parent directory exists on a case-insensitive file system.
|
||||
This option is only present on operating systems that support
|
||||
case-insensitive file systems.
|
||||
.TP 8
|
||||
.B globstar
|
||||
Same as
|
||||
.BR \-G .
|
||||
|
|
|
@ -92,6 +92,10 @@ int path_expand(Shell_t *shp,const char *pattern, struct argnod **arghead)
|
|||
flags |= GLOB_MARK;
|
||||
if(sh_isoption(SH_GLOBSTARS))
|
||||
flags |= GLOB_STARSTAR;
|
||||
#if SHOPT_GLOBCASEDET
|
||||
if(sh_isoption(SH_GLOBCASEDET))
|
||||
flags |= GLOB_DCASE;
|
||||
#endif
|
||||
if(sh_isstate(SH_COMPLETE))
|
||||
{
|
||||
#if KSHELL
|
||||
|
|
|
@ -1028,6 +1028,15 @@ make install
|
|||
prev path/pathfind.c
|
||||
exec - ${CC} ${mam_cc_FLAGS} ${KSH_RELFLAGS} ${CCFLAGS} -I. -Icomp -Iinclude -Istd -D_PACKAGE_ast -c path/pathfind.c
|
||||
done pathfind.o generated
|
||||
make pathicase.o
|
||||
make path/pathicase.c
|
||||
prev include/error.h implicit
|
||||
prev include/ast.h implicit
|
||||
done path/pathicase.c
|
||||
meta pathicase.o %.c>%.o path/pathicase.c pathicase
|
||||
prev path/pathicase.c
|
||||
exec - ${CC} ${mam_cc_FLAGS} ${KSH_RELFLAGS} ${CCFLAGS} -I. -Icomp -Iinclude -Istd -D_PACKAGE_ast -c path/pathicase.c
|
||||
done pathicase.o generated
|
||||
make pathkey.o
|
||||
make path/pathkey.c
|
||||
prev ast_api.h implicit
|
||||
|
@ -6081,7 +6090,7 @@ make install
|
|||
exec - ${CC} ${mam_cc_FLAGS} ${KSH_RELFLAGS} ${CCFLAGS} -I. -Icomp -Iinclude -Istd -D__OBSOLETE__=20120101 -D_PACKAGE_ast -c disc/sfstrtmp.c
|
||||
done sfstrtmp.o generated
|
||||
exec - ${AR} rc libast.a state.o transition.o opendir.o readdir.o rewinddir.o seekdir.o telldir.o getcwd.o fastfind.o hashalloc.o hashdump.o hashfree.o hashlast.o hashlook.o hashscan.o hashsize.o hashview.o hashwalk.o memhash.o memsum.o strhash.o strkey.o strsum.o stracmp.o strnacmp.o ccmap.o ccmapid.o ccnative.o chresc.o chrtoi.o
|
||||
exec - ${AR} rc libast.a streval.o strexpr.o strmatch.o strcopy.o modei.o modex.o strmode.o strlcat.o strlcpy.o strlook.o strncopy.o strsearch.o strpsearch.o stresc.o stropt.o strtape.o strpcmp.o strnpcmp.o strvcmp.o strnvcmp.o tok.o tokline.o tokscan.o pathaccess.o pathcat.o pathcanon.o pathcheck.o pathpath.o pathexists.o pathfind.o pathkey.o pathprobe.o pathrepl.o pathnative.o pathposix.o pathtemp.o pathtmp.o pathstat.o pathgetlink.o pathsetlink.o pathbin.o pathshell.o pathcd.o pathprog.o ftwalk.o ftwflags.o fts.o astintercept.o conformance.o getenv.o setenviron.o optget.o optjoin.o optesc.o optctx.o strsort.o struniq.o magic.o mime.o mimetype.o signal.o sigflag.o systrace.o error.o errorf.o errormsg.o errorx.o localeconv.o setlocale.o translate.o catopen.o iconv.o lc.o lctab.o mc.o base64.o recfmt.o recstr.o reclen.o fmtrec.o fmtbase.o fmtbuf.o fmtclock.o fmtdev.o fmtelapsed.o fmterror.o fmtesc.o fmtfmt.o fmtfs.o fmtident.o fmtint.o fmtip4.o fmtip6.o fmtls.o fmtmatch.o fmtmode.o fmtnum.o fmtperm.o fmtre.o fmttime.o
|
||||
exec - ${AR} rc libast.a streval.o strexpr.o strmatch.o strcopy.o modei.o modex.o strmode.o strlcat.o strlcpy.o strlook.o strncopy.o strsearch.o strpsearch.o stresc.o stropt.o strtape.o strpcmp.o strnpcmp.o strvcmp.o strnvcmp.o tok.o tokline.o tokscan.o pathaccess.o pathcat.o pathcanon.o pathcheck.o pathpath.o pathexists.o pathfind.o pathicase.o pathkey.o pathprobe.o pathrepl.o pathnative.o pathposix.o pathtemp.o pathtmp.o pathstat.o pathgetlink.o pathsetlink.o pathbin.o pathshell.o pathcd.o pathprog.o ftwalk.o ftwflags.o fts.o astintercept.o conformance.o getenv.o setenviron.o optget.o optjoin.o optesc.o optctx.o strsort.o struniq.o magic.o mime.o mimetype.o signal.o sigflag.o systrace.o error.o errorf.o errormsg.o errorx.o localeconv.o setlocale.o translate.o catopen.o iconv.o lc.o lctab.o mc.o base64.o recfmt.o recstr.o reclen.o fmtrec.o fmtbase.o fmtbuf.o fmtclock.o fmtdev.o fmtelapsed.o fmterror.o fmtesc.o fmtfmt.o fmtfs.o fmtident.o fmtint.o fmtip4.o fmtip6.o fmtls.o fmtmatch.o fmtmode.o fmtnum.o fmtperm.o fmtre.o fmttime.o
|
||||
exec - ${AR} rc libast.a fmtuid.o fmtgid.o fmtsignal.o fmtscale.o fmttmx.o fmttv.o fmtversion.o strelapsed.o strperm.o struid.o strgid.o strtoip4.o strtoip6.o stack.o stk.o swapget.o swapmem.o swapop.o swapput.o sigdata.o sigcrit.o sigunblock.o procopen.o procclose.o procrun.o procfree.o tmdate.o tmequiv.o tmfix.o tmfmt.o tmform.o tmgoff.o tminit.o tmleap.o tmlex.o tmlocale.o tmmake.o tmpoff.o tmscan.o tmsleep.o tmtime.o tmtype.o tmweek.o tmword.o tmzone.o tmxdate.o tmxduration.o tmxfmt.o tmxgettime.o tmxleap.o tmxmake.o tmxscan.o tmxsettime.o tmxsleep.o tmxtime.o tmxtouch.o tvcmp.o tvgettime.o tvsettime.o tvsleep.o tvtouch.o cmdarg.o vecargs.o vecfile.o vecfree.o vecload.o vecstring.o univdata.o touch.o mnt.o debug.o memccpy.o memchr.o memcmp.o memcpy.o memdup.o memmove.o memset.o mkdir.o mkfifo.o mknod.o rmdir.o remove.o rename.o link.o unlink.o strdup.o strchr.o strrchr.o strstr.o strtod.o strtold.o strtol.o strtoll.o strtoul.o strtoull.o strton.o strtonll.o strntod.o strntold.o strnton.o
|
||||
exec - ${AR} rc libast.a strntonll.o strntol.o strntoll.o strntoul.o strntoull.o strcasecmp.o strncasecmp.o strerror.o mktemp.o tmpnam.o fsync.o execlp.o execve.o execvp.o execvpe.o spawnveg.o vfork.o killpg.o hsearch.o tsearch.o getlogin.o putenv.o setenv.o unsetenv.o lstat.o statvfs.o eaccess.o gross.o omitted.o readlink.o symlink.o getpgrp.o setpgid.o setsid.o waitpid.o creat64.o fcntl.o open.o atexit.o getdents.o getwd.o dup2.o errno.o getpreroot.o ispreroot.o realopen.o setpreroot.o getgroups.o mount.o system.o iblocks.o modedata.o tmdata.o memfatal.o sfkeyprintf.o sfdcdio.o sfdcdos.o sfdcfilter.o sfdcseekable.o sfdcslow.o sfdcsubstr.o sfdctee.o sfdcunion.o sfdcmore.o sfdcprefix.o wc.o wc2utf8.o basename.o closelog.o dirname.o fmtmsglib.o fnmatch.o ftw.o getdate.o getsubopt.o glob.o nftw.o openlog.o re_comp.o resolvepath.o realpath.o regcmp.o regexp.o setlogmask.o strftime.o strptime.o swab.o syslog.o tempnam.o wordexp.o mktime.o regalloc.o regclass.o regcoll.o regcomp.o regcache.o regdecomp.o regerror.o regexec.o regfatal.o reginit.o
|
||||
exec - ${AR} rc libast.a regnexec.o regsubcomp.o regsubexec.o regsub.o regrecord.o regrexec.o regstat.o dtclose.o dtdisc.o dthash.o dtlist.o dtmethod.o dtopen.o dtstat.o dtstrhash.o dttree.o dtuser.o dtview.o dtwalk.o dtnew.o dtcomp.o sfclose.o sfclrlock.o sfdisc.o sfdlen.o sfexcept.o sfgetl.o sfgetu.o sfcvt.o sfecvt.o sffcvt.o sfextern.o sffilbuf.o sfflsbuf.o sfprints.o sfgetd.o sfgetr.o sfllen.o sfmode.o sfmove.o sfnew.o sfpkrd.o sfnotify.o sfnputc.o sfopen.o sfpeek.o sfpoll.o sfpool.o sfpopen.o sfprintf.o sfputd.o sfputl.o sfputr.o sfputu.o sfrd.o sfread.o sfreserve.o sfscanf.o sfseek.o sfset.o sfsetbuf.o sfsetfd.o sfsize.o sfsk.o sfstack.o sfstrtod.o sfsync.o sfswap.o sftable.o sftell.o sftmp.o sfungetc.o sfvprintf.o sfvscanf.o sfwr.o sfwrite.o sfpurge.o sfraise.o sfwalk.o sfgetm.o sfmutex.o sfputm.o sfresize.o _sfclrerr.o _sfeof.o _sferror.o _sffileno.o _sfopen.o _sfstacked.o _sfvalue.o _sfgetc.o _sfgetl.o _sfgetl2.o _sfgetu.o _sfgetu2.o _sfdlen.o _sfllen.o _sfslen.o _sfulen.o _sfputc.o _sfputd.o _sfputl.o _sfputm.o
|
||||
|
|
|
@ -4,6 +4,7 @@ cmd universe
|
|||
|
||||
hdr dirent,direntry,filio,fmtmsg,fnmatch,jioctl,libgen,limits
|
||||
hdr locale,ndir,nl_types,process,spawn,syslog,utime,vfork
|
||||
hdr linux/fs,sys/ioctl
|
||||
hdr wchar note{ <wchar.h> and isw*() really work }end execute{
|
||||
#include <wchar.h>
|
||||
int
|
||||
|
|
|
@ -317,6 +317,7 @@ extern int pathcheck(const char*, const char*, Pathcheck_t*);
|
|||
extern int pathexists(char*, int);
|
||||
extern char* pathfind(const char*, const char*, const char*, char*, size_t);
|
||||
extern int pathgetlink(const char*, char*, int);
|
||||
extern int pathicase(const char*);
|
||||
extern int pathinclude(const char*);
|
||||
extern char* pathkey(char*, char*, const char*, const char*, const char*);
|
||||
extern char* pathkey_20100601(const char*, const char*, const char*, char*, size_t, char*, size_t);
|
||||
|
|
|
@ -94,6 +94,11 @@ struct _glob_
|
|||
|
||||
};
|
||||
|
||||
/*
|
||||
* The standard/extended interface GLOB_* flags below must
|
||||
* fit in the GLOB_FLAGMASK bitmask defined in misc/glob.c.
|
||||
*/
|
||||
|
||||
/* standard interface */
|
||||
#define GLOB_APPEND 0x0001 /* append to previous */
|
||||
#define GLOB_DOOFFS 0x0002 /* gl_offs defines argv offset */
|
||||
|
@ -113,8 +118,8 @@ struct _glob_
|
|||
#define GLOB_LIST 0x2000 /* just create gl_list */
|
||||
#define GLOB_ALTDIRFUNC 0x4000 /* gnu discipline functions */
|
||||
#define GLOB_DISC 0x8000 /* discipline initialized */
|
||||
|
||||
#define GLOB_GROUP 0x10000 /* REG_SHELL_GROUP */
|
||||
#define GLOB_DCASE 0x20000 /* detect FS case insensitivity */
|
||||
|
||||
/* gl_status */
|
||||
#define GLOB_NOTDIR 0x0001 /* last gl_dirnext() not a dir */
|
||||
|
|
|
@ -50,6 +50,7 @@ char* pathcat(char* \fIpath\fP, const char* \fIdirs\fP, int \fIsep\fP, const
|
|||
char* pathcd(char* \fIpath\fP, const char* \fIhome\fP);
|
||||
int pathcheck(const char* \fIpackage\fP, const char* \fItool\fP, Pathcheck_t* \fIpc\fP);
|
||||
int pathgetlink(const char* \fIname\fP, char* \fIbuf\fP, int \fIsiz\fP);
|
||||
int pathicase(const char* \fIpath\fP);
|
||||
char* pathkey(char* \fIkey\fP, char* \fIattr\fP, const char* \fIlang\fP, const char* \fIpath\fP);
|
||||
char* pathnext(char* \fIpath\fP, char* \fIextra\fP, long* \fIvisits\fP);
|
||||
char* pathpath(char* \fIpath\fP, const char* \fIp\fP, const char* \fIa\fP, int \fImode\fP);
|
||||
|
@ -230,6 +231,32 @@ by converting non-standard dynamic link text to
|
|||
.L pathsetsymlink
|
||||
converts in the other direction.
|
||||
.PP
|
||||
.L pathicase
|
||||
uses an operating system-specific method, if available,
|
||||
to determine if a file system uses case-insensitive file names.
|
||||
The return value is
|
||||
.B 1
|
||||
if the file system associated with the
|
||||
.I path
|
||||
is case-insensitive (regardless of case preservation),
|
||||
.B 0
|
||||
if it is not, or
|
||||
.B \-1
|
||||
if an error occurred. On error,
|
||||
.L errno
|
||||
is set by the system-specific function that was used.
|
||||
If the operating system does not have a known method
|
||||
to determine file system case insensitivity for the
|
||||
.IR path ,
|
||||
then
|
||||
.L pathicase
|
||||
returns
|
||||
.B \-1
|
||||
with
|
||||
.L errno
|
||||
set to
|
||||
.LR ENOSYS .
|
||||
.PP
|
||||
.L pathkey
|
||||
generates in
|
||||
.I key
|
||||
|
|
|
@ -37,7 +37,12 @@
|
|||
#include <ctype.h>
|
||||
#include <regex.h>
|
||||
|
||||
#define GLOB_MAGIC 0xaaaa0000
|
||||
/*
|
||||
* GLOB_MAGIC is used for sanity checking. Its significant bits must not overlap with those used
|
||||
* for flags. If a new GLOB_* flag bit is added to glob.h, these must be adapted accordingly.
|
||||
*/
|
||||
#define GLOB_MAGIC 0xAAA80000 /* 10101010101010000000000000000000 */
|
||||
#define GLOB_FLAGMASK 0x0003FFFF /* 00000000000000111111111111111111 */
|
||||
|
||||
#define MATCH_RAW 1
|
||||
#define MATCH_MAKE 2
|
||||
|
@ -143,7 +148,9 @@ gl_type(glob_t* gp, const char* path, int flags)
|
|||
static int
|
||||
gl_attr(glob_t* gp, const char* path, int flags)
|
||||
{
|
||||
return strchr(astconf("PATH_ATTRIBUTES", path, NiL), 'c') ? GLOB_ICASE : 0;
|
||||
NOT_USED(gp);
|
||||
NOT_USED(flags);
|
||||
return pathicase(path) > 0 ? GLOB_ICASE : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -485,7 +492,9 @@ skip:
|
|||
|| t1 == GLOB_SYM && pat[0]=='*' && pat[1]=='\0') /* follow symlinks to dirs for non-globstar components */
|
||||
&& (dirf = (*gp->gl_diropen)(gp, dirname)))
|
||||
{
|
||||
if (!(gp->re_flags & REG_ICASE) && ((*gp->gl_attr)(gp, dirname, 0) & GLOB_ICASE))
|
||||
if (!(gp->re_flags & REG_ICASE)
|
||||
&& (gp->gl_flags & GLOB_DCASE)
|
||||
&& ((*gp->gl_attr)(gp, dirname, 0) & GLOB_ICASE))
|
||||
{
|
||||
if (!prei)
|
||||
{
|
||||
|
@ -613,7 +622,7 @@ glob(const char* pattern, int flags, int (*errfn)(const char*, int), register gl
|
|||
}
|
||||
else
|
||||
{
|
||||
gp->gl_flags = (flags&0xffff)|GLOB_MAGIC;
|
||||
gp->gl_flags = (flags & GLOB_FLAGMASK) | GLOB_MAGIC;
|
||||
gp->re_flags = REG_SHELL|REG_NOSUB|REG_LEFT|REG_RIGHT|((flags&GLOB_AUGMENTED)?REG_AUGMENTED:0);
|
||||
gp->gl_pathc = 0;
|
||||
gp->gl_ignore = 0;
|
||||
|
@ -730,7 +739,7 @@ glob(const char* pattern, int flags, int (*errfn)(const char*, int), register gl
|
|||
f &= ~GLOB_STARSTAR;
|
||||
continue;
|
||||
case ')':
|
||||
flags = (gp->gl_flags = f) & 0xffff;
|
||||
flags = (gp->gl_flags = f) & GLOB_FLAGMASK;
|
||||
if (f & GLOB_ICASE)
|
||||
gp->re_flags |= REG_ICASE;
|
||||
else
|
||||
|
|
|
@ -63,7 +63,7 @@ pathexists(char* path, int mode)
|
|||
|
||||
t = &tree;
|
||||
e = (c = *path) == '/' ? path + 1 : path;
|
||||
cmp = strchr(astconf("PATH_ATTRIBUTES", path, NiL), 'c') ? strcasecmp : strcmp;
|
||||
cmp = pathicase(path) > 0 ? strcasecmp : strcmp;
|
||||
if ((ast.locale.set & (AST_LC_debug|AST_LC_find)) == (AST_LC_debug|AST_LC_find))
|
||||
sfprintf(sfstderr, "locale test %s\n", path);
|
||||
while (c)
|
||||
|
|
59
src/lib/libast/path/pathicase.c
Normal file
59
src/lib/libast/path/pathicase.c
Normal file
|
@ -0,0 +1,59 @@
|
|||
/***********************************************************************
|
||||
* *
|
||||
* This file is part of the ksh 93u+m package *
|
||||
* Copyright (c) 2021 Contributors to ksh 93u+m *
|
||||
* <https://github.com/ksh93/ksh> *
|
||||
* and is licensed under the *
|
||||
* Eclipse Public License, Version 1.0 *
|
||||
* *
|
||||
* A copy of the License is available at *
|
||||
* http://www.eclipse.org/org/documents/epl-v10.html *
|
||||
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
|
||||
* *
|
||||
* Martijn Dekker <martijn@inlv.org> *
|
||||
* *
|
||||
***********************************************************************/
|
||||
|
||||
#include <ast.h>
|
||||
#include <error.h>
|
||||
|
||||
#if _hdr_linux_fs && _hdr_sys_ioctl
|
||||
#include <linux/fs.h>
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Return 1 if the given path is on a case insensitive file system, 0 if not, -1 on error.
|
||||
*/
|
||||
int
|
||||
pathicase(const char *path)
|
||||
{
|
||||
#ifdef _PC_PATH_ATTRIBUTES
|
||||
/* AT&T mystery system (AST UWIN?) */
|
||||
char *a = astconf("PATH_ATTRIBUTES", path, (char*)0);
|
||||
return a ? strchr(a,'c') != 0 : -1;
|
||||
#elif _lib_pathconf && defined(_PC_CASE_SENSITIVE)
|
||||
/* macOS; QNX 7.0+ */
|
||||
long r = pathconf(path, _PC_CASE_SENSITIVE);
|
||||
return r < 0L ? -1 : r == 0L;
|
||||
#elif _lib_pathconf && defined(_PC_CASE_INSENSITIVE)
|
||||
/* Cygwin */
|
||||
long r = pathconf(path, _PC_CASE_INSENSITIVE);
|
||||
return r < 0L ? -1 : r > 0L;
|
||||
#elif _hdr_linux_fs && _hdr_sys_ioctl && defined(FS_IOC_GETFLAGS) && defined(FS_CASEFOLD_FL)
|
||||
/* Linux 5.2+ */
|
||||
int attr = 0, fd, r;
|
||||
if ((fd = open(path, O_RDONLY|O_NONBLOCK)) < 0)
|
||||
return -1;
|
||||
r = ioctl(fd, FS_IOC_GETFLAGS, &attr);
|
||||
close(fd);
|
||||
return r < 0 ? -1 : attr & FS_CASEFOLD_FL != 0;
|
||||
#elif _WINIX || __APPLE__
|
||||
/* Windows or Mac without pathconf probe: assume case insensitive */
|
||||
return 1;
|
||||
#else
|
||||
/* Not implemented */
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
|
@ -221,11 +221,7 @@ static Feature_t dynamic[] =
|
|||
{
|
||||
&dynamic[OP_path_attributes+1],
|
||||
"PATH_ATTRIBUTES",
|
||||
#if _WINIX
|
||||
"c",
|
||||
#else
|
||||
&null[0],
|
||||
#endif
|
||||
&null[0],
|
||||
0,
|
||||
15,
|
||||
|
@ -706,6 +702,8 @@ format(register Feature_t* fp, const char* path, const char* value, unsigned int
|
|||
}
|
||||
*s = 0;
|
||||
}
|
||||
#else
|
||||
fp->value = pathicase(path) > 0 ? "c" : null;
|
||||
#endif
|
||||
break;
|
||||
|
||||
|
|
Loading…
Reference in a new issue