diff -r 000000000000 -r 2e3d3ce01487 openenvutils/commandshell/shell/src/prompt.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openenvutils/commandshell/shell/src/prompt.c Tue Feb 02 10:12:00 2010 +0200 @@ -0,0 +1,1035 @@ +// prompt.c - construct zsh prompts +// +// © Portions Copyright (c) Symbian Software Ltd 2007. All rights reserved. +// +/* + * This file is part of zsh, the Z shell. + * + * Copyright (c) 1992-1997 Paul Falstad + * All rights reserved. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and to distribute modified versions of this software for any + * purpose, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * In no event shall Paul Falstad or the Zsh Development Group be liable + * to any party for direct, indirect, special, incidental, or consequential + * damages arising out of the use of this software and its documentation, + * even if Paul Falstad and the Zsh Development Group have been advised of + * the possibility of such damage. + * + * Paul Falstad and the Zsh Development Group specifically disclaim any + * warranties, including, but not limited to, the implied warranties of + * merchantability and fitness for a particular purpose. The software + * provided hereunder is on an "as is" basis, and Paul Falstad and the + * Zsh Development Group have no obligation to provide maintenance, + * support, updates, enhancements, or modifications. + * + */ + +#include "zsh.mdh" +#include "prompt.pro" + +#ifdef __SYMBIAN32__ +#ifdef __WINSCW__ +#pragma warn_possunwant off +#endif//__WINSCW__ +#endif//__SYMBIAN32__ + +/* text attribute mask */ + +/**/ +unsigned txtattrmask; + +/* text change - attribute change made by prompts */ + +/**/ +mod_export unsigned txtchange; + +/* the command stack for use with %_ in prompts */ + +/**/ +unsigned char *cmdstack; +/**/ +int cmdsp; + +/* parser states, for %_ */ + +static char *cmdnames[CS_COUNT] = { + "for", "while", "repeat", "select", + "until", "if", "then", "else", + "elif", "math", "cond", "cmdor", + "cmdand", "pipe", "errpipe", "foreach", + "case", "function", "subsh", "cursh", + "array", "quote", "dquote", "bquote", + "cmdsubst", "mathsubst", "elif-then", "heredoc", + "heredocd", "brace", "braceparam", "always", +}; + +/* The buffer into which an expanded and metafied prompt is being written, * + * and its size. */ + +static char *buf; +static int bufspc; + +/* bp is the pointer to the current position in the buffer, where the next * + * character will be added. */ + +static char *bp; + +/* Position of the start of the current line in the buffer */ + +static char *bufline; + +/* bp1 is an auxiliary 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. */ + +static char *bp1; + +/* The format string, for %-expansion. */ + +static char *fm; + +/* Non-zero if truncating the current segment of the buffer. */ + +static int trunclen; + +/* Current level of nesting of %{ / %} sequences. */ + +static int dontcount; + +/* Level of %{ / %} surrounding a truncation segment. */ + +static int trunccount; + +/* Strings to use for %r and %R (for the spelling prompt). */ + +static char *rstring, *Rstring; + +/* + * 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 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 * + * may have embedded Inpar and Outpar, which indicate a toggling * + * between spacing and non-spacing parts of the prompt, and * + * Nularg, which (in a non-spacing sequence) indicates a * + * `glitch' space. */ + +/**/ +mod_export char * +promptexpand(char *s, int ns, char *rs, char *Rs) +{ + if(!s) + return ztrdup(""); + + if ((termflags & TERM_UNKNOWN) && (unset(INTERACTIVE))) + init_term(); + + if (isset(PROMPTSUBST)) { + int olderr = errflag; + int oldval = lastval; + + s = dupstring(s); + if (!parsestr(s)) + singsub(&s); + + /* Ignore errors and status change in prompt substitution */ + errflag = olderr; + lastval = oldval; + } + + rstring = rs; + Rstring = Rs; + fm = s; + bp = bufline = buf = zshcalloc(bufspc = 256); + bp1 = NULL; + trunclen = 0; + putpromptchar(1, '\0'); + addbufspc(1); + 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; +} + +/* Perform %- and !-expansion as required on a section of the prompt. The * + * section is ended by an instance of endchar. If doprint is 0, the valid * + * % sequences are merely skipped over, and nothing is stored. */ + +/**/ +static int +putpromptchar(int doprint, int endchar) +{ + char *ss, *tmbuf = NULL, *hostnam; + int t0, arg, test, sep, j, numjobs; + struct tm *tm; + time_t timet; + Nameddir nd; + + for (; *fm && *fm != endchar; fm++) { + arg = 0; + if (*fm == '%' && isset(PROMPTPERCENT)) { + 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, 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; + switch (tc = *fm) { + case 'c': + case '.': + case '~': + if ((nd = finddir(ss))) { + arg--; + ss += strlen(nd->dir); + } /*FALLTHROUGH*/ + case '/': + case 'C': + /* `/' gives 0, `/any' gives 1, etc. */ + if (*ss++ == '/' && *ss) + arg--; + for (; *ss; ss++) + if (*ss == '/') + arg--; + if (arg <= 0) + test = 1; + break; + case 't': + case 'T': + case 'd': + case 'D': + case 'w': + timet = time(NULL); + tm = localtime(&timet); + switch (tc) { + case 't': + test = (arg == tm->tm_min); + break; + case 'T': + test = (arg == tm->tm_hour); + break; + case 'd': + test = (arg == tm->tm_mday); + break; + case 'D': + test = (arg == tm->tm_mon); + break; + case 'w': + test = (arg == tm->tm_wday); + break; + } + break; + case '?': + if (lastval == arg) + test = 1; + break; + case '#': + if (geteuid() == (uid_t)arg) + test = 1; + break; + case 'g': + if (getegid() == (gid_t)arg) + test = 1; + break; + case 'j': + for (numjobs = 0, j = 1; j <= maxjob; j++) + if (jobtab[j].stat && jobtab[j].procs && + !(jobtab[j].stat & STAT_NOPRINT)) numjobs++; + if (numjobs >= 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; + break; + case 'S': + if (time(NULL) - shtimer.tv_sec >= arg) + test = 1; + break; + case 'v': + if (arrlen(psvar) >= arg) + test = 1; + break; + case '_': + test = (cmdsp >= arg); + break; + case '!': + test = privasserted(); + break; + default: + test = -1; + break; + } + 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) + switch(*fm) { + case '[': + while(idigit(*++fm)); + while(*++fm != ']'); + continue; + case '<': + while(*++fm != '<'); + continue; + case '>': + while(*++fm != '>'); + continue; + case 'D': + if(fm[1]=='{') + while(*++fm != '}'); + continue; + default: + continue; + } + switch (*fm) { + case '~': + promptpath(pwd, arg, 1); + break; + case 'd': + case '/': + promptpath(pwd, arg, 0); + break; + case 'c': + case '.': + promptpath(pwd, arg ? arg : 1, 1); + break; + case 'C': + promptpath(pwd, arg ? arg : 1, 0); + break; + case 'N': + promptpath(scriptname ? scriptname : argzero, arg, 0); + break; + case 'h': + case '!': + addbufspc(DIGBUFSIZE); + convbase(bp, curhist, 10); + bp += strlen(bp); + break; + case 'j': + for (numjobs = 0, j = 1; j <= maxjob; j++) + if (jobtab[j].stat && jobtab[j].procs && + !(jobtab[j].stat & STAT_NOPRINT)) numjobs++; + addbufspc(DIGBUFSIZE); + sprintf(bp, "%d", numjobs); + bp += strlen(bp); + break; + case 'M': + queue_signals(); + if ((hostnam = getsparam("HOST"))) + stradd(hostnam); + unqueue_signals(); + break; + case 'm': + if (!arg) + arg++; + queue_signals(); + if (!(hostnam = getsparam("HOST"))) + break; + 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; + stradd(*ss ? dupstrpfx(hostnam, ss - hostnam) : hostnam); + } + unqueue_signals(); + break; + case 'S': + txtchangeset(TXTSTANDOUT, TXTNOSTANDOUT); + txtset(TXTSTANDOUT); + tsetcap(TCSTANDOUTBEG, 1); + break; + case 's': + txtchangeset(TXTNOSTANDOUT, TXTSTANDOUT); + txtset(TXTDIRTY); + txtunset(TXTSTANDOUT); + tsetcap(TCSTANDOUTEND, 1); + break; + case 'B': + txtchangeset(TXTBOLDFACE, TXTNOBOLDFACE); + txtset(TXTDIRTY); + txtset(TXTBOLDFACE); + tsetcap(TCBOLDFACEBEG, 1); + break; + case 'b': + txtchangeset(TXTNOBOLDFACE, TXTBOLDFACE); + txtchangeset(TXTNOSTANDOUT, TXTSTANDOUT); + txtchangeset(TXTNOUNDERLINE, TXTUNDERLINE); + txtset(TXTDIRTY); + txtunset(TXTBOLDFACE); + tsetcap(TCALLATTRSOFF, 1); + break; + case 'U': + txtchangeset(TXTUNDERLINE, TXTNOUNDERLINE); + txtset(TXTUNDERLINE); + tsetcap(TCUNDERLINEBEG, 1); + break; + case 'u': + txtchangeset(TXTNOUNDERLINE, TXTUNDERLINE); + txtset(TXTDIRTY); + txtunset(TXTUNDERLINE); + tsetcap(TCUNDERLINEEND, 1); + break; + case '[': + if (idigit(*++fm)) + arg = zstrtol(fm, &fm, 10); + if (!prompttrunc(arg, ']', doprint, endchar)) + return *fm; + break; + case '<': + case '>': + if (!prompttrunc(arg, *fm, doprint, endchar)) + return *fm; + break; + case '{': /*}*/ + if (!dontcount++) { + addbufspc(1); + *bp++ = Inpar; + } + break; + case /*{*/ '}': + if (trunccount && trunccount >= dontcount) + return *fm; + if (dontcount && !--dontcount) { + addbufspc(1); + *bp++ = Outpar; + } + break; + case 't': + case '@': + case 'T': + case '*': + case 'w': + case 'W': + case 'D': + { + char *tmfmt, *dd; + + switch (*fm) { + case 'T': + tmfmt = "%K:%M"; + break; + case '*': + tmfmt = "%K:%M:%S"; + break; + case 'w': + tmfmt = "%a %f"; + break; + case 'W': + tmfmt = "%m/%d/%y"; + break; + case 'D': + if (fm[1] == '{' /*}*/) { + for (ss = fm + 2; *ss && *ss != /*{*/ '}'; ss++) + if(*ss == '\\' && ss[1]) + ss++; + dd = tmfmt = tmbuf = zalloc(ss - fm); + for (ss = fm + 2; *ss && *ss != /*{*/ '}'; + ss++) { + if(*ss == '\\' && ss[1]) + ss++; + *dd++ = *ss; + } + *dd = 0; + fm = ss - !*ss; + if (!*tmfmt) { + free(tmbuf); + continue; + } + } else + tmfmt = "%y-%m-%d"; + break; + default: + tmfmt = "%l:%M%p"; + break; + } + timet = time(NULL); + tm = localtime(&timet); + /* + * Hack because strftime won't say how + * much space it actually needs. Try to add it + * a few times until it works. Some formats don't + * actually have a length, so we could go on for + * ever. + */ + for(j = 0, t0 = strlen(tmfmt)*8; j < 3; j++, t0*=2) { + addbufspc(t0); + if (ztrftime(bp, t0, tmfmt, tm) >= 0) + break; + } + bp += strlen(bp); + free(tmbuf); + tmbuf = NULL; + break; + } + case 'n': + stradd(get_username()); + break; + case 'l': + if (*ttystrname) { + ss = (strncmp(ttystrname, "/dev/tty", 8) ? + ttystrname + 5 : ttystrname + 8); + stradd(ss); + } else + stradd("()"); + break; + case 'y': + if (*ttystrname) { + ss = (strncmp(ttystrname, "/dev/", 5) ? + ttystrname : ttystrname + 5); + stradd(ss); + } else + stradd("()"); + break; + case 'L': + addbufspc(DIGBUFSIZE); + sprintf(bp, "%ld", (long)shlvl); + bp += strlen(bp); + break; + case '?': + addbufspc(DIGBUFSIZE); + sprintf(bp, "%ld", (long)lastval); + bp += strlen(bp); + break; + case '%': + case ')': + addbufspc(1); + *bp++ = *fm; + break; + case '#': + addbufspc(1); + *bp++ = privasserted() ? '#' : '%'; + break; + case 'v': + if (!arg) + arg = 1; + else if (arg < 0) + arg += arrlen(psvar) + 1; + if (arg > 0 && arrlen(psvar) >= arg) + stradd(psvar[arg - 1]); + break; + case 'E': + tsetcap(TCCLEAREOL, 1); + break; + case '^': + if (cmdsp) { + if (arg >= 0) { + if (arg > cmdsp || arg == 0) + arg = cmdsp; + for (t0 = cmdsp - 1; arg--; t0--) { + stradd(cmdnames[cmdstack[t0]]); + if (arg) { + addbufspc(1); + *bp++=' '; + } + } + } else { + arg = -arg; + if (arg > cmdsp) + arg = cmdsp; + for (t0 = arg - 1; arg--; t0--) { + stradd(cmdnames[cmdstack[t0]]); + if (arg) { + addbufspc(1); + *bp++=' '; + } + } + } + } + break; + case '_': + if (cmdsp) { + if (arg >= 0) { + if (arg > cmdsp || arg == 0) + arg = cmdsp; + for (t0 = cmdsp - arg; arg--; t0++) { + stradd(cmdnames[cmdstack[t0]]); + if (arg) { + addbufspc(1); + *bp++=' '; + } + } + } else { + arg = -arg; + if (arg > cmdsp) + arg = cmdsp; + for (t0 = 0; arg--; t0++) { + stradd(cmdnames[cmdstack[t0]]); + if (arg) { + addbufspc(1); + *bp++=' '; + } + } + } + } + break; + case 'r': + if(rstring) + stradd(rstring); + break; + case 'R': + if(Rstring) + stradd(Rstring); + break; + case 'i': + addbufspc(DIGBUFSIZE); + sprintf(bp, "%ld", (long)lineno); + bp += strlen(bp); + break; + case '\0': + return 0; + case Meta: + fm++; + break; + } + } else if(*fm == '!' && isset(PROMPTBANG)) { + if(doprint) { + if(fm[1] == '!') { + fm++; + addbufspc(1); + pputc('!'); + } else { + addbufspc(DIGBUFSIZE); + convbase(bp, curhist, 10); + bp += strlen(bp); + } + } + } else { + char c = *fm == Meta ? *++fm ^ 32 : *fm; + + if (doprint) { + addbufspc(1); + pputc(c); + } + } + } + + return *fm; +} + +/* pputc adds a character to the buffer, metafying. There must * + * already be space. */ + +/**/ +static void +pputc(char c) +{ + if(imeta(STOUC(c))) { + *bp++ = Meta; + c ^= 32; + } + *bp++ = c; + if (c == '\n' && !dontcount) + bufline = bp; +} + +/* Make sure there is room for `need' more characters in the buffer. */ + +/**/ +static void +addbufspc(int need) +{ + need *= 2; /* for metafication */ + if((bp - buf) + need > bufspc) { + int bo = bp - buf; + int bo1 = bp1 ? bp1 - buf : -1; + + if(need & 255) + need = (need | 255) + 1; + buf = realloc(buf, bufspc += need); + bp = buf + bo; + if(bo1 != -1) + bp1 = buf + bo1; + } +} + +/* stradd() adds a metafied string to the prompt, * + * in a visible representation. */ + +/**/ +void +stradd(char *d) +{ + char *ps, *pc; + addbufspc(niceztrlen(d)); + /* This loop puts the nice representation of the string into the prompt * + * buffer. */ + for(ps=d; *ps; ps++) + for(pc=nicechar(*ps == Meta ? STOUC(*++ps)^32 : STOUC(*ps)); *pc; pc++) + *bp++ = *pc; +} + +/* tsetcap(), among other things, can write a termcap string into the buffer. */ + +/**/ +mod_export void +tsetcap(int cap, int flag) +{ + if (tccan(cap) && !isset(SINGLELINEZLE) && + !(termflags & (TERM_NOUP|TERM_BAD|TERM_UNKNOWN))) { + switch(flag) { + case -1: + tputs(tcstr[cap], 1, putraw); + break; + case 0: + tputs(tcstr[cap], 1, putshout); + break; + case 1: + if (!dontcount) { + addbufspc(1); + *bp++ = Inpar; + } + tputs(tcstr[cap], 1, putstr); + if (!dontcount) { + int glitch = 0; + + if (cap == TCSTANDOUTBEG || cap == TCSTANDOUTEND) + glitch = tgetnum("sg"); + else if (cap == TCUNDERLINEBEG || cap == TCUNDERLINEEND) + glitch = tgetnum("ug"); + if(glitch < 0) + glitch = 0; + addbufspc(glitch + 1); + while(glitch--) + *bp++ = Nularg; + *bp++ = Outpar; + } + break; + } + + if (txtisset(TXTDIRTY)) { + txtunset(TXTDIRTY); + if (txtisset(TXTBOLDFACE) && cap != TCBOLDFACEBEG) + tsetcap(TCBOLDFACEBEG, flag); + if (txtisset(TXTSTANDOUT)) + tsetcap(TCSTANDOUTBEG, flag); + if (txtisset(TXTUNDERLINE)) + tsetcap(TCUNDERLINEBEG, flag); + } + } +} + +/**/ +int +putstr(int d) +{ + addbufspc(1); + pputc(d); + return 0; +} + +/* Count height etc. of a prompt string returned by promptexpand(). * + * This depends on the current terminal width, and tabs and * + * newlines require nontrivial processing. * + * Passing `overf' as -1 means to ignore columns (absolute width). */ + +/**/ +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) + s = 0; + else if(*str == Outpar) + s = 1; + else if(*str == Nularg) + w++; + else if(s) { + if(*str == '\t') + w = (w | 7) + 1; + else if(*str == '\n') { + w = 0; + h++; + } else + w++; + } + } + if(w >= columns && overf >= 0) { + if (!overf || w > columns) { + w = 0; + h++; + } + } + if(wp) + *wp = w; + 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++; + trunccount = dontcount; + putpromptchar(doprint, endchar); + trunccount = 0; + 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; +}