Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

PATCH: 3.1.4: flushing input properly



"Bart Schaefer" wrote:
> Aha.  I think both substitution errors -and- parsing failures ought to
> consume the entire remainder of the input.   Consider what happens if
> the statement following the error is something destructive like a "rm",
> which was e.g. expected to happened in a different directory.

I had come to the same conclusion for the same reason.  Now we're
getting somewhere.  The following was based on a non-vanilla
(raspberry ripple, if I remember right) 3.1.3, but if I've been
following properly it should work with 3.1.4, and replaces the input.c
patchfest of the last few weeks, including 4095 and yesterday's 4161.

All history and parsing errors now discard the input buffer completely
with no funny tests.  This should remove all the ^C problems, and the
possibilities Bart alluded to.  Furthermore, the unparsed code now
gets properly tacked on to the end of the history line, so you should
be able to retrieve it and edit it.  Furtherfurthermore, one of my
personal bugbears is removed: in something like

% cmd1 !word a long expression I took ages typing in<ESC><RET>
cmd2 and this bit here I was rather attached to

when !word fails, the remainder of the buffer is saved in the history
as it is being junked from the input, ending the long and inglorious
zsh tradition that anything after a history failure is lost forever.
So when you try and re-edit the line to fix it, all that's missing is
the !word that didn't work (it's a bit more work to get that to remain
verbatim, so I didn't try).

Most of the patch is converting inerrflush() to herrflush().  In fact,
inerrflush() is now only called from the signal handler, but I wanted
to alter that as little as possible.  I hope nobody was particularly
attached to discard_input().

A slightly different issue: it remains the case that the shell
blithely ignores parse errors, executing any commands it comes across
and causing merry hell wherever it goes:

% cat scr
if [[ very_unusual_circumstances ]]; then 
  echo rm -rf /
else
  echo do nothing
fi
echo everything worked fine.
% zsh -f scr
scr: parse error near `]]' [1]
rm -rf /
scr: parse error near `else' [3]
do nothing
scr: parse error near `fi' [5]
everything worked fine.

This is in fact a question about when to stop reading input
altogether; the commands weren't in the input buffer when the parse
error happened, so this patch has no effect.  You might well argue it
ought to give up on the first error, as ksh does.  That needs careful
handling, though, to distinguish between running scripts, running
interactively, and sourcing a file.

*** Src/hist.c.inerr	Fri Jun 26 09:51:13 1998
--- Src/hist.c	Fri Jun 26 10:02:19 1998
***************
*** 251,256 ****
--- 251,264 ----
  	inungetc(c);
  }
  
+ /**/
+ void
+ herrflush(void)
+ {
+     while (!lexstop && inbufct)
+ 	hwaddc(ingetc());
+ }
+ 
  /* extract :s/foo/bar/ delimiters and arguments */
  
  /**/
***************
*** 272,279 ****
      zsfree(hsubr);
      hsubr = ptr2;
      if (hsubl && !strstr(subline, hsubl)) {
  	zerr("substitution failed", NULL, 0);
- 	inerrflush();
  	return 1;
      }
      return 0;
--- 280,287 ----
      zsfree(hsubr);
      hsubr = ptr2;
      if (hsubl && !strstr(subline, hsubl)) {
+ 	herrflush();
  	zerr("substitution failed", NULL, 0);
  	return 1;
      }
      return 0;
***************
*** 358,364 ****
  	    mev = ev = hconsearch(hsubl = ztrdup(buf), &marg);
  	    evset = 0;
  	    if (ev == -1) {
! 		inerrflush();
  		zerr("no such event: %s", buf, 0);
  		return -1;
  	    }
--- 366,372 ----
  	    mev = ev = hconsearch(hsubl = ztrdup(buf), &marg);
  	    evset = 0;
  	    if (ev == -1) {
! 		herrflush();
  		zerr("no such event: %s", buf, 0);
  		return -1;
  	    }
***************
*** 410,418 ****
  		ev = curhist;
  		evset = 1;
  	    } else if ((ev = hcomsearch(buf)) == -1) {
  		zerr("event not found: %s", buf, 0);
- 		while (c != '\n' && !lexstop)
- 		    c = ingetc();
  		return -1;
  	    } else
  		evset = 1;
--- 418,425 ----
  		ev = curhist;
  		evset = 1;
  	    } else if ((ev = hcomsearch(buf)) == -1) {
+ 		herrflush();
  		zerr("event not found: %s", buf, 0);
  		return -1;
  	    } else
  		evset = 1;
***************
*** 434,442 ****
  		    ehist = gethist(defev = mev);
  		    argc = getargc(ehist);
  		} else {
  		    zerr("Ambiguous history reference", NULL, 0);
- 		    while (c != '\n' && !lexstop)
- 			c = ingetc();
  		    return -1;
  		}
  
--- 441,448 ----
  		    ehist = gethist(defev = mev);
  		    argc = getargc(ehist);
  		} else {
+ 		    herrflush();
  		    zerr("Ambiguous history reference", NULL, 0);
  		    return -1;
  		}
  
***************
*** 493,499 ****
  		break;
  	    case 'h':
  		if (!remtpath(&sline)) {
! 		    inerrflush();
  		    zerr("modifier failed: h", NULL, 0);
  		    return -1;
  		}
--- 499,505 ----
  		break;
  	    case 'h':
  		if (!remtpath(&sline)) {
! 		    herrflush();
  		    zerr("modifier failed: h", NULL, 0);
  		    return -1;
  		}
***************
*** 500,506 ****
  		break;
  	    case 'e':
  		if (!rembutext(&sline)) {
! 		    inerrflush();
  		    zerr("modifier failed: e", NULL, 0);
  		    return -1;
  		}
--- 506,512 ----
  		break;
  	    case 'e':
  		if (!rembutext(&sline)) {
! 		    herrflush();
  		    zerr("modifier failed: e", NULL, 0);
  		    return -1;
  		}
***************
*** 507,513 ****
  		break;
  	    case 'r':
  		if (!remtext(&sline)) {
! 		    inerrflush();
  		    zerr("modifier failed: r", NULL, 0);
  		    return -1;
  		}
--- 513,519 ----
  		break;
  	    case 'r':
  		if (!remtext(&sline)) {
! 		    herrflush();
  		    zerr("modifier failed: r", NULL, 0);
  		    return -1;
  		}
***************
*** 514,520 ****
  		break;
  	    case 't':
  		if (!remlpaths(&sline)) {
! 		    inerrflush();
  		    zerr("modifier failed: t", NULL, 0);
  		    return -1;
  		}
--- 520,526 ----
  		break;
  	    case 't':
  		if (!remlpaths(&sline)) {
! 		    herrflush();
  		    zerr("modifier failed: t", NULL, 0);
  		    return -1;
  		}
***************
*** 526,532 ****
  		if (hsubl && hsubr)
  		    subst(&sline, hsubl, hsubr, gbal);
  		else {
! 		    inerrflush();
  		    zerr("no previous substitution", NULL, 0);
  		    return -1;
  		}
--- 532,538 ----
  		if (hsubl && hsubr)
  		    subst(&sline, hsubl, hsubr, gbal);
  		else {
! 		    herrflush();
  		    zerr("no previous substitution", NULL, 0);
  		    return -1;
  		}
***************
*** 544,550 ****
  		upcase(&sline);
  		break;
  	    default:
! 		inerrflush();
  		zerr("illegal modifier: %c", NULL, c);
  		return -1;
  	    }
--- 550,556 ----
  		upcase(&sline);
  		break;
  	    default:
! 		herrflush();
  		zerr("illegal modifier: %c", NULL, c);
  		return -1;
  	    }
***************
*** 995,1006 ****
  	ret = argc;
      else if (c == '%') {
  	if (evset) {
! 	    inerrflush();
  	    zerr("Ambiguous history reference", NULL, 0);
  	    return -2;
  	}
  	if (marg == -1) {
! 	    inerrflush();
  	    zerr("%% with no previous word matched", NULL, 0);
  	    return -2;
  	}
--- 1001,1012 ----
  	ret = argc;
      else if (c == '%') {
  	if (evset) {
! 	    herrflush();
  	    zerr("Ambiguous history reference", NULL, 0);
  	    return -2;
  	}
  	if (marg == -1) {
! 	    herrflush();
  	    zerr("%% with no previous word matched", NULL, 0);
  	    return -2;
  	}
***************
*** 1233,1239 ****
  
      ret = quietgethist(ev);
      if (!ret) {
! 	inerrflush();
  	zerr("no such event: %d", NULL, ev);
      }
      return ret;
--- 1239,1245 ----
  
      ret = quietgethist(ev);
      if (!ret) {
! 	herrflush();
  	zerr("no such event: %d", NULL, ev);
      }
      return ret;
***************
*** 1248,1254 ****
  
      if (arg2 < arg1 || arg1 >= nwords || arg2 >= nwords) {
  	/* remember, argN is indexed from 0, nwords is total no. of words */
! 	inerrflush();
  	zerr("no such word in event", NULL, 0);
  	return NULL;
      }
--- 1254,1260 ----
  
      if (arg2 < arg1 || arg1 >= nwords || arg2 >= nwords) {
  	/* remember, argN is indexed from 0, nwords is total no. of words */
! 	herrflush();
  	zerr("no such word in event", NULL, 0);
  	return NULL;
      }
*** Src/input.c.inerr	Tue Jun  2 17:16:03 1998
--- Src/input.c	Wed Jun 24 10:52:16 1998
***************
*** 101,109 ****
  static int inbufleft;		/* Characters left in current input
  				   stack element */
  
- static int lastc;		/* used as flag that end of line was reached */
  
- 
   /* Input must be stacked since the input queue is used by
    * various different parts of the shell.
    */
--- 101,107 ----
***************
*** 178,185 ****
  int
  ingetc(void)
  {
      if (lexstop)
! 	return lastc = ' ';
      for (;;) {
  	if (inbufleft) {
  	    inbufleft--;
--- 176,185 ----
  int
  ingetc(void)
  {
+     char lastc;
+ 
      if (lexstop)
! 	return ' ';
      for (;;) {
  	if (inbufleft) {
  	    inbufleft--;
***************
*** 202,212 ****
  	 */
  	if (strin || errflag) {
  	    lexstop = 1;
! 	    return lastc = ' ';
  	}
  	/* As a last resort, get some more input */
  	if (inputline())
! 	    return lastc = ' ';
      }
  }
  
--- 202,212 ----
  	 */
  	if (strin || errflag) {
  	    lexstop = 1;
! 	    return ' ';
  	}
  	/* As a last resort, get some more input */
  	if (inputline())
! 	    return ' ';
      }
  }
  
***************
*** 422,433 ****
  void
  inerrflush(void)
  {
!     /*
!      * This always goes character by character, but at present
!      * it is only used in the history code, where that is the only
!      * completely safe way of discarding input.
!      */
!     while ((strin || lastc != '\n') && !lexstop)
  	ingetc();
  }
  
--- 422,428 ----
  void
  inerrflush(void)
  {
!     while (!lexstop && inbufct)
  	ingetc();
  }
  
*** Src/parse.c.inerr	Fri Jun 26 11:06:51 1998
--- Src/parse.c	Fri Jun 26 11:07:52 1998
***************
*** 72,78 ****
  
  #define YYERROR  { tok = LEXERR; return NULL; }
  #define YYERRORV { tok = LEXERR; return; }
! #define COND_ERROR(X,Y) do{zerr(X,Y,0);discard_input();YYERROR}while(0)
  
  #define make_list()     allocnode(N_LIST)
  #define make_sublist()  allocnode(N_SUBLIST)
--- 72,78 ----
  
  #define YYERROR  { tok = LEXERR; return NULL; }
  #define YYERRORV { tok = LEXERR; return; }
! #define COND_ERROR(X,Y) do{herrflush();zerr(X,Y,0);YYERROR}while(0)
  
  #define make_list()     allocnode(N_LIST)
  #define make_sublist()  allocnode(N_SUBLIST)
***************
*** 142,149 ****
  	    yyerror();
  	    return NULL;
  	}
  	yyerror();
- 	discard_input();
  	return NULL;
      } else {
  	l->right = par_event();
--- 142,149 ----
  	    yyerror();
  	    return NULL;
  	}
+ 	herrflush();
  	yyerror();
  	return NULL;
      } else {
  	l->right = par_event();
***************
*** 1362,1385 ****
      n->right = (void *) c;
      n->ntype = NT_SET(N_COND, NT_STR, NT_STR, 0, 0);
      return n;
- }
- 
- /**/
- static void
- discard_input(void)
- {
-     errflag = 0;
-     if (isnewlin <= 0) {
- 	/* Discard remaining stuff after a parse error. */
- 	int c;
- 
- 	hwbegin(0);
- 	while ((c = hgetc()) != '\n' && !lexstop);
- 	if (c == '\n')
- 	    hungetc('\n');
- 	hwend();
-     }
-     errflag = 1;
  }
  
  /**/
--- 1362,1367 ----

-- 
Peter Stephenson <pws@xxxxxxxxxxxxxxxxx>       Tel: +39 50 844536
WWW:  http://www.ifh.de/~pws/
Gruppo Teorico, Dipartimento di Fisica
Piazza Torricelli 2, 56100 Pisa, Italy



Messages sorted by: Reverse Date, Date, Thread, Author