From 74e5fcee384467e74983a3077bad97974477e877 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Tue, 6 May 2008 18:19:14 +0000 Subject: 24953: "default" zle_highlight; fix allocation bug in colour sequences --- Src/Zle/zle_refresh.c | 229 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 138 insertions(+), 91 deletions(-) (limited to 'Src') diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c index d4137f0d2..6275d2cf3 100644 --- a/Src/Zle/zle_refresh.c +++ b/Src/Zle/zle_refresh.c @@ -203,11 +203,12 @@ int predisplaylen, postdisplaylen; /* - * Attributes used for highlighting special (unprintable) characters + * Attributes used by default on the command line, and + * attributes for highlighting special (unprintable) characters * displayed on screen. */ -static int special_atr_on; +static int default_atr_on, special_atr_on; /* Flags for the region_highlight structure */ enum { @@ -503,6 +504,31 @@ match_highlight(const char *teststr, int *on_var) } +/* Allocate buffer for colour code composition */ + +static void +set_colseq_buf(void) +{ + int lenfg, lenbg, len; + + 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); +} + /* * Parse the variable zle_highlight to decide how to highlight characters * and regions. Set defaults for anything not explicitly covered. @@ -516,30 +542,30 @@ zle_set_highlight(void) int special_atr_on_set = 0; int region_atr_on_set = 0; int isearch_atr_on_set = 0; - int lenfg, lenbg, len; struct region_highlight *rhp; - special_atr_on = 0; + special_atr_on = default_atr_on = 0; if (!region_highlights) { region_highlights = (struct region_highlight *) zshcalloc(N_SPECIAL_HIGHLIGHTS*sizeof(struct region_highlight)); n_region_highlights = N_SPECIAL_HIGHLIGHTS; } else { - region_highlights->atr = 0; + for (rhp = region_highlights; + rhp < region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp++) { + rhp->atr = 0; + } } if (atrs) { for (; *atrs; atrs++) { if (!strcmp(*atrs, "none")) { /* reset attributes for consistency... usually unnecessary */ - special_atr_on = 0; + special_atr_on = default_atr_on = 0; special_atr_on_set = region_atr_on_set = isearch_atr_on_set = 1; - for (rhp = region_highlights; - rhp < region_highlights + N_SPECIAL_HIGHLIGHTS; - rhp++) { - rhp->atr = 0; - } + } else if (strpfx("default:", *atrs)) { + match_highlight(*atrs + 8, &default_atr_on); } else if (strpfx("special:", *atrs)) { match_highlight(*atrs + 8, &special_atr_on); special_atr_on_set = 1; @@ -573,23 +599,7 @@ zle_set_highlight(void) if (!isearch_atr_on_set) region_highlights[1].atr = TXTUNDERLINE; - /* Allocate buffer for colour code composition */ - 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); + set_colseq_buf(); } @@ -597,8 +607,10 @@ zle_set_highlight(void) static void zle_free_highlight(void) { + DPUTS(!colseq_buf, "Freeing colour sequence buffer without alloc"); /* Free buffer for colour code composition */ free(colseq_buf); + colseq_buf = NULL; } /* @@ -615,63 +627,59 @@ get_region_highlight(UNUSED(Param pm)) { int arrsize = n_region_highlights; char **retarr, **arrp; + struct region_highlight *rhp; /* region_highlights may not have been set yet */ - if (!arrsize) - arrsize = N_SPECIAL_HIGHLIGHTS; - arrp = retarr = (char **)zhalloc(arrsize*sizeof(char *)); - /* ignore NULL termination */ - arrsize--; - if (arrsize) { - struct region_highlight *rhp; + if (arrsize) + arrsize -= N_SPECIAL_HIGHLIGHTS; + arrp = retarr = (char **)zhalloc((arrsize+1)*sizeof(char *)); - /* ignore special highlighting */ - for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; - arrsize--; - rhp++, arrp++) { - char digbuf1[DIGBUFSIZE], digbuf2[DIGBUFSIZE]; - int atrlen = 0, alloclen, done1; - const struct highlight *hp; - - sprintf(digbuf1, "%d", rhp->start); - sprintf(digbuf2, "%d", rhp->end); - - for (hp = highlights; hp->name; hp++) { + /* ignore special highlighting */ + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + arrsize--; + rhp++, arrp++) { + char digbuf1[DIGBUFSIZE], digbuf2[DIGBUFSIZE]; + int atrlen = 0, alloclen, done1; + const struct highlight *hp; + + sprintf(digbuf1, "%d", rhp->start); + sprintf(digbuf2, "%d", rhp->end); + + for (hp = highlights; hp->name; hp++) { + if (hp->mask_on & rhp->atr) { + if (atrlen) + atrlen++; /* comma */ + atrlen += strlen(hp->name); + } + } + if (atrlen == 0) + atrlen = 4; /* none */ + alloclen = atrlen + strlen(digbuf1) + strlen(digbuf2) + + 3; /* 2 spaces, 1 0 */ + if (rhp->flags & ZRH_PREDISPLAY) + alloclen += 2; /* "P " */ + *arrp = (char *)zhalloc(alloclen * sizeof(char)); + /* + * On input we allow a space after the flags. + * I haven't put a space here because I think it's + * marginally easier to have the output always split + * into three words, and then check the first to + * see if there are flags. However, it's arguable. + */ + sprintf(*arrp, "%s%s %s ", + (rhp->flags & ZRH_PREDISPLAY) ? "P" : "", + digbuf1, digbuf2); + if (atrlen) { + for (hp = highlights, done1 = 0; hp->name; hp++) { if (hp->mask_on & rhp->atr) { - if (atrlen) - atrlen++; /* comma */ - atrlen += strlen(hp->name); + if (done1) + strcat(*arrp, ","); + strcat(*arrp, hp->name); + done1 = 1; } } - if (atrlen == 0) - atrlen = 4; /* none */ - alloclen = atrlen + strlen(digbuf1) + strlen(digbuf2) + - 3; /* 2 spaces, 1 0 */ - if (rhp->flags & ZRH_PREDISPLAY) - alloclen += 2; /* "P " */ - *arrp = (char *)zhalloc(alloclen * sizeof(char)); - /* - * On input we allow a space after the flags. - * I haven't put a space here because I think it's - * marginally easier to have the output always split - * into three words, and then check the first to - * see if there are flags. However, it's arguable. - */ - sprintf(*arrp, "%s%s %s ", - (rhp->flags & ZRH_PREDISPLAY) ? "P" : "", - digbuf1, digbuf2); - if (atrlen) { - for (hp = highlights, done1 = 0; hp->name; hp++) { - if (hp->mask_on & rhp->atr) { - if (done1) - strcat(*arrp, ","); - strcat(*arrp, hp->name); - done1 = 1; - } - } - } else - strcat(*arrp, "none"); - } + } else + strcat(*arrp, "none"); } *arrp = '\0'; return retarr; @@ -748,6 +756,34 @@ unset_region_highlight(Param pm, int exp) } +/* The last attributes that were on. */ +static int lastatr; + +/* + * Clear the last attributes that we set: used when we're going + * to be outputting stuff that shouldn't show up as text. + */ +static void +clearattributes(void) +{ + if (lastatr) { + settextattributes(TXT_ATTR_OFF_FROM_ON(lastatr)); + lastatr = 0; + } +} + +/* + * Output a termcap capability, clearing any text attributes so + * as not to mess up the display. + */ + +static void +tcoutclear(int cap) +{ + clearattributes(); + tcout(cap); +} + /* * Output the character. This must come from the new video * buffer, nbuf, since we access the multiword buffer nmwbuf @@ -767,7 +803,6 @@ zwcputc(const REFRESH_ELEMENT *c, int *curatrp) * This differs from *curatrp, which is an optimisation for * writing lots of stuff at once. */ - static int lastatr; #ifdef MULTIBYTE_SUPPORT mbstate_t mbstate; int i; @@ -1093,6 +1128,12 @@ setcolourattribute(int colour, int fg_bg, int tc, int def, int use_termcap) { char *ptr; + int do_free; + + if ((do_free = (colseq_buf == NULL))) { + /* This can happen when moving the cursor in trashzle() */ + set_colseq_buf(); + } /* * If we're not restoring the default, and either have a * colour value that is too large for ANSI, or have been told @@ -1122,6 +1163,11 @@ setcolourattribute(int colour, int fg_bg, int tc, int def, *ptr++ = colour + '0'; strcpy(ptr, fg_bg_sequences[fg_bg].end); tputs(colseq_buf, 1, putshout); + + if (do_free) { + free(colseq_buf); + colseq_buf = NULL; + } } /**/ @@ -1310,7 +1356,7 @@ zrefresh(void) nbuf[vln] = obuf[vln]; moveto(nlnct, 0); - tcout(TCCLEAREOD); + tcoutclear(TCCLEAREOD); moveto(ovln, ovcs); nbuf[vln] = nb; } else { @@ -1370,7 +1416,7 @@ zrefresh(void) if (!clearflag) { if (tccan(TCCLEAREOD)) - tcout(TCCLEAREOD); + tcoutclear(TCCLEAREOD); else cleareol = 1; /* request: clear to end of line */ if (listshown > 0) @@ -1429,7 +1475,7 @@ zrefresh(void) rpms.s = nbuf[rpms.ln = 0] + lpromptw; rpms.sen = *nbuf + winw; for (t = tmpline, tmppos = 0; tmppos < tmpll; t++, tmppos++) { - int base_atr_on = 0, base_atr_off = 0, ireg; + int base_atr_on = default_atr_on, base_atr_off = 0, ireg; int all_atr_on, all_atr_off; struct region_highlight *rhp; /* @@ -1445,9 +1491,10 @@ zrefresh(void) offset = predisplaylen; /* increment over it */ if (rhp->start + offset <= tmppos && tmppos < rhp->end + offset) { - if (base_atr_on & (TXTFGCOLOUR|TXTBGCOLOUR)) { - /* keep colour already set */ - base_atr_on |= rhp->atr & ~TXT_ATTR_COLOUR_ON_MASK; + if (rhp->atr & (TXTFGCOLOUR|TXTBGCOLOUR)) { + /* override colour with later entry */ + base_atr_on = (base_atr_on & ~TXT_ATTR_ON_VALUES_MASK) | + rhp->atr; } else { /* no colour set yet */ base_atr_on |= rhp->atr; @@ -2021,7 +2068,7 @@ refreshline(int ln) if (cleareol && !nllen && !(hasam && ln < nlnct - 1) && tccan(TCCLEAREOL)) { moveto(ln, 0); - tcout(TCCLEAREOL); + tcoutclear(TCCLEAREOL); return; } @@ -2161,7 +2208,7 @@ refreshline(int ln) /* if we can finish quickly, do so */ if ((col_cleareol >= 0) && (ccs >= col_cleareol)) { - tcout(TCCLEAREOL); + tcoutclear(TCCLEAREOL); return; } @@ -2195,7 +2242,7 @@ refreshline(int ln) zwrite(nl, i); vcs += i; if (col_cleareol >= 0) - tcout(TCCLEAREOL); + tcoutclear(TCCLEAREOL); return; } @@ -2505,7 +2552,7 @@ tcoutarg(int cap, int arg) mod_export int clearscreen(UNUSED(char **args)) { - tcout(TCCLEARSCREEN); + tcoutclear(TCCLEARSCREEN); resetneeded = 1; clearflag = 0; return 0; @@ -2823,7 +2870,7 @@ singlerefresh(ZLE_STRING_T tmpline, int tmpll, int tmpcs) } if (!vp->chr) { if (tccan(TCCLEAREOL)) - tcout(TCCLEAREOL); + tcoutclear(TCCLEAREOL); else for (; refreshop++->chr; vcs++) zputc(&zr_sp); -- cgit 1.4.1