mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
Allow proper tilde expansion overrides (#225)
Until now, when performing any tilde expansion like ~/foo or ~user/foo, ksh added a placeholder built-in command called '.sh.tilde', ostensibly with the intention to allow users to override it with a shell function or custom builtin. The multishell ksh93 repo <https://github.com/multishell/ksh93/> shows this was added sometime between 2002-06-28 and 2004-02-29. However, it has never worked and crashed the shell. This commit replaces that with something that works. Specific tilde expansions can now be overridden using .set or .get discipline functions associated with the .sh.tilde variable (see manual, Discipline Functions). For example, you can use either of: .sh.tilde.set() { case ${.sh.value} in '~tmp') .sh.value=${XDG_RUNTIME_DIR:-${TMPDIR:-/tmp}} ;; '~doc') .sh.value=~/Documents ;; '~ksh') .sh.value=/usr/local/src/ksh93/ksh ;; esac } .sh.tilde.get() { case ${.sh.tilde} in '~tmp') .sh.value=${XDG_RUNTIME_DIR:-${TMPDIR:-/tmp}} ;; '~doc') .sh.value=~/Documents ;; '~ksh') .sh.value=/usr/local/src/ksh93/ksh ;; esac } src/cmd/ksh93/include/variables.h, src/cmd/ksh93/data/variables.c: - Add SH_TILDENOD for a new ${.sh.tilde} predefined variable. It is initially unset. src/cmd/ksh93/sh/macro.c: - sh_btilde(): Removed. - tilde_expand2(): Rewritten. I started out with the tiny version of this function from the 2002-06-28 version of ksh. It uses the stack instead of sfio, which is more efficient. A bugfix for $HOME == '/' was retrofitted so that ~/foo does not become //foo instead of /foo. The rest is entirely new code. To implement the override functionality, it now checks if ${.sh.tilde} has any discipline function associated with it. If it does, it assigns the tilde expression to ${.sh.tilde} using nv_putval(), triggering the .set discipline, and then reads it back using nv_getval(), triggering the .get discipline. The resulting value is used if it is nonempty and does not still start with a tilde. src/cmd/ksh93/bltins/typeset.c, src/cmd/ksh93/tests/builtins.sh: - Since ksh no longer adds a dummy '.sh.tilde' builtin, remove the ad-hoc hack that suppressed it from the output of 'builtin'. src/cmd/ksh93/tests/tilde.sh: - Add tests verifying everything I can think of, as well as tests for bugs found and fixed during this rewrite. src/cmd/ksh93/tests/pty.sh: - Add test verifying that the .sh.tilde.set() discipline does not modify the exit status value ($?) when performing tilde expansion as part of tab completion. src/cmd/ksh93/sh.1: - Instead of "tilde substitution", call the basic mechanism "tilde expansion", which is the term used everywhere else (including the 1995 Bolsky/Korn ksh book). - Document the new override feature. Resolves: https://github.com/ksh93/ksh/issues/217
This commit is contained in:
parent
595a0a5684
commit
936a1939a8
11 changed files with 190 additions and 76 deletions
|
@ -2619,64 +2619,44 @@ static int charlen(const char *string,int len)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the default tilde discipline function
|
||||
*/
|
||||
static int sh_btilde(int argc, char *argv[], Shbltin_t *context)
|
||||
{
|
||||
Shell_t *shp = context->shp;
|
||||
char *cp = sh_tilde(shp,argv[1]);
|
||||
NOT_USED(argc);
|
||||
if(!cp)
|
||||
cp = argv[1];
|
||||
sfputr(sfstdout, cp, '\n');
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* <offset> is byte offset for beginning of tilde string
|
||||
*/
|
||||
static void tilde_expand2(Shell_t *shp, register int offset)
|
||||
{
|
||||
char shtilde[10], *av[3], *ptr=stkfreeze(shp->stk,1);
|
||||
Sfio_t *iop, *save=sfstdout;
|
||||
Namval_t *np;
|
||||
static int beenhere=0;
|
||||
strcpy(shtilde,".sh.tilde");
|
||||
np = nv_open(shtilde,shp->fun_tree, NV_VARNAME|NV_NOARRAY|NV_NOASSIGN|NV_NOFAIL);
|
||||
if(np && !beenhere)
|
||||
char *cp = NIL(char*); /* character pointer for tilde expansion result */
|
||||
char *stakp = stakptr(0); /* current stack object (&stakp[offset] is tilde string) */
|
||||
int curoff = staktell(); /* current offset of current stack object */
|
||||
static char block; /* for disallowing tilde expansion in .get/.set to change ${.sh.tilde} */
|
||||
/*
|
||||
* Allow overriding tilde expansion with a .sh.tilde.set or .get discipline function.
|
||||
*/
|
||||
if(!block && SH_TILDENOD->nvfun && SH_TILDENOD->nvfun->disc)
|
||||
{
|
||||
beenhere = 1;
|
||||
sh_addbuiltin(shtilde,sh_btilde,0);
|
||||
nv_onattr(np,NV_EXPORT);
|
||||
stakfreeze(1); /* terminate current stack object to avoid data corruption */
|
||||
block++;
|
||||
nv_putval(SH_TILDENOD, &stakp[offset], 0);
|
||||
cp = nv_getval(SH_TILDENOD);
|
||||
block--;
|
||||
if(cp[0]=='\0' || cp[0]=='~')
|
||||
cp = NIL(char*); /* do not use empty or unexpanded result */
|
||||
stakset(stakp,curoff); /* restore stack to state on function entry */
|
||||
}
|
||||
av[0] = ".sh.tilde";
|
||||
av[1] = &ptr[offset];
|
||||
av[2] = 0;
|
||||
iop = sftmp((IOBSIZE>PATH_MAX?IOBSIZE:PATH_MAX)+1);
|
||||
sfset(iop,SF_READ,0);
|
||||
sfstdout = iop;
|
||||
if(np)
|
||||
sh_fun(np, (Namval_t*)0, av);
|
||||
else
|
||||
sh_btilde(2, av, &shp->bltindata);
|
||||
sfstdout = save;
|
||||
stkset(shp->stk,ptr, offset);
|
||||
sfseek(iop,(Sfoff_t)0,SEEK_SET);
|
||||
sfset(iop,SF_READ,1);
|
||||
if(ptr = sfreserve(iop, SF_UNBOUND, -1))
|
||||
/*
|
||||
* Perform default tilde expansion unless overridden.
|
||||
* Write the result to the stack, if any.
|
||||
*/
|
||||
stakputc(0);
|
||||
if(!cp)
|
||||
cp = sh_tilde(shp,&stakp[offset]);
|
||||
if(cp)
|
||||
{
|
||||
Sfoff_t n = sfvalue(iop);
|
||||
while(ptr[n-1]=='\n')
|
||||
n--;
|
||||
if(n==1 && fcpeek(0)=='/' && ptr[n-1])
|
||||
n--;
|
||||
if(n)
|
||||
sfwrite(shp->stk,ptr,n);
|
||||
stakseek(offset);
|
||||
if(!(cp[0]=='/' && !cp[1] && fcpeek(0)=='/'))
|
||||
stakputs(cp); /* for ~ == /, avoid ~/foo -> //foo */
|
||||
}
|
||||
else
|
||||
sfputr(shp->stk,av[1],0);
|
||||
sfclose(iop);
|
||||
stakseek(curoff);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue