diff options
Diffstat (limited to 'dotfiles/system/.zsh/modules/Src/prompt.c')
| -rw-r--r-- | dotfiles/system/.zsh/modules/Src/prompt.c | 2046 |
1 files changed, 0 insertions, 2046 deletions
diff --git a/dotfiles/system/.zsh/modules/Src/prompt.c b/dotfiles/system/.zsh/modules/Src/prompt.c deleted file mode 100644 index 959ed8e..0000000 --- a/dotfiles/system/.zsh/modules/Src/prompt.c +++ /dev/null @@ -1,2046 +0,0 @@ -/* - * prompt.c - construct zsh prompts - * - * 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" - -/* text attribute mask */ - -/**/ -mod_export unsigned txtattrmask; - -/* 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", -}; - - -struct buf_vars; - -struct buf_vars { -/* Previous set of prompt variables on the stack. */ - - struct buf_vars *last; - -/* The buffer into which an expanded and metafied prompt is being written, * - * and its size. */ - - char *buf; - int bufspc; - -/* bp is the pointer to the current position in the buffer, where the next * - * character will be added. */ - - char *bp; - -/* Position of the start of the current line in the buffer */ - - 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. */ - - char *bp1; - -/* The format string, for %-expansion. */ - - char *fm; - -/* Non-zero if truncating the current segment of the buffer. */ - - int truncwidth; - -/* Current level of nesting of %{ / %} sequences. */ - - int dontcount; - -/* Level of %{ / %} surrounding a truncation segment. */ - - int trunccount; - -/* Strings to use for %r and %R (for the spelling prompt). */ - - char *rstring, *Rstring; -}; - -typedef struct buf_vars *Buf_vars; - -/* The currently active prompt output variables */ -static Buf_vars bv; - -/* - * 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->node.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. - * - * txtchangep gives an integer controlling the attributes of - * the prompt. This is for use in zle to maintain the attributes - * consistenly. Other parts of the shell should not need to use it. - */ - -/**/ -mod_export char * -promptexpand(char *s, int ns, char *rs, char *Rs, unsigned int *txtchangep) -{ - struct buf_vars new_vars; - - 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); - /* - * We don't need the special Nularg hack here and we're - * going to be using Nularg for other things. - */ - if (*s == Nularg && s[1] == '\0') - *s = '\0'; - - /* - * Ignore errors and status change in prompt substitution. - * However, keep any user interrupt error that occurred. - */ - errflag = olderr | (errflag & ERRFLAG_INT); - lastval = oldval; - } - - memset(&new_vars, 0, sizeof(new_vars)); - new_vars.last = bv; - bv = &new_vars; - - new_vars.rstring = rs; - new_vars.Rstring = Rs; - new_vars.fm = s; - new_vars.bufspc = 256; - new_vars.bp = new_vars.bufline = new_vars.buf = zshcalloc(new_vars.bufspc); - new_vars.bp1 = NULL; - new_vars.truncwidth = 0; - - putpromptchar(1, '\0', txtchangep); - addbufspc(2); - if (new_vars.dontcount) - *new_vars.bp++ = Outpar; - *new_vars.bp = '\0'; - if (!ns) { - /* If zero, Inpar, Outpar and Nularg should be removed. */ - for (new_vars.bp = new_vars.buf; *new_vars.bp; ) { - if (*new_vars.bp == Meta) - new_vars.bp += 2; - else if (*new_vars.bp == Inpar || *new_vars.bp == Outpar || - *new_vars.bp == Nularg) - chuck(new_vars.bp); - else - new_vars.bp++; - } - } - - bv = new_vars.last; - - return new_vars.buf; -} - -/* Parse the argument for %F and %K */ -static int -parsecolorchar(int arg, int is_fg) -{ - if (bv->fm[1] == '{') { - char *ep; - bv->fm += 2; /* skip over F{ */ - if ((ep = strchr(bv->fm, '}'))) { - char oc = *ep, *col, *coll; - *ep = '\0'; - /* expand the contents of the argument so you can use - * %v for example */ - coll = col = promptexpand(bv->fm, 0, NULL, NULL, NULL); - *ep = oc; - arg = match_colour((const char **)&coll, is_fg, 0); - free(col); - bv->fm = ep; - } else { - arg = match_colour((const char **)&bv->fm, is_fg, 0); - if (*bv->fm != '}') - bv->fm--; - } - } else - arg = match_colour(NULL, 1, arg); - return arg; -} - -/* 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, unsigned int *txtchangep) -{ - char *ss, *hostnam; - int t0, arg, test, sep, j, numjobs, len; - struct tm *tm; - struct timespec ts; - time_t timet; - Nameddir nd; - - for (; *bv->fm && *bv->fm != endchar; bv->fm++) { - arg = 0; - if (*bv->fm == '%' && isset(PROMPTPERCENT)) { - int minus = 0; - bv->fm++; - if (*bv->fm == '-') { - minus = 1; - bv->fm++; - } - if (idigit(*bv->fm)) { - arg = zstrtol(bv->fm, &bv->fm, 10); - if (minus) - arg *= -1; - } else if (minus) - arg = -1; - if (*bv->fm == '(') { - int tc, otruncwidth; - - if (idigit(*++bv->fm)) { - arg = zstrtol(bv->fm, &bv->fm, 10); - } else if (arg < 0) { - /* negative numbers don't make sense here */ - arg *= -1; - } - test = 0; - ss = pwd; - switch (tc = *bv->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++ == '/' && *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': - *bv->bp = '\0'; - countprompt(bv->bufline, &t0, 0, 0); - if (minus) - t0 = zterm_columns - t0; - if (t0 >= arg) - test = 1; - break; - case 'e': - { - Funcstack fsptr = funcstack; - test = arg; - while (fsptr && test > 0) { - test--; - fsptr = fsptr->prev; - } - test = !test; - } - 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_ge(psvar, arg)) - test = 1; - break; - case 'V': - if (psvar && *psvar && arrlen_ge(psvar, arg)) { - if (*psvar[(arg ? arg : 1) - 1]) - test = 1; - } - break; - case '_': - test = (cmdsp >= arg); - break; - case '!': - test = privasserted(); - break; - default: - test = -1; - break; - } - if (!*bv->fm || !(sep = *++bv->fm)) - return 0; - bv->fm++; - /* Don't do the current truncation until we get back */ - otruncwidth = bv->truncwidth; - bv->truncwidth = 0; - if (!putpromptchar(test == 1 && doprint, sep, - txtchangep) || !*++bv->fm || - !putpromptchar(test == 0 && doprint, ')', - txtchangep)) { - bv->truncwidth = otruncwidth; - return 0; - } - bv->truncwidth = otruncwidth; - continue; - } - if (!doprint) - switch(*bv->fm) { - case '[': - while(idigit(*++bv->fm)); - while(*++bv->fm != ']'); - continue; - case '<': - while(*++bv->fm != '<'); - continue; - case '>': - while(*++bv->fm != '>'); - continue; - case 'D': - if(bv->fm[1]=='{') - while(*++bv->fm != '}'); - continue; - default: - continue; - } - switch (*bv->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(bv->bp, curhist, 10); - bv->bp += strlen(bv->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(bv->bp, "%d", numjobs); - bv->bp += strlen(bv->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"))) { - unqueue_signals(); - 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(txtchangep, TXTSTANDOUT, TXTNOSTANDOUT); - txtset(TXTSTANDOUT); - tsetcap(TCSTANDOUTBEG, TSC_PROMPT); - break; - case 's': - txtchangeset(txtchangep, TXTNOSTANDOUT, TXTSTANDOUT); - txtunset(TXTSTANDOUT); - tsetcap(TCSTANDOUTEND, TSC_PROMPT|TSC_DIRTY); - break; - case 'B': - txtchangeset(txtchangep, TXTBOLDFACE, TXTNOBOLDFACE); - txtset(TXTBOLDFACE); - tsetcap(TCBOLDFACEBEG, TSC_PROMPT|TSC_DIRTY); - break; - case 'b': - txtchangeset(txtchangep, TXTNOBOLDFACE, TXTBOLDFACE); - txtunset(TXTBOLDFACE); - tsetcap(TCALLATTRSOFF, TSC_PROMPT|TSC_DIRTY); - break; - case 'U': - txtchangeset(txtchangep, TXTUNDERLINE, TXTNOUNDERLINE); - txtset(TXTUNDERLINE); - tsetcap(TCUNDERLINEBEG, TSC_PROMPT); - break; - case 'u': - txtchangeset(txtchangep, TXTNOUNDERLINE, TXTUNDERLINE); - txtunset(TXTUNDERLINE); - tsetcap(TCUNDERLINEEND, TSC_PROMPT|TSC_DIRTY); - break; - case 'F': - arg = parsecolorchar(arg, 1); - if (arg >= 0 && !(arg & TXTNOFGCOLOUR)) { - txtchangeset(txtchangep, arg & TXT_ATTR_FG_ON_MASK, - TXTNOFGCOLOUR | TXT_ATTR_FG_COL_MASK); - txtunset(TXT_ATTR_FG_COL_MASK); - txtset(arg & TXT_ATTR_FG_ON_MASK); - set_colour_attribute(arg, COL_SEQ_FG, TSC_PROMPT); - break; - } - /* else FALLTHROUGH */ - case 'f': - txtchangeset(txtchangep, TXTNOFGCOLOUR, TXT_ATTR_FG_ON_MASK); - txtunset(TXT_ATTR_FG_ON_MASK); - set_colour_attribute(TXTNOFGCOLOUR, COL_SEQ_FG, TSC_PROMPT); - break; - case 'K': - arg = parsecolorchar(arg, 0); - if (arg >= 0 && !(arg & TXTNOBGCOLOUR)) { - txtchangeset(txtchangep, arg & TXT_ATTR_BG_ON_MASK, - TXTNOBGCOLOUR | TXT_ATTR_BG_COL_MASK); - txtunset(TXT_ATTR_BG_COL_MASK); - txtset(arg & TXT_ATTR_BG_ON_MASK); - set_colour_attribute(arg, COL_SEQ_BG, TSC_PROMPT); - break; - } - /* else FALLTHROUGH */ - case 'k': - txtchangeset(txtchangep, TXTNOBGCOLOUR, TXT_ATTR_BG_ON_MASK); - txtunset(TXT_ATTR_BG_ON_MASK); - set_colour_attribute(TXTNOBGCOLOUR, COL_SEQ_BG, TSC_PROMPT); - break; - case '[': - if (idigit(*++bv->fm)) - arg = zstrtol(bv->fm, &bv->fm, 10); - if (!prompttrunc(arg, ']', doprint, endchar, txtchangep)) - return *bv->fm; - break; - case '<': - case '>': - /* Test (minus) here so -0 means "at the right margin" */ - if (minus) { - *bv->bp = '\0'; - countprompt(bv->bufline, &t0, 0, 0); - arg = zterm_columns - t0 + arg; - if (arg <= 0) - arg = 1; - } - if (!prompttrunc(arg, *bv->fm, doprint, endchar, txtchangep)) - return *bv->fm; - break; - case '{': /*}*/ - if (!bv->dontcount++) { - addbufspc(1); - *bv->bp++ = Inpar; - } - if (arg <= 0) - break; - /* else */ - /* FALLTHROUGH */ - case 'G': - if (arg > 0) { - addbufspc(arg); - while (arg--) - *bv->bp++ = Nularg; - } else { - addbufspc(1); - *bv->bp++ = Nularg; - } - break; - case /*{*/ '}': - if (bv->trunccount && bv->trunccount >= bv->dontcount) - return *bv->fm; - if (bv->dontcount && !--bv->dontcount) { - addbufspc(1); - *bv->bp++ = Outpar; - } - break; - case 't': - case '@': - case 'T': - case '*': - case 'w': - case 'W': - case 'D': - { - char *tmfmt, *dd, *tmbuf = NULL; - - switch (*bv->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 (bv->fm[1] == '{' /*}*/) { - for (ss = bv->fm + 2; *ss && *ss != /*{*/ '}'; ss++) - if(*ss == '\\' && ss[1]) - ss++; - dd = tmfmt = tmbuf = zalloc(ss - bv->fm); - for (ss = bv->fm + 2; *ss && *ss != /*{*/ '}'; - ss++) { - if(*ss == '\\' && ss[1]) - ss++; - *dd++ = *ss; - } - *dd = 0; - bv->fm = ss - !*ss; - if (!*tmfmt) { - free(tmbuf); - continue; - } - } else - tmfmt = "%y-%m-%d"; - break; - default: - tmfmt = "%l:%M%p"; - break; - } - zgettime(&ts); - tm = localtime(&ts.tv_sec); - /* - * 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 ((len = ztrftime(bv->bp, t0, tmfmt, tm, ts.tv_nsec)) - >= 0) - break; - } - /* There is enough room for this because addbufspc(t0) - * allocates room for t0 * 2 bytes. */ - if (len >= 0) - metafy(bv->bp, len, META_NOALLOC); - bv->bp += strlen(bv->bp); - zsfree(tmbuf); - 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); -#if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD) - sprintf(bv->bp, "%lld", shlvl); -#else - sprintf(bv->bp, "%ld", (long)shlvl); -#endif - bv->bp += strlen(bv->bp); - break; - case '?': - addbufspc(DIGBUFSIZE); -#if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD) - sprintf(bv->bp, "%lld", lastval); -#else - sprintf(bv->bp, "%ld", (long)lastval); -#endif - bv->bp += strlen(bv->bp); - break; - case '%': - case ')': - addbufspc(1); - *bv->bp++ = *bv->fm; - break; - case '#': - addbufspc(1); - *bv->bp++ = privasserted() ? '#' : '%'; - break; - case 'v': - if (!arg) - arg = 1; - else if (arg < 0) - arg += arrlen(psvar) + 1; - if (arg > 0 && arrlen_ge(psvar, arg)) - stradd(psvar[arg - 1]); - break; - case 'E': - tsetcap(TCCLEAREOL, TSC_PROMPT); - 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); - *bv->bp++=' '; - } - } - } else { - arg = -arg; - if (arg > cmdsp) - arg = cmdsp; - for (t0 = arg - 1; arg--; t0--) { - stradd(cmdnames[cmdstack[t0]]); - if (arg) { - addbufspc(1); - *bv->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); - *bv->bp++=' '; - } - } - } else { - arg = -arg; - if (arg > cmdsp) - arg = cmdsp; - for (t0 = 0; arg--; t0++) { - stradd(cmdnames[cmdstack[t0]]); - if (arg) { - addbufspc(1); - *bv->bp++=' '; - } - } - } - } - break; - case 'r': - if(bv->rstring) - stradd(bv->rstring); - break; - case 'R': - if(bv->Rstring) - stradd(bv->Rstring); - break; - case 'e': - { - int depth = 0; - Funcstack fsptr = funcstack; - while (fsptr) { - depth++; - fsptr = fsptr->prev; - } - addbufspc(DIGBUFSIZE); - sprintf(bv->bp, "%d", depth); - bv->bp += strlen(bv->bp); - break; - } - case 'I': - if (funcstack && funcstack->tp != FS_SOURCE && - !IN_EVAL_TRAP()) { - /* - * We're in a function or an eval with - * EVALLINENO. Calculate the line number in - * the file. - */ - zlong flineno = lineno + funcstack->flineno; - /* take account of eval line nos. starting at 1 */ - if (funcstack->tp == FS_EVAL) - lineno--; - addbufspc(DIGBUFSIZE); -#if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD) - sprintf(bv->bp, "%lld", flineno); -#else - sprintf(bv->bp, "%ld", (long)flineno); -#endif - bv->bp += strlen(bv->bp); - break; - } - /* else we're in a file and lineno is already correct */ - /* FALLTHROUGH */ - case 'i': - addbufspc(DIGBUFSIZE); -#if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD) - sprintf(bv->bp, "%lld", lineno); -#else - sprintf(bv->bp, "%ld", (long)lineno); -#endif - bv->bp += strlen(bv->bp); - break; - case 'x': - if (funcstack && funcstack->tp != FS_SOURCE && - !IN_EVAL_TRAP()) - promptpath(funcstack->filename ? funcstack->filename : "", - arg, 0); - else - promptpath(scriptfilename ? scriptfilename : argzero, - arg, 0); - break; - case '\0': - return 0; - case Meta: - bv->fm++; - break; - } - } else if(*bv->fm == '!' && isset(PROMPTBANG)) { - if(doprint) { - if(bv->fm[1] == '!') { - bv->fm++; - addbufspc(1); - pputc('!'); - } else { - addbufspc(DIGBUFSIZE); - convbase(bv->bp, curhist, 10); - bv->bp += strlen(bv->bp); - } - } - } else { - char c = *bv->fm == Meta ? *++bv->fm ^ 32 : *bv->fm; - - if (doprint) { - addbufspc(1); - pputc(c); - } - } - } - - return *bv->fm; -} - -/* pputc adds a character to the buffer, metafying. There must * - * already be space. */ - -/**/ -static void -pputc(char c) -{ - if (imeta(c)) { - *bv->bp++ = Meta; - c ^= 32; - } - *bv->bp++ = c; - if (c == '\n' && !bv->dontcount) - bv->bufline = bv->bp; -} - -/* Make sure there is room for `need' more characters in the buffer. */ - -/**/ -static void -addbufspc(int need) -{ - need *= 2; /* for metafication */ - if((bv->bp - bv->buf) + need > bv->bufspc) { - int bo = bv->bp - bv->buf; - int bo1 = bv->bp1 ? bv->bp1 - bv->buf : -1; - ptrdiff_t bufline_off = bv->bufline ? bv->bufline - bv->buf : -1; - - if(need & 255) - need = (need | 255) + 1; - bv->buf = realloc(bv->buf, bv->bufspc += need); - memset(bv->buf + bv->bufspc - need, 0, need); - bv->bp = bv->buf + bo; - if(bo1 != -1) - bv->bp1 = bv->buf + bo1; - if (bufline_off != -1) - bv->bufline = bv->buf + bufline_off; - } -} - -/* stradd() adds a metafied string to the prompt, * - * in a visible representation. */ - -/**/ -void -stradd(char *d) -{ -#ifdef MULTIBYTE_SUPPORT - char *ums, *ups; - int upslen, eol = 0; - mbstate_t mbs; - - memset(&mbs, 0, sizeof mbs); - ums = ztrdup(d); - ups = unmetafy(ums, &upslen); - - /* - * We now have a raw string of possibly multibyte characters. - * Read each character one by one. - */ - while (upslen > 0) { - wchar_t cc; - char *pc; - size_t cnt = eol ? MB_INVALID : mbrtowc(&cc, ups, upslen, &mbs); - - switch (cnt) { - case MB_INCOMPLETE: - eol = 1; - /* FALL THROUGH */ - case MB_INVALID: - /* Bad character. Take the next byte on its own. */ - pc = nicechar(*ups); - cnt = 1; - memset(&mbs, 0, sizeof mbs); - break; - case 0: - cnt = 1; - /* FALL THROUGH */ - default: - /* Take full wide character in one go */ - mb_charinit(); - pc = wcs_nicechar(cc, NULL, NULL); - break; - } - /* Keep output as metafied string. */ - addbufspc(strlen(pc)); - - upslen -= cnt; - ups += cnt; - - /* Put printed representation into the buffer */ - while (*pc) - *bv->bp++ = *pc++; - } - - free(ums); -#else - 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 ? *++ps^32 : *ps); *pc; pc++) - *bv->bp++ = *pc; - } -#endif -} - -/* tsetcap(), among other things, can write a termcap string into the buffer. */ - -/**/ -mod_export void -tsetcap(int cap, int flags) -{ - if (tccan(cap) && !isset(SINGLELINEZLE) && - !(termflags & (TERM_NOUP|TERM_BAD|TERM_UNKNOWN))) { - switch (flags & TSC_OUTPUT_MASK) { - case TSC_RAW: - tputs(tcstr[cap], 1, putraw); - break; - case 0: - default: - tputs(tcstr[cap], 1, putshout); - break; - case TSC_PROMPT: - if (!bv->dontcount) { - addbufspc(1); - *bv->bp++ = Inpar; - } - tputs(tcstr[cap], 1, putstr); - if (!bv->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--) - *bv->bp++ = Nularg; - *bv->bp++ = Outpar; - } - break; - } - - if (flags & TSC_DIRTY) { - flags &= ~TSC_DIRTY; - if (txtisset(TXTBOLDFACE) && cap != TCBOLDFACEBEG) - tsetcap(TCBOLDFACEBEG, flags); - if (txtisset(TXTSTANDOUT)) - tsetcap(TCSTANDOUTBEG, flags); - if (txtisset(TXTUNDERLINE)) - tsetcap(TCUNDERLINEBEG, flags); - if (txtisset(TXTFGCOLOUR)) - set_colour_attribute(txtattrmask, COL_SEQ_FG, TSC_PROMPT); - if (txtisset(TXTBGCOLOUR)) - set_colour_attribute(txtattrmask, COL_SEQ_BG, TSC_PROMPT); - } - } -} - -/**/ -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). - * - * If multibyte is enabled, take account of multibyte characters - * by locating them and finding out their screen width. - */ - -/**/ -mod_export void -countprompt(char *str, int *wp, int *hp, int overf) -{ - int w = 0, h = 1; - int s = 1; -#ifdef MULTIBYTE_SUPPORT - int wcw, multi = 0; - char inchar; - mbstate_t mbs; - wchar_t wc; - - memset(&mbs, 0, sizeof(mbs)); -#endif - - for (; *str; str++) { - if (w > zterm_columns && overf >= 0) { - w = 0; - h++; - } - /* - * Input string should be metafied, so tokens in it should - * be real tokens, even if there are multibyte characters. - */ - if (*str == Inpar) - s = 0; - else if (*str == Outpar) - s = 1; - else if (*str == Nularg) - w++; - else if (s) { - if (*str == Meta) { -#ifdef MULTIBYTE_SUPPORT - inchar = *++str ^ 32; -#else - str++; -#endif - } else { -#ifdef MULTIBYTE_SUPPORT - /* - * Don't look for tab or newline in the middle - * of a multibyte character. Otherwise, we are - * relying on the character set being an extension - * of ASCII so it's safe to test a single byte. - */ - if (!multi) { -#endif - if (*str == '\t') { - w = (w | 7) + 1; - continue; - } else if (*str == '\n') { - w = 0; - h++; - continue; - } -#ifdef MULTIBYTE_SUPPORT - } - - inchar = *str; -#endif - } - -#ifdef MULTIBYTE_SUPPORT - switch (mbrtowc(&wc, &inchar, 1, &mbs)) { - case MB_INCOMPLETE: - /* Character is incomplete -- keep looking. */ - multi = 1; - break; - case MB_INVALID: - memset(&mbs, 0, sizeof mbs); - /* Invalid character: assume single width. */ - multi = 0; - w++; - break; - case 0: - multi = 0; - break; - default: - /* - * If the character isn't printable, WCWIDTH() returns - * -1. We assume width 1. - */ - wcw = WCWIDTH(wc); - if (wcw >= 0) - w += wcw; - else - w++; - multi = 0; - break; - } -#else - w++; -#endif - } - } - /* - * multi may still be set if we were in the middle of the character. - * This isn't easy to handle generally; just assume there's no - * output. - */ - if(w >= zterm_columns && overf >= 0) { - if (!overf || w > zterm_columns) { - w = 0; - h++; - } - } - if(wp) - *wp = w; - if(hp) - *hp = h; -} - -/**/ -static int -prompttrunc(int arg, int truncchar, int doprint, int endchar, - unsigned int *txtchangep) -{ - if (arg > 0) { - char ch = *bv->fm, *ptr, *truncstr; - int truncatleft = ch == '<'; - int w = bv->bp - bv->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 (bv->truncwidth) { - while (*--bv->fm != '%') - ; - bv->fm--; - return 0; - } - - bv->truncwidth = arg; - if (*bv->fm != ']') - bv->fm++; - while (*bv->fm && *bv->fm != truncchar) { - if (*bv->fm == '\\' && bv->fm[1]) - ++bv->fm; - addbufspc(1); - *bv->bp++ = *bv->fm++; - } - if (!*bv->fm) - return 0; - if (bv->bp - bv->buf == w && truncchar == ']') { - addbufspc(1); - *bv->bp++ = '<'; - } - ptr = bv->buf + w; /* addbufspc() may have realloc()'d bv->buf */ - /* - * Now: - * bv->buf is the start of the output prompt buffer - * ptr is the start of the truncation string - * bv->bp is the end of the truncation string - */ - truncstr = ztrduppfx(ptr, bv->bp - ptr); - - bv->bp = ptr; - w = bv->bp - bv->buf; - bv->fm++; - bv->trunccount = bv->dontcount; - putpromptchar(doprint, endchar, txtchangep); - bv->trunccount = 0; - ptr = bv->buf + w; /* putpromptchar() may have realloc()'d */ - *bv->bp = '\0'; - /* - * Now: - * ptr is the start of the truncation string and also - * where we need to start putting any truncated output - * bv->bp is the end of the string we have just added, which - * may need truncating. - */ - - /* - * w below is screen width if multibyte support is enabled - * (note that above it was a raw string pointer difference). - * It's the full width of the string we may need to truncate. - * - * bv->truncwidth has come from the user, so we interpret this - * as a screen width, too. - */ - countprompt(ptr, &w, 0, -1); - if (w > bv->truncwidth) { - /* - * We need to truncate. t points to the truncation string - * -- which is inserted literally, without nice - * representation. twidth is its printing width, and maxwidth - * is the amount of the main string that we want to keep. - * Note that if the truncation string is longer than the - * truncation length (twidth > bv->truncwidth), the truncation - * string is used in full. - */ - char *t = truncstr; - int fullen = bv->bp - ptr; - int twidth, maxwidth; - int ntrunc = strlen(t); - - twidth = MB_METASTRWIDTH(t); - if (twidth < bv->truncwidth) { - maxwidth = bv->truncwidth - twidth; - /* - * It's not safe to assume there are no invisible substrings - * just because the width is less than the full string - * length since there may be multibyte characters. - */ - addbufspc(ntrunc+1); - /* may have realloc'd */ - ptr = bv->bp - fullen; - - if (truncatleft) { - /* - * To truncate at the left, selectively copy - * maxwidth bytes from the main prompt, preceded - * by the truncation string in full. - * - * We're overwriting the string containing the - * text to be truncated, so copy it. We've - * just ensured there's sufficient space at the - * end of the prompt string. - * - * Pointer into text to be truncated. - */ - char *fulltextptr, *fulltext; - int remw; -#ifdef MULTIBYTE_SUPPORT - mbstate_t mbs; - memset(&mbs, 0, sizeof mbs); -#endif - - fulltextptr = fulltext = ptr + ntrunc; - memmove(fulltext, ptr, fullen); - fulltext[fullen] = '\0'; - - /* Copy the truncstr into place. */ - while (*t) - *ptr++ = *t++; - - /* - * Find the point in the text at which we should - * start copying, i.e. when the remaining width - * is less than or equal to the maximum width. - */ - remw = w; - while (remw > maxwidth && *fulltextptr) { - if (*fulltextptr == Inpar) { - /* - * Text marked as invisible: copy - * regardless, since we don't know what - * this does. It only affects the width - * if there are Nularg's present. - * However, even in that case we - * can't break the sequence down, so - * we still loop over the entire group. - */ - for (;;) { - *ptr++ = *fulltextptr; - if (*fulltextptr == '\0' || - *fulltextptr++ == Outpar) - break; - if (fulltextptr[-1] == Nularg) - remw--; - } - } else { -#ifdef MULTIBYTE_SUPPORT - /* - * Normal text: build up a multibyte character. - */ - char inchar; - wchar_t cc; - int wcw; - - /* - * careful: string is still metafied (we - * need that because we don't know a - * priori when to stop and the resulting - * string must be metafied). - */ - if (*fulltextptr == Meta) - inchar = *++fulltextptr ^ 32; - else - inchar = *fulltextptr; - fulltextptr++; - switch (mbrtowc(&cc, &inchar, 1, &mbs)) { - case MB_INCOMPLETE: - /* Incomplete multibyte character. */ - break; - case MB_INVALID: - /* Reset invalid state. */ - memset(&mbs, 0, sizeof mbs); - /* FALL THROUGH */ - case 0: - /* Assume a single-byte character. */ - remw--; - break; - default: - wcw = WCWIDTH(cc); - if (wcw >= 0) - remw -= wcw; - else - remw--; - break; - } -#else - /* Single byte character */ - if (*fulltextptr == Meta) - fulltextptr++; - fulltextptr++; - remw--; -#endif - } - } - - /* - * Now simply copy the rest of the text. Still - * metafied, so this is easy. - */ - while (*fulltextptr) - *ptr++ = *fulltextptr++; - /* Mark the end of copying */ - bv->bp = ptr; - } else { - /* - * Truncating at the right is easier: just leave - * enough characters until we have reached the - * maximum width. - */ - char *skiptext = ptr; -#ifdef MULTIBYTE_SUPPORT - mbstate_t mbs; - memset(&mbs, 0, sizeof mbs); -#endif - - while (maxwidth > 0 && *skiptext) { - if (*skiptext == Inpar) { - /* see comment on left truncation above */ - for (;;) { - if (*skiptext == '\0' || - *skiptext++ == Outpar) - break; - if (skiptext[-1] == Nularg) - maxwidth--; - } - } else { -#ifdef MULTIBYTE_SUPPORT - char inchar; - wchar_t cc; - int wcw; - - if (*skiptext == Meta) - inchar = *++skiptext ^ 32; - else - inchar = *skiptext; - skiptext++; - switch (mbrtowc(&cc, &inchar, 1, &mbs)) { - case MB_INCOMPLETE: - /* Incomplete character. */ - break; - case MB_INVALID: - /* Reset invalid state. */ - memset(&mbs, 0, sizeof mbs); - /* FALL THROUGH */ - case 0: - /* Assume a single-byte character. */ - maxwidth--; - break; - default: - wcw = WCWIDTH(cc); - if (wcw >= 0) - maxwidth -= wcw; - else - maxwidth--; - break; - } -#else - if (*skiptext == Meta) - skiptext++; - skiptext++; - maxwidth--; -#endif - } - } - /* - * We don't need the visible text from now on, - * but we'd better copy any invisible bits. - * History dictates that these go after the - * truncation string. This is sensible since - * they may, for example, turn off an effect which - * should apply to all text at this point. - * - * Copy the truncstr. - */ - ptr = skiptext; - while (*t) - *ptr++ = *t++; - bv->bp = ptr; - if (*skiptext) { - /* Move remaining text so we don't overwrite it */ - memmove(bv->bp, skiptext, strlen(skiptext)+1); - skiptext = bv->bp; - - /* - * Copy anything we want, updating bv->bp - */ - while (*skiptext) { - if (*skiptext == Inpar) { - for (;;) { - *bv->bp++ = *skiptext; - if (*skiptext == Outpar || - *skiptext == '\0') - break; - skiptext++; - } - } - else - skiptext++; - } - } - } - } else { - /* Just copy truncstr; no other text appears. */ - while (*t) - *ptr++ = *t++; - bv->bp = ptr; - } - *bv->bp = '\0'; - } - zsfree(truncstr); - bv->truncwidth = 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 (!*bv->fm) - return 0; - if (*bv->fm != endchar) { - bv->fm++; - /* - * With bv->truncwidth set to zero, we always reach endchar * - * (or the terminating NULL) this time round. * - */ - if (!putpromptchar(doprint, endchar, txtchangep)) - return 0; - } - /* Now we have to trick it into matching endchar again */ - bv->fm--; - } else { - if (*bv->fm != endchar) - bv->fm++; - while(*bv->fm && *bv->fm != truncchar) { - if (*bv->fm == '\\' && bv->fm[1]) - bv->fm++; - bv->fm++; - } - if (bv->truncwidth || !*bv->fm) - return 0; - } - return 1; -} - -/**/ -void -cmdpush(int cmdtok) -{ - if (cmdsp >= 0 && cmdsp < CMDSTACKSZ) - cmdstack[cmdsp++] = (unsigned char)cmdtok; -} - -/**/ -void -cmdpop(void) -{ - if (cmdsp <= 0) { - DPUTS(1, "BUG: cmdstack empty"); - fflush(stderr); - } else - cmdsp--; -} - - -/***************************************************************************** - * Utilities dealing with colour and other forms of highlighting. - * - * These are shared by prompts and by zle, so it's easiest to have them - * in the main shell. - *****************************************************************************/ - -/* Defines standard ANSI colour names in index order */ -static const char *ansi_colours[] = { - "black", "red", "green", "yellow", "blue", "magenta", "cyan", "white", - "default", NULL -}; - -/* Defines the available types of highlighting */ -struct highlight { - const char *name; - int mask_on; - int mask_off; -}; - -static const struct highlight highlights[] = { - { "none", 0, TXT_ATTR_ON_MASK }, - { "bold", TXTBOLDFACE, 0 }, - { "standout", TXTSTANDOUT, 0 }, - { "underline", TXTUNDERLINE, 0 }, - { NULL, 0, 0 } -}; - -/* - * Return index of ANSI colour for which *teststrp is an abbreviation. - * Any non-alphabetic character ends the abbreviation. - * 8 is the special value for default (note this is *not* the - * right sequence for default which is typically 9). - * -1 is failure. - */ - -static int -match_named_colour(const char **teststrp) -{ - const char *teststr = *teststrp, *end, **cptr; - int len; - - for (end = teststr; ialpha(*end); end++) - ; - len = end - teststr; - *teststrp = end; - - for (cptr = ansi_colours; *cptr; cptr++) { - if (!strncmp(teststr, *cptr, len)) - return cptr - ansi_colours; - } - - return -1; -} - -/* - * Match just the colour part of a highlight specification. - * If teststrp is NULL, use the already parsed numeric colour. - * Return the attributes to set in the attribute variable. - * Return -1 for out of range. Does not check the character - * following the colour specification. - */ - -/**/ -mod_export int -match_colour(const char **teststrp, int is_fg, int colour) -{ - int shft, on, named = 0, tc; - - if (teststrp) { - if ((named = ialpha(**teststrp))) { - colour = match_named_colour(teststrp); - if (colour == 8) { - /* default */ - return is_fg ? TXTNOFGCOLOUR : TXTNOBGCOLOUR; - } - } - else - colour = (int)zstrtol(*teststrp, (char **)teststrp, 10); - } - if (colour < 0 || colour >= 256) - return -1; - if (is_fg) { - shft = TXT_ATTR_FG_COL_SHIFT; - on = TXTFGCOLOUR; - tc = TCFGCOLOUR; - } else { - shft = TXT_ATTR_BG_COL_SHIFT; - on = TXTBGCOLOUR; - tc = TCBGCOLOUR; - } - /* - * Try termcap for numbered characters if posible. - * Don't for named characters, since our best bet - * of getting the names right is with ANSI sequences. - */ - if (!named && tccan(tc)) { - if (tccolours >= 0 && colour >= tccolours) { - /* - * Out of range of termcap colours. - * Can we assume ANSI colours work? - */ - if (colour > 7) - return -1; /* No. */ - } else { - /* - * We can handle termcap colours and the number - * is in range, so use termcap. - */ - on |= is_fg ? TXT_ATTR_FG_TERMCAP : - TXT_ATTR_BG_TERMCAP; - } - } - return on | (colour << shft); -} - -/* - * Match a set of highlights in the given teststr. - * Set *on_var to reflect the values found. - */ - -/**/ -mod_export void -match_highlight(const char *teststr, int *on_var) -{ - int found = 1; - - *on_var = 0; - while (found && *teststr) { - const struct highlight *hl; - - found = 0; - if (strpfx("fg=", teststr) || strpfx("bg=", teststr)) { - int is_fg = (teststr[0] == 'f'), atr; - - teststr += 3; - atr = match_colour(&teststr, is_fg, 0); - if (*teststr == ',') - teststr++; - else if (*teststr) - break; - found = 1; - /* skip out of range colours but keep scanning attributes */ - if (atr >= 0) - *on_var |= atr; - } else { - for (hl = highlights; hl->name; hl++) { - if (strpfx(hl->name, teststr)) { - const char *val = teststr + strlen(hl->name); - - if (*val == ',') - val++; - else if (*val) - break; - - *on_var |= hl->mask_on; - *on_var &= ~hl->mask_off; - teststr = val; - found = 1; - } - } - } - } -} - -/* - * Count or output a string for colour information: used - * by output_highlight(). - */ - -static int -output_colour(int colour, int fg_bg, int use_tc, char *buf) -{ - int atrlen = 3, len; - char *ptr = buf; - if (buf) { - strcpy(ptr, fg_bg == COL_SEQ_FG ? "fg=" : "bg="); - ptr += 3; - } - /* colour should only be > 7 if using termcap but let's be safe */ - if (use_tc || colour > 7) { - char digbuf[DIGBUFSIZE]; - sprintf(digbuf, "%d", colour); - len = strlen(digbuf); - atrlen += len; - if (buf) - strcpy(ptr, digbuf); - } else { - len = strlen(ansi_colours[colour]); - atrlen += len; - if (buf) - strcpy(ptr, ansi_colours[colour]); - } - - return atrlen; -} - -/* - * Count the length needed for outputting highlighting information - * as a string based on the bits for the attributes. - * - * If buf is not NULL, output the strings into the buffer, too. - * As conventional with strings, the allocated length should be - * at least the returned value plus 1 for the NUL byte. - */ - -/**/ -mod_export int -output_highlight(int atr, char *buf) -{ - const struct highlight *hp; - int atrlen = 0, len; - char *ptr = buf; - - if (atr & TXTFGCOLOUR) { - len = output_colour(txtchangeget(atr, TXT_ATTR_FG_COL), - COL_SEQ_FG, - (atr & TXT_ATTR_FG_TERMCAP), - ptr); - atrlen += len; - if (buf) - ptr += len; - } - if (atr & TXTBGCOLOUR) { - if (atrlen) { - atrlen++; - if (buf) { - strcpy(ptr, ","); - ptr++; - } - } - len = output_colour(txtchangeget(atr, TXT_ATTR_BG_COL), - COL_SEQ_BG, - (atr & TXT_ATTR_BG_TERMCAP), - ptr); - atrlen += len; - if (buf) - ptr += len; - } - for (hp = highlights; hp->name; hp++) { - if (hp->mask_on & atr) { - if (atrlen) { - atrlen++; - if (buf) { - strcpy(ptr, ","); - ptr++; - } - } - len = strlen(hp->name); - atrlen += len; - if (buf) { - strcpy(ptr, hp->name); - ptr += len; - } - } - } - - if (atrlen == 0) { - if (buf) - strcpy(ptr, "none"); - return 4; - } - return atrlen; -} - -/* Structure and array for holding special colour terminal sequences */ - -/* Start of escape sequence for foreground colour */ -#define TC_COL_FG_START "\033[3" -/* End of escape sequence for foreground colour */ -#define TC_COL_FG_END "m" -/* Code to reset foreground colour */ -#define TC_COL_FG_DEFAULT "9" - -/* Start of escape sequence for background colour */ -#define TC_COL_BG_START "\033[4" -/* End of escape sequence for background colour */ -#define TC_COL_BG_END "m" -/* Code to reset background colour */ -#define TC_COL_BG_DEFAULT "9" - -struct colour_sequences { - char *start; /* Escape sequence start */ - char *end; /* Escape sequence terminator */ - char *def; /* Code to reset default colour */ -}; -static struct colour_sequences fg_bg_sequences[2]; - -/* - * We need a buffer for colour sequence composition. It may - * vary depending on the sequences set. However, it's inefficient - * allocating it separately every time we send a colour sequence, - * so do it once per refresh. - */ -static char *colseq_buf; - -/* - * Count how often this has been allocated, for recursive usage. - */ -static int colseq_buf_allocs; - -/**/ -void -set_default_colour_sequences(void) -{ - fg_bg_sequences[COL_SEQ_FG].start = ztrdup(TC_COL_FG_START); - fg_bg_sequences[COL_SEQ_FG].end = ztrdup(TC_COL_FG_END); - fg_bg_sequences[COL_SEQ_FG].def = ztrdup(TC_COL_FG_DEFAULT); - - fg_bg_sequences[COL_SEQ_BG].start = ztrdup(TC_COL_BG_START); - fg_bg_sequences[COL_SEQ_BG].end = ztrdup(TC_COL_BG_END); - fg_bg_sequences[COL_SEQ_BG].def = ztrdup(TC_COL_BG_DEFAULT); -} - -static void -set_colour_code(char *str, char **var) -{ - char *keyseq; - int len; - - zsfree(*var); - keyseq = getkeystring(str, &len, GETKEYS_BINDKEY, NULL); - *var = metafy(keyseq, len, META_DUP); -} - -/* Allocate buffer for colour code composition */ - -/**/ -mod_export void -allocate_colour_buffer(void) -{ - char **atrs; - int lenfg, lenbg, len; - - if (colseq_buf_allocs++) - return; - - atrs = getaparam("zle_highlight"); - if (atrs) { - for (; *atrs; atrs++) { - if (strpfx("fg_start_code:", *atrs)) { - set_colour_code(*atrs + 14, &fg_bg_sequences[COL_SEQ_FG].start); - } else if (strpfx("fg_default_code:", *atrs)) { - set_colour_code(*atrs + 16, &fg_bg_sequences[COL_SEQ_FG].def); - } else if (strpfx("fg_end_code:", *atrs)) { - set_colour_code(*atrs + 12, &fg_bg_sequences[COL_SEQ_FG].end); - } else if (strpfx("bg_start_code:", *atrs)) { - set_colour_code(*atrs + 14, &fg_bg_sequences[COL_SEQ_BG].start); - } else if (strpfx("bg_default_code:", *atrs)) { - set_colour_code(*atrs + 16, &fg_bg_sequences[COL_SEQ_BG].def); - } else if (strpfx("bg_end_code:", *atrs)) { - set_colour_code(*atrs + 12, &fg_bg_sequences[COL_SEQ_BG].end); - } - } - } - - lenfg = strlen(fg_bg_sequences[COL_SEQ_FG].def); - /* always need 1 character for non-default code */ - if (lenfg < 1) - lenfg = 1; - lenfg += strlen(fg_bg_sequences[COL_SEQ_FG].start) + - strlen(fg_bg_sequences[COL_SEQ_FG].end); - - lenbg = strlen(fg_bg_sequences[COL_SEQ_BG].def); - /* always need 1 character for non-default code */ - if (lenbg < 1) - lenbg = 1; - lenbg += strlen(fg_bg_sequences[COL_SEQ_BG].start) + - strlen(fg_bg_sequences[COL_SEQ_BG].end); - - len = lenfg > lenbg ? lenfg : lenbg; - colseq_buf = (char *)zalloc(len+1); -} - -/* Free the colour buffer previously allocated. */ - -/**/ -mod_export void -free_colour_buffer(void) -{ - if (--colseq_buf_allocs) - return; - - DPUTS(!colseq_buf, "Freeing colour sequence buffer without alloc"); - /* Free buffer for colour code composition */ - free(colseq_buf); - colseq_buf = NULL; -} - -/* - * Handle outputting of a colour for prompts or zle. - * colour is the numeric colour, 0 to 255 (or less if termcap - * says fewer are supported). - * fg_bg indicates if we're changing the foreground or background. - * tc indicates the termcap code to use, if appropriate. - * def indicates if we're resetting the default colour. - * use_termcap indicates if we should use termcap to output colours. - * flags is either 0 or TSC_PROMPT. - */ - -/**/ -mod_export void -set_colour_attribute(int atr, int fg_bg, int flags) -{ - char *ptr; - int do_free, is_prompt = (flags & TSC_PROMPT) ? 1 : 0; - int colour, tc, def, use_termcap; - - if (fg_bg == COL_SEQ_FG) { - colour = txtchangeget(atr, TXT_ATTR_FG_COL); - tc = TCFGCOLOUR; - def = txtchangeisset(atr, TXTNOFGCOLOUR); - use_termcap = txtchangeisset(atr, TXT_ATTR_FG_TERMCAP); - } else { - colour = txtchangeget(atr, TXT_ATTR_BG_COL); - tc = TCBGCOLOUR; - def = txtchangeisset(atr, TXTNOBGCOLOUR); - use_termcap = txtchangeisset(atr, TXT_ATTR_BG_TERMCAP); - } - - /* - * If we're not restoring the default, and either have a - * colour value that is too large for ANSI, or have been told - * to use the termcap sequence, try to use the termcap sequence. - * - * We have already sanitised the values we allow from the - * highlighting variables, so much of this shouldn't be - * necessary at this point, but we might as well be safe. - */ - if (!def && (colour > 7 || use_termcap)) { - /* - * We can if it's available, and either we couldn't get - * the maximum number of colours, or the colour is in range. - */ - if (tccan(tc) && (tccolours < 0 || colour < tccolours)) - { - if (is_prompt) - { - if (!bv->dontcount) { - addbufspc(1); - *bv->bp++ = Inpar; - } - tputs(tgoto(tcstr[tc], colour, colour), 1, putstr); - if (!bv->dontcount) { - addbufspc(1); - *bv->bp++ = Outpar; - } - } else { - tputs(tgoto(tcstr[tc], colour, colour), 1, putshout); - } - /* That worked. */ - return; - } - /* - * Nope, that didn't work. - * If 0 to 7, assume standard ANSI works, otherwise it won't. - */ - if (colour > 7) - return; - } - - if ((do_free = (colseq_buf == NULL))) { - /* This can happen when moving the cursor in trashzle() */ - allocate_colour_buffer(); - } - - strcpy(colseq_buf, fg_bg_sequences[fg_bg].start); - - ptr = colseq_buf + strlen(colseq_buf); - if (def) { - strcpy(ptr, fg_bg_sequences[fg_bg].def); - while (*ptr) - ptr++; - } else - *ptr++ = colour + '0'; - strcpy(ptr, fg_bg_sequences[fg_bg].end); - - if (is_prompt) { - if (!bv->dontcount) { - addbufspc(1); - *bv->bp++ = Inpar; - } - tputs(colseq_buf, 1, putstr); - if (!bv->dontcount) { - addbufspc(1); - *bv->bp++ = Outpar; - } - } else - tputs(colseq_buf, 1, putshout); - - if (do_free) - free_colour_buffer(); -} |
