text input: fix problem with autoindenting and ^^D
authorSven Verdoolaege <skimo@kotnet.org>
Tue, 29 Dec 2009 18:07:19 +0000 (29 19:07 +0100)
committerSven Verdoolaege <skimo@kotnet.org>
Fri, 1 Jan 2010 15:34:12 +0000 (1 16:34 +0100)
The following sequence would lead to an abort:

:se ai^Mi^I^M^^Da^D

The problem appears to be that the carat state is overloaded
to track both the current state and something that happened
before ("C_NOCHANGE").  Keep track of "nochange" in a separate
variable.

Problem reported and analyzed by Peter Bex <Peter.Bex@xs4all.nl>

common/common.h
ex/ex_txt.c
vi/v_txt.c

index 624a53f..45ac768 100644 (file)
@@ -57,7 +57,7 @@ typedef struct _text          TEXT;
 typedef struct _win            WIN;
 
 /* Autoindent state. */
-typedef enum { C_NOTSET, C_CARATSET, C_NOCHANGE, C_ZEROSET } carat_t;
+typedef enum { C_NOTSET, C_CARATSET, C_ZEROSET } carat_t;
 
 /* Busy message types. */
 typedef enum { BUSY_ON = 1, BUSY_OFF, BUSY_UPDATE } busy_t;
index 410d984..f551ee5 100644 (file)
@@ -62,6 +62,7 @@ ex_txt(SCR *sp, TEXTH *tiqh, ARG_CHAR_T prompt, u_int32_t flags)
        carat_t carat_st;
        size_t cnt;
        int rval;
+       int nochange;
 
        rval = 0;
 
@@ -110,7 +111,7 @@ newtp:              if ((tp = text_init(sp, NULL, 0, 32)) == NULL)
                txt_prompt(sp, tp, prompt, flags);
        }
 
-       for (carat_st = C_NOTSET;;) {
+       for (carat_st = C_NOTSET, nochange = 0;;) {
                if (v_event_get(sp, &ev, 0, 0))
                        goto err;
 
@@ -206,7 +207,8 @@ notlast:                    CIRCLEQ_REMOVE(tiqh, tp, q);
                         * erased.
                         */
                        if (LF_ISSET(TXT_AUTOINDENT)) {
-                               if (carat_st == C_NOCHANGE) {
+                               if (nochange) {
+                                       nochange = 0;
                                        if (v_txt_auto(sp,
                                            OOBLNO, &ait, ait.ai, ntp))
                                                goto err;
@@ -293,7 +295,8 @@ notlast:                    CIRCLEQ_REMOVE(tiqh, tp, q);
                                MEMCPYW(ait.lb, tp->lb, tp->ai);
                                ait.ai = ait.len = tp->ai;
 
-                               carat_st = C_NOCHANGE;
+                               carat_st = C_NOTSET;
+                               nochange = 1;
                                goto leftmargin;
                        case C_ZEROSET:                 /* 0^D */
                                if (tp->len > tp->ai + 1)
index 76b56b8..65e33e1 100644 (file)
@@ -275,6 +275,7 @@ v_txt(SCR *sp, VICMD *vp, MARK *tm, const CHAR_T *lp, size_t len, ARG_CHAR_T pro
        int showmatch;          /* Showmatch set on this character. */
        int wm_set, wm_skip;    /* Wrapmargin happened, blank skip flags. */
        int max, tmp;
+       int nochange;
        CHAR_T *p;
 
        gp = sp->gp;
@@ -458,6 +459,7 @@ newtp:              if ((tp = text_init(sp, lp, len, len + 32)) == NULL)
        /* Other text input mode setup. */
        quote = Q_NOTSET;
        carat = C_NOTSET;
+       nochange = 0;
        FL_INIT(is_flags,
            LF_ISSET(TXT_SEARCHINCR) ? IS_RESTART | IS_RUNNING : 0);
        filec_redraw = hexcnt = showmatch = 0;
@@ -785,7 +787,8 @@ k_cr:               if (LF_ISSET(TXT_CR)) {
                 * characters may have been erased.
                 */
                if (LF_ISSET(TXT_AUTOINDENT)) {
-                       if (carat == C_NOCHANGE) {
+                       if (nochange) {
+                               nochange = 0;
                                if (v_txt_auto(sp, OOBLNO, &ait, ait.ai, ntp))
                                        goto err;
                                FREE_SPACEW(sp, ait.lb, ait.lb_len);
@@ -958,7 +961,8 @@ k_escape:   LINE_RESOLVE;
                        MEMMOVEW(ait.lb, tp->lb, tp->ai);
                        ait.ai = ait.len = tp->ai;
 
-                       carat = C_NOCHANGE;
+                       carat = C_NOTSET;
+                       nochange = 1;
                        goto leftmargin;
                case C_ZEROSET:         /* 0^D */
                        if (tp->ai == 0 || tp->cno > tp->ai + tp->offset + 1)