mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-09-10 12:40:58 +02:00
12242: based on code from Fr. Br. George (George V Kouryachy):
use negative integers in prompt to count from other end of string
This commit is contained in:
parent
b46926af8d
commit
fa699be45d
3 changed files with 348 additions and 171 deletions
|
@ -1,3 +1,9 @@
|
|||
2000-07-13 Peter Stephenson <pws@cambridgesiliconradio.com>
|
||||
|
||||
* 12242: Fr. Br. George (George V Kouryachy) and pws:
|
||||
Doc/Zsh/prompt.yo, Src/prompt.c: negative integers in prompt
|
||||
escapes count from the other end of the appropriate string.
|
||||
|
||||
2000-07-13 Sven Wischnowsky <wischnow@zsh.org>
|
||||
|
||||
* 12241: Completion/Core/_main_complete, Src/Zle/computil.c: fix
|
||||
|
|
|
@ -44,7 +44,8 @@ xitem(tt(%d))
|
|||
item(tt(%/))(
|
||||
Present working directory (tt($PWD)). If an integer follows the `tt(%)',
|
||||
it specifies a number of trailing components of tt($PWD) to show; zero
|
||||
means the whole path.
|
||||
means the whole path. A negative integer specifies leading components,
|
||||
i.e. tt(%-1d) specifies the first component.
|
||||
)
|
||||
item(tt(%~))(
|
||||
As tt(%d) and tt(%/), but if tt($PWD) has a named directory as its prefix,
|
||||
|
@ -64,7 +65,8 @@ The full machine hostname.
|
|||
item(tt(%m))(
|
||||
The hostname up to the first `tt(.)'.
|
||||
An integer may follow the `tt(%)' to specify
|
||||
how many components of the hostname are desired.
|
||||
how many components of the hostname are desired. With a negative integer,
|
||||
trailing components of the hostname are shown.
|
||||
)
|
||||
item(tt(%S) LPAR()tt(%s)RPAR())(
|
||||
Start (stop) standout mode.
|
||||
|
@ -93,7 +95,7 @@ The name of the script, sourced file, or shell function that zsh is
|
|||
currently executing, whichever was started most recently. If there is
|
||||
none, this is equivalent to the parameter tt($0). An integer may follow
|
||||
the `tt(%)' to specify a number of trailing path components to show; zero
|
||||
means the full path.
|
||||
means the full path. A negative integer specifies leading components.
|
||||
)
|
||||
item(tt(%i))(
|
||||
The line number currently being executed in the script, sourced file, or
|
||||
|
@ -126,7 +128,7 @@ The return code of the last command executed just before the prompt.
|
|||
item(tt(%_))(
|
||||
The status of the parser, i.e. the shell constructs (like `tt(if)' and
|
||||
`tt(for)') that have been started on the command line. If given an integer
|
||||
number that many strings will be printed; zero or no integer means
|
||||
number that many strings will be printed; zero or negative or no integer means
|
||||
print as many as there are. This is most useful in prompts tt(PS2) for
|
||||
continuation lines and tt(PS4) for debugging with the tt(XTRACE) option; in
|
||||
the latter case it will also work non-interactively.
|
||||
|
@ -145,7 +147,8 @@ capability vectors.
|
|||
item(tt(%v))(
|
||||
vindex(psvar, use of)
|
||||
The value of the first element of the tt(psvar) array parameter. Following
|
||||
the `tt(%)' with an integer gives that element of the array.
|
||||
the `tt(%)' with an integer gives that element of the array. Negative
|
||||
integers count from the end of the array.
|
||||
)
|
||||
item(tt(%{)...tt(%}))(
|
||||
Include a string as a literal escape sequence.
|
||||
|
@ -163,10 +166,9 @@ var(true-text)
|
|||
and var(false-text) may both contain arbitrarily-nested escape
|
||||
sequences, including further ternary expressions.
|
||||
|
||||
The left
|
||||
parenthesis may be preceded or followed by a positive integer var(n),
|
||||
which defaults to zero. The test character var(x) may be any of the
|
||||
following:
|
||||
The left parenthesis may be preceded or followed by a positive integer var(n),
|
||||
which defaults to zero. A negative integer will be multiplied by -1.
|
||||
The test character var(x) may be any of the following:
|
||||
|
||||
startsitem()
|
||||
sxitem(tt(c))
|
||||
|
|
465
Src/prompt.c
465
Src/prompt.c
|
@ -38,7 +38,7 @@ unsigned txtattrmask;
|
|||
/* text change - attribute change made by prompts */
|
||||
|
||||
/**/
|
||||
unsigned txtchange;
|
||||
mod_export unsigned txtchange;
|
||||
|
||||
/* the command stack for use with %_ in prompts */
|
||||
|
||||
|
@ -71,6 +71,10 @@ static int bufspc;
|
|||
|
||||
static char *bp;
|
||||
|
||||
/* Position of the start of the current line in the buffer */
|
||||
|
||||
static char *bufline;
|
||||
|
||||
/* bp1 is an auxilliary pointer into the buffer, which when non-NULL is *
|
||||
* moved whenever the buffer is reallocated. It is used when data is *
|
||||
* being temporarily held in the buffer. */
|
||||
|
@ -81,11 +85,9 @@ static char *bp1;
|
|||
|
||||
static char *fm;
|
||||
|
||||
/* Current truncation string (metafied), the length at which truncation *
|
||||
* occurs, and the direction in which it occurs. */
|
||||
/* Non-zero if truncating the current segment of the buffer. */
|
||||
|
||||
static char *truncstr;
|
||||
static int trunclen, truncatleft;
|
||||
static int trunclen;
|
||||
|
||||
/* Current level of nesting of %{ / %} sequences. */
|
||||
|
||||
|
@ -95,9 +97,48 @@ static int dontcount;
|
|||
|
||||
static char *rstring, *Rstring;
|
||||
|
||||
/* If non-zero, Inpar, Outpar and Nularg can be added to the buffer. */
|
||||
/*
|
||||
* Expand path p; maximum is npath segments where 0 means the whole path.
|
||||
* If tilde is 1, try and find a named directory to use.
|
||||
*/
|
||||
|
||||
static int nonsp;
|
||||
static void
|
||||
promptpath(char *p, int npath, int tilde)
|
||||
{
|
||||
char *modp = p;
|
||||
Nameddir nd;
|
||||
|
||||
if (tilde && ((nd = finddir(p))))
|
||||
modp = tricat("~", nd->nam, p + strlen(nd->dir));
|
||||
|
||||
if (npath) {
|
||||
char *sptr;
|
||||
if (npath > 0) {
|
||||
for (sptr = modp + strlen(modp); sptr > modp; sptr--) {
|
||||
if (*sptr == '/' && !--npath) {
|
||||
sptr++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*sptr == '/' && sptr[1] && sptr != modp)
|
||||
sptr++;
|
||||
stradd(sptr);
|
||||
} else {
|
||||
char cbu;
|
||||
for (sptr = modp+1; *sptr; sptr++)
|
||||
if (*sptr == '/' && !++npath)
|
||||
break;
|
||||
cbu = *sptr;
|
||||
*sptr = 0;
|
||||
stradd(modp);
|
||||
*sptr = cbu;
|
||||
}
|
||||
} else
|
||||
stradd(modp);
|
||||
|
||||
if (p != modp)
|
||||
zsfree(modp);
|
||||
}
|
||||
|
||||
/* Perform prompt expansion on a string, putting the result in a *
|
||||
* permanently-allocated string. If ns is non-zero, this string *
|
||||
|
@ -107,7 +148,7 @@ static int nonsp;
|
|||
* `glitch' space. */
|
||||
|
||||
/**/
|
||||
char *
|
||||
mod_export char *
|
||||
promptexpand(char *s, int ns, char *rs, char *Rs)
|
||||
{
|
||||
if(!s)
|
||||
|
@ -119,20 +160,18 @@ promptexpand(char *s, int ns, char *rs, char *Rs)
|
|||
if (isset(PROMPTSUBST)) {
|
||||
int olderr = errflag;
|
||||
|
||||
HEAPALLOC {
|
||||
s = dupstring(s);
|
||||
if (!parsestr(s))
|
||||
singsub(&s);
|
||||
} LASTALLOC;
|
||||
|
||||
/* Ignore errors in prompt substitution */
|
||||
errflag = olderr;
|
||||
}
|
||||
|
||||
rstring = rs;
|
||||
Rstring = Rs;
|
||||
nonsp = ns;
|
||||
fm = s;
|
||||
bp = buf = zalloc(bufspc = 256);
|
||||
bp = bufline = buf = zcalloc(bufspc = 256);
|
||||
bp1 = NULL;
|
||||
trunclen = 0;
|
||||
putpromptchar(1, '\0');
|
||||
|
@ -140,6 +179,17 @@ promptexpand(char *s, int ns, char *rs, char *Rs)
|
|||
if(dontcount)
|
||||
*bp++ = Outpar;
|
||||
*bp = 0;
|
||||
if (!ns) {
|
||||
/* If zero, Inpar, Outpar and Nularg should be removed. */
|
||||
for (bp = buf; *bp; ) {
|
||||
if (*bp == Meta)
|
||||
bp += 2;
|
||||
else if (*bp == Inpar || *bp == Outpar || *bp == Nularg)
|
||||
chuck(bp);
|
||||
else
|
||||
bp++;
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
@ -160,14 +210,26 @@ putpromptchar(int doprint, int endchar)
|
|||
for (; *fm && *fm != endchar; fm++) {
|
||||
arg = 0;
|
||||
if (*fm == '%' && isset(PROMPTPERCENT)) {
|
||||
if (idigit(*++fm)) {
|
||||
arg = zstrtol(fm, &fm, 10);
|
||||
int minus = 0;
|
||||
fm++;
|
||||
if (*fm == '-') {
|
||||
minus = 1;
|
||||
fm++;
|
||||
}
|
||||
if (idigit(*fm)) {
|
||||
arg = zstrtol(fm, &fm, 10);
|
||||
if (minus)
|
||||
arg *= -1;
|
||||
} else if (minus)
|
||||
arg = -1;
|
||||
if (*fm == '(') {
|
||||
int tc;
|
||||
int tc, otrunclen;
|
||||
|
||||
if (idigit(*++fm)) {
|
||||
arg = zstrtol(fm, &fm, 10);
|
||||
} else if (arg < 0) {
|
||||
/* negative numbers don't make sense here */
|
||||
arg *= -1;
|
||||
}
|
||||
test = 0;
|
||||
ss = pwd;
|
||||
|
@ -224,6 +286,12 @@ putpromptchar(int doprint, int endchar)
|
|||
if (getegid() == arg)
|
||||
test = 1;
|
||||
break;
|
||||
case 'l':
|
||||
*bp = '\0';
|
||||
countprompt(bufline, &t0, 0, 0);
|
||||
if (t0 >= arg)
|
||||
test = 1;
|
||||
break;
|
||||
case 'L':
|
||||
if (shlvl >= arg)
|
||||
test = 1;
|
||||
|
@ -249,10 +317,15 @@ putpromptchar(int doprint, int endchar)
|
|||
if (!*fm || !(sep = *++fm))
|
||||
return 0;
|
||||
fm++;
|
||||
/* Don't do the current truncation until we get back */
|
||||
otrunclen = trunclen;
|
||||
trunclen = 0;
|
||||
if (!putpromptchar(test == 1 && doprint, sep) || !*++fm ||
|
||||
!putpromptchar(test == 0 && doprint, ')')) {
|
||||
trunclen = otrunclen;
|
||||
return 0;
|
||||
}
|
||||
trunclen = otrunclen;
|
||||
continue;
|
||||
}
|
||||
if (!doprint)
|
||||
|
@ -276,49 +349,21 @@ putpromptchar(int doprint, int endchar)
|
|||
}
|
||||
switch (*fm) {
|
||||
case '~':
|
||||
if ((nd = finddir(pwd))) {
|
||||
char *t = tricat("~", nd->nam, pwd + strlen(nd->dir));
|
||||
stradd(t);
|
||||
zsfree(t);
|
||||
promptpath(pwd, arg, 1);
|
||||
break;
|
||||
}
|
||||
case 'd':
|
||||
case '/':
|
||||
stradd(pwd);
|
||||
promptpath(pwd, arg, 0);
|
||||
break;
|
||||
case 'c':
|
||||
case '.':
|
||||
{
|
||||
char *t;
|
||||
|
||||
if ((nd = finddir(pwd)))
|
||||
t = tricat("~", nd->nam, pwd + strlen(nd->dir));
|
||||
else
|
||||
t = ztrdup(pwd);
|
||||
if (!arg)
|
||||
arg++;
|
||||
for (ss = t + strlen(t); ss > t; ss--)
|
||||
if (*ss == '/' && !--arg) {
|
||||
ss++;
|
||||
promptpath(pwd, arg ? arg : 1, 1);
|
||||
break;
|
||||
}
|
||||
if(*ss == '/' && ss[1] && ss != t)
|
||||
ss++;
|
||||
stradd(ss);
|
||||
zsfree(t);
|
||||
break;
|
||||
}
|
||||
case 'C':
|
||||
if (!arg)
|
||||
arg++;
|
||||
for (ss = pwd + strlen(pwd); ss > pwd; ss--)
|
||||
if (*ss == '/' && !--arg) {
|
||||
ss++;
|
||||
promptpath(pwd, arg ? arg : 1, 0);
|
||||
break;
|
||||
}
|
||||
if (*ss == '/' && ss[1] && (ss != pwd))
|
||||
ss++;
|
||||
stradd(ss);
|
||||
case 'N':
|
||||
promptpath(scriptname ? scriptname : argzero, arg, 0);
|
||||
break;
|
||||
case 'h':
|
||||
case '!':
|
||||
|
@ -332,6 +377,12 @@ putpromptchar(int doprint, int endchar)
|
|||
case 'm':
|
||||
if (!arg)
|
||||
arg++;
|
||||
if (arg < 0) {
|
||||
for (ss = hostnam + strlen(hostnam); ss > hostnam; ss--)
|
||||
if (ss[-1] == '.' && !++arg)
|
||||
break;
|
||||
stradd(ss);
|
||||
} else {
|
||||
for (ss = hostnam; *ss; ss++)
|
||||
if (*ss == '.' && !--arg)
|
||||
break;
|
||||
|
@ -339,6 +390,7 @@ putpromptchar(int doprint, int endchar)
|
|||
*ss = '\0';
|
||||
stradd(hostnam);
|
||||
*ss = t0;
|
||||
}
|
||||
break;
|
||||
case 'S':
|
||||
txtchangeset(TXTSTANDOUT, TXTNOSTANDOUT);
|
||||
|
@ -378,71 +430,23 @@ putpromptchar(int doprint, int endchar)
|
|||
break;
|
||||
case '[':
|
||||
if (idigit(*++fm))
|
||||
trunclen = zstrtol(fm, &fm, 10);
|
||||
else
|
||||
trunclen = arg;
|
||||
if (trunclen) {
|
||||
truncatleft = *fm && *fm != ']' && *fm++ == '<';
|
||||
bp1 = bp;
|
||||
while (*fm && *fm != ']') {
|
||||
if (*fm == '\\' && fm[1])
|
||||
++fm;
|
||||
addbufspc(1);
|
||||
*bp++ = *fm++;
|
||||
}
|
||||
addbufspc(2);
|
||||
if (bp1 == bp)
|
||||
*bp++ = '<';
|
||||
*bp = '\0';
|
||||
zsfree(truncstr);
|
||||
truncstr = ztrdup(bp = bp1);
|
||||
bp1 = NULL;
|
||||
} else {
|
||||
while (*fm && *fm != ']') {
|
||||
if (*fm == '\\' && fm[1])
|
||||
fm++;
|
||||
fm++;
|
||||
}
|
||||
}
|
||||
if(!*fm)
|
||||
return 0;
|
||||
arg = zstrtol(fm, &fm, 10);
|
||||
if (!prompttrunc(arg, ']', doprint, endchar))
|
||||
return *fm;
|
||||
break;
|
||||
case '<':
|
||||
case '>':
|
||||
if((trunclen = arg)) {
|
||||
char ch = *fm++;
|
||||
truncatleft = ch == '<';
|
||||
bp1 = bp;
|
||||
while (*fm && *fm != ch) {
|
||||
if (*fm == '\\' && fm[1])
|
||||
++fm;
|
||||
addbufspc(1);
|
||||
*bp++ = *fm++;
|
||||
}
|
||||
addbufspc(1);
|
||||
*bp = '\0';
|
||||
zsfree(truncstr);
|
||||
truncstr = ztrdup(bp = bp1);
|
||||
bp1 = NULL;
|
||||
} else {
|
||||
char ch = *fm++;
|
||||
while(*fm && *fm != ch) {
|
||||
if (*fm == '\\' && fm[1])
|
||||
fm++;
|
||||
fm++;
|
||||
}
|
||||
}
|
||||
if(!*fm)
|
||||
return 0;
|
||||
if (!prompttrunc(arg, *fm, doprint, endchar))
|
||||
return *fm;
|
||||
break;
|
||||
case '{': /*}*/
|
||||
if (!dontcount++ && nonsp) {
|
||||
if (!dontcount++) {
|
||||
addbufspc(1);
|
||||
*bp++ = Inpar;
|
||||
}
|
||||
break;
|
||||
case /*{*/ '}':
|
||||
if (dontcount && !--dontcount && nonsp) {
|
||||
if (dontcount && !--dontcount) {
|
||||
addbufspc(1);
|
||||
*bp++ = Outpar;
|
||||
}
|
||||
|
@ -535,6 +539,8 @@ putpromptchar(int doprint, int endchar)
|
|||
case 'v':
|
||||
if (!arg)
|
||||
arg = 1;
|
||||
else if (arg < 0)
|
||||
arg += arrlen(psvar) + 1;
|
||||
if (arrlen(psvar) >= arg)
|
||||
stradd(psvar[arg - 1]);
|
||||
break;
|
||||
|
@ -562,6 +568,11 @@ putpromptchar(int doprint, int endchar)
|
|||
if(Rstring)
|
||||
stradd(Rstring);
|
||||
break;
|
||||
case 'i':
|
||||
addbufspc(DIGBUFSIZE);
|
||||
sprintf(bp, "%ld", (long)lineno);
|
||||
bp += strlen(bp);
|
||||
break;
|
||||
case '\0':
|
||||
return 0;
|
||||
case Meta:
|
||||
|
@ -569,7 +580,7 @@ putpromptchar(int doprint, int endchar)
|
|||
break;
|
||||
}
|
||||
} else if(*fm == '!' && isset(PROMPTBANG)) {
|
||||
if(doprint)
|
||||
if(doprint) {
|
||||
if(fm[1] == '!') {
|
||||
fm++;
|
||||
addbufspc(1);
|
||||
|
@ -579,6 +590,7 @@ putpromptchar(int doprint, int endchar)
|
|||
sprintf(bp, "%d", curhist);
|
||||
bp += strlen(bp);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
char c = *fm == Meta ? *++fm ^ 32 : *fm;
|
||||
|
||||
|
@ -604,6 +616,8 @@ pputc(char c)
|
|||
c ^= 32;
|
||||
}
|
||||
*bp++ = c;
|
||||
if (c == '\n' && !dontcount)
|
||||
bufline = bp;
|
||||
}
|
||||
|
||||
/* Make sure there is room for `need' more characters in the buffer. */
|
||||
|
@ -627,52 +641,25 @@ addbufspc(int need)
|
|||
}
|
||||
|
||||
/* stradd() adds a metafied string to the prompt, *
|
||||
* in a visible representation, doing truncation. */
|
||||
* in a visible representation. */
|
||||
|
||||
/**/
|
||||
void
|
||||
stradd(char *d)
|
||||
{
|
||||
/* dlen is the full length of the string we want to add */
|
||||
int dlen = niceztrlen(d);
|
||||
char *ps, *pd, *pc, *t;
|
||||
int tlen, maxlen;
|
||||
addbufspc(dlen);
|
||||
char *ps, *pc;
|
||||
addbufspc(niceztrlen(d));
|
||||
/* This loop puts the nice representation of the string into the prompt *
|
||||
* buffer. It might be modified later. Note that bp isn't changed. */
|
||||
for(ps=d, pd=bp; *ps; ps++)
|
||||
* buffer. */
|
||||
for(ps=d; *ps; ps++)
|
||||
for(pc=nicechar(*ps == Meta ? STOUC(*++ps)^32 : STOUC(*ps)); *pc; pc++)
|
||||
*pd++ = *pc;
|
||||
if(!trunclen || dlen <= trunclen) {
|
||||
/* No truncation is needed, so update bp and return, *
|
||||
* leaving the full string in the prompt. */
|
||||
bp += dlen;
|
||||
return;
|
||||
}
|
||||
/* We need to truncate. t points to the truncation string -- which is *
|
||||
* inserted literally, without nice representation. tlen is its *
|
||||
* length, and maxlen is the amout of the main string that we want to *
|
||||
* keep. Note that if the truncation string is longer than the *
|
||||
* truncation length (tlen > trunclen), the truncation string is used *
|
||||
* in full. */
|
||||
addbufspc(tlen = ztrlen(t = truncstr));
|
||||
maxlen = tlen < trunclen ? trunclen - tlen : 0;
|
||||
if(truncatleft) {
|
||||
memmove(bp + strlen(t), bp + dlen - maxlen, maxlen);
|
||||
while(*t)
|
||||
*bp++ = *t++;
|
||||
bp += maxlen;
|
||||
} else {
|
||||
bp += maxlen;
|
||||
while(*t)
|
||||
*bp++ = *t++;
|
||||
}
|
||||
*bp++ = *pc;
|
||||
}
|
||||
|
||||
/* tsetcap(), among other things, can write a termcap string into the buffer. */
|
||||
|
||||
/**/
|
||||
void
|
||||
mod_export void
|
||||
tsetcap(int cap, int flag)
|
||||
{
|
||||
if (!(termflags & TERM_SHORT) && tcstr[cap]) {
|
||||
|
@ -684,12 +671,12 @@ tsetcap(int cap, int flag)
|
|||
tputs(tcstr[cap], 1, putshout);
|
||||
break;
|
||||
case 1:
|
||||
if (!dontcount && nonsp) {
|
||||
if (!dontcount) {
|
||||
addbufspc(1);
|
||||
*bp++ = Inpar;
|
||||
}
|
||||
tputs(tcstr[cap], 1, putstr);
|
||||
if (!dontcount && nonsp) {
|
||||
if (!dontcount) {
|
||||
int glitch = 0;
|
||||
|
||||
if (cap == TCSTANDOUTBEG || cap == TCSTANDOUTEND)
|
||||
|
@ -729,15 +716,20 @@ putstr(int d)
|
|||
|
||||
/* Count height etc. of a prompt string returned by promptexpand(). *
|
||||
* This depends on the current terminal width, and tabs and *
|
||||
* newlines require nontrivial processing. */
|
||||
* newlines require nontrivial processing. *
|
||||
* Passing `overf' as -1 means to ignore columns (absolute width). */
|
||||
|
||||
/**/
|
||||
void
|
||||
countprompt(char *str, int *wp, int *hp)
|
||||
mod_export void
|
||||
countprompt(char *str, int *wp, int *hp, int overf)
|
||||
{
|
||||
int w = 0, h = 1;
|
||||
int s = 1;
|
||||
for(; *str; str++) {
|
||||
if(w >= columns && overf >= 0) {
|
||||
w = 0;
|
||||
h++;
|
||||
}
|
||||
if(*str == Meta)
|
||||
str++;
|
||||
if(*str == Inpar)
|
||||
|
@ -749,12 +741,15 @@ countprompt(char *str, int *wp, int *hp)
|
|||
else if(s) {
|
||||
if(*str == '\t')
|
||||
w = (w | 7) + 1;
|
||||
else if(*str == '\n')
|
||||
w = columns;
|
||||
else
|
||||
else if(*str == '\n') {
|
||||
w = 0;
|
||||
h++;
|
||||
} else
|
||||
w++;
|
||||
}
|
||||
if(w >= columns) {
|
||||
}
|
||||
if(w >= columns && overf >= 0) {
|
||||
if (!overf || w > columns) {
|
||||
w = 0;
|
||||
h++;
|
||||
}
|
||||
|
@ -764,3 +759,177 @@ countprompt(char *str, int *wp, int *hp)
|
|||
if(hp)
|
||||
*hp = h;
|
||||
}
|
||||
|
||||
/**/
|
||||
static int
|
||||
prompttrunc(int arg, int truncchar, int doprint, int endchar)
|
||||
{
|
||||
if (arg > 0) {
|
||||
char ch = *fm, *ptr, *truncstr;
|
||||
int truncatleft = ch == '<';
|
||||
int w = bp - buf;
|
||||
|
||||
/*
|
||||
* If there is already a truncation active, return so that
|
||||
* can be finished, backing up so that the new truncation
|
||||
* can be started afterwards.
|
||||
*/
|
||||
if (trunclen) {
|
||||
while (*--fm != '%')
|
||||
;
|
||||
fm--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
trunclen = arg;
|
||||
if (*fm != ']')
|
||||
fm++;
|
||||
while (*fm && *fm != truncchar) {
|
||||
if (*fm == '\\' && fm[1])
|
||||
++fm;
|
||||
addbufspc(1);
|
||||
*bp++ = *fm++;
|
||||
}
|
||||
if (!*fm)
|
||||
return 0;
|
||||
if (bp - buf == w && truncchar == ']') {
|
||||
addbufspc(1);
|
||||
*bp++ = '<';
|
||||
}
|
||||
ptr = buf + w; /* addbufspc() may have realloc()'d buf */
|
||||
truncstr = ztrduppfx(ptr, bp - ptr);
|
||||
|
||||
bp = ptr;
|
||||
w = bp - buf;
|
||||
fm++;
|
||||
putpromptchar(doprint, endchar);
|
||||
ptr = buf + w; /* putpromptchar() may have realloc()'d */
|
||||
*bp = '\0';
|
||||
|
||||
countprompt(ptr, &w, 0, -1);
|
||||
if (w > trunclen) {
|
||||
/*
|
||||
* We need to truncate. t points to the truncation string -- *
|
||||
* which is inserted literally, without nice representation. *
|
||||
* tlen is its length, and maxlen is the amount of the main *
|
||||
* string that we want to keep. Note that if the truncation *
|
||||
* string is longer than the truncation length (tlen > *
|
||||
* trunclen), the truncation string is used in full. *
|
||||
*/
|
||||
char *t = truncstr;
|
||||
int fullen = bp - ptr;
|
||||
int tlen = ztrlen(t), maxlen;
|
||||
maxlen = tlen < trunclen ? trunclen - tlen : 0;
|
||||
if (w < fullen) {
|
||||
/* Invisible substrings, lots of shuffling. */
|
||||
int n = strlen(t);
|
||||
char *p = ptr, *q = buf;
|
||||
addbufspc(n);
|
||||
ptr = buf + (p - q); /* addbufspc() may have realloc()'d */
|
||||
|
||||
if (truncatleft) {
|
||||
p = ptr + n;
|
||||
q = p;
|
||||
|
||||
n = fullen - w;
|
||||
|
||||
/* Shift the whole string right, then *
|
||||
* selectively copy to the left. */
|
||||
memmove(p, ptr, fullen);
|
||||
while (w > 0 || n > 0) {
|
||||
if (*p == Inpar)
|
||||
do {
|
||||
*q++ = *p;
|
||||
--n;
|
||||
} while (*p++ != Outpar && *p && n);
|
||||
else if (w) {
|
||||
if (--w < maxlen)
|
||||
*q++ = *p;
|
||||
++p;
|
||||
}
|
||||
}
|
||||
bp = q;
|
||||
} else {
|
||||
/* Truncate on the right, selectively */
|
||||
q = ptr + fullen;
|
||||
|
||||
/* First skip over as much as will "fit". */
|
||||
while (w > 0 && maxlen > 0) {
|
||||
if (*ptr == Inpar)
|
||||
while (*ptr++ != Outpar && *ptr) {;}
|
||||
else
|
||||
++ptr, --w, --maxlen;
|
||||
}
|
||||
if (ptr < q) {
|
||||
/* We didn't reach the end of the string. *
|
||||
* In case there are more invisible bits, *
|
||||
* insert the truncstr and keep looking. */
|
||||
memmove(ptr + n, ptr, q - ptr);
|
||||
q = ptr + n;
|
||||
while (*t)
|
||||
*ptr++ = *t++;
|
||||
while (*q) {
|
||||
if (*q == Inpar)
|
||||
do {
|
||||
*ptr++ = *q;
|
||||
} while (*q++ != Outpar && *q);
|
||||
else
|
||||
++q;
|
||||
}
|
||||
bp = ptr;
|
||||
*bp = 0;
|
||||
} else
|
||||
bp = ptr + n;
|
||||
}
|
||||
} else {
|
||||
/* No invisible substrings. */
|
||||
if (tlen > fullen) {
|
||||
addbufspc(tlen - fullen);
|
||||
ptr = bp; /* addbufspc() may have realloc()'d buf */
|
||||
bp += tlen - fullen;
|
||||
} else
|
||||
bp -= fullen - trunclen;
|
||||
if (truncatleft) {
|
||||
if (maxlen)
|
||||
memmove(ptr + strlen(t), ptr + fullen - maxlen,
|
||||
maxlen);
|
||||
} else
|
||||
ptr += maxlen;
|
||||
}
|
||||
/* Finally, copy the truncstr into place. */
|
||||
while (*t)
|
||||
*ptr++ = *t++;
|
||||
}
|
||||
zsfree(truncstr);
|
||||
trunclen = 0;
|
||||
/*
|
||||
* We may have returned early from the previous putpromptchar *
|
||||
* because we found another truncation following this one. *
|
||||
* In that case we need to do the rest now. *
|
||||
*/
|
||||
if (!*fm)
|
||||
return 0;
|
||||
if (*fm != endchar) {
|
||||
fm++;
|
||||
/*
|
||||
* With trunclen set to zero, we always reach endchar *
|
||||
* (or the terminating NULL) this time round. *
|
||||
*/
|
||||
if (!putpromptchar(doprint, endchar))
|
||||
return 0;
|
||||
}
|
||||
/* Now we have to trick it into matching endchar again */
|
||||
fm--;
|
||||
} else {
|
||||
if (*fm != ']')
|
||||
fm++;
|
||||
while(*fm && *fm != truncchar) {
|
||||
if (*fm == '\\' && fm[1])
|
||||
fm++;
|
||||
fm++;
|
||||
}
|
||||
if (trunclen || !*fm)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue