about summary refs log tree commit diff
path: root/Src
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2008-05-06 18:19:14 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2008-05-06 18:19:14 +0000
commit74e5fcee384467e74983a3077bad97974477e877 (patch)
tree00664bc467a0cabc140351f20f92e8a8b24ce2d4 /Src
parentdbe5fd93a7f29a6f800d470fff3c1b946ec3fdb4 (diff)
downloadzsh-74e5fcee384467e74983a3077bad97974477e877.tar.gz
zsh-74e5fcee384467e74983a3077bad97974477e877.tar.xz
zsh-74e5fcee384467e74983a3077bad97974477e877.zip
24953: "default" zle_highlight; fix allocation bug in colour sequences
Diffstat (limited to 'Src')
-rw-r--r--Src/Zle/zle_refresh.c229
1 files changed, 138 insertions, 91 deletions
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);