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

Re: Remaining zsh3.0-pre2 bugs



> 1. History bug:
> The magic-space binding seems to mess up the history of
> a line with a quoted argument that spawns two lines.
> Note that in the following examples the number of spaces
> and the placement of the single-quote matter.
[...]
> pride% exec ./zsh -f
> pride% bindkey ' ' magic-space
> pride% echo 'a
> > b c'
> a
> b c
> pride% history
>     1  bindkey ' ' magic-space
>     2  history

And an other bug is that here documents do not appear in the history.
That's in fact a much more difficult bug.  The bug described above can be
fixed just by adding hwgetword to the list of saved variables in lexsave.

The patch below should fix both problems.  After this patch

% cat << EOF ; echo 'foo
bar'
foobar
EOF

gives

foobar
foo
bar

which is the way other shells behave.  There is an other change in this
patch to make par_redir even more simple.  History expansion is not
disables in the name of here document (but it is still disabled in here
documents of course).  So

% cat << !$
foo
!$

will no longer work if history expansion is enabled.  Note that this change
only affect interactive shell where here documents are rarely used and even
if one uses a here document it is very unlikely that she puts a bangchar in
the end-mark.

The patch is quite big so please test it extensively as there may be some
cases when it does not behave the way it should.

Zoltan


*** Src/globals.h	1996/07/01 20:59:36	2.23
--- Src/globals.h	1996/07/01 20:59:36
***************
*** 107,112 ****
--- 107,114 ----
  /* lexical analyzer error flag */
   
  EXTERN int lexstop;
+ 
+ EXTERN struct heredocs *hdocs;
   
  /* suppress error messages */
   
*** Src/zsh.h	1996/07/05 20:50:29	2.27
--- Src/zsh.h	1996/07/05 20:50:29
***************
*** 601,606 ****
--- 601,610 ----
      int cmdoutval;
  };
  
+ struct heredocs {
+     struct heredocs *next;
+     Redir rd;
+ };
  
  /*******************************/
  /* Definitions for Hash Tables */
*** Src/parse.c	1996/07/01 20:59:36	2.15
--- Src/parse.c	1996/07/08 00:19:37
***************
*** 1118,1127 ****
  void
  par_redir(LinkList l)
  {
-     char *toks;
      struct redir *fn = (struct redir *)allocnode(N_REDIR);
      int oldcmdpos, oldnc;
-     int nohist;
  
      oldcmdpos = incmdpos;
      incmdpos = 0;
--- 1118,1125 ----
***************
*** 1130,1210 ****
  	nocorrect = 1;
      fn->type = redirtab[tok - OUTANG];
      fn->fd1 = tokfd;
-     if ((nohist = fn->type == HEREDOC || fn->type == HEREDOCDASH))
- 	STOPHIST
      yylex();
-     if (nohist)
- 	ALLOWHIST
      if (tok != STRING && tok != ENVSTRING)
  	YYERRORV;
-     toks = tokstr;
      incmdpos = oldcmdpos;
      nocorrect = oldnc;
-     yylex();
- 
- /* assign default fd */
  
      if (fn->fd1 == -1)
  	fn->fd1 = IS_READFD(fn->type) ? 0 : 1;
  
!     fn->name = toks;
  
      switch (fn->type) {
      case HEREDOC:
      case HEREDOCDASH: {
  	/* <<[-] name */
! 	char tbuf[256], *tlin = NULL;
! 	int tsiz = 0, redirl;
  
! 	/* Save the rest of the current line for later tokenization */
! 	if (!isnewlin) {
! 	    while (ingets(tbuf, 256) != NULL) {
! 		redirl = strlen(tbuf);
! 		if (tsiz == 0) {
! 		    tlin = ztrdup(tbuf);	/* Test for failure? */
! 		    tsiz = redirl;
! 		} else {
! 		    tlin = realloc(tlin, tsiz + redirl + 1);	/* Test for failure? */
! 		    strcpy(&tlin[tsiz], tbuf);
! 		    tsiz += redirl;
! 		}
! 		if (tbuf[redirl - 1] == '\n')
! 		    break;
! 	    }
! 	}
! 	cmdpush(fn->type == HEREDOC ? CS_HEREDOC : CS_HEREDOCD);
! 	/* Now grab the document */
! 	fn->name = gethere(toks, fn->type);
! 	fn->type = HERESTR;
! 	cmdpop();
! 	/* Put back the saved line to resume tokenizing */
! 	if (tsiz > 0) {
! 	    inputsetline(tlin, INP_FREE);
! 	}
  	break;
      }
- 
      case WRITE:
      case WRITENOW:
! 	if (toks[0] == Outang && toks[1] == Inpar)
  	    /* > >(...) */
  	    fn->type = OUTPIPE;
! 	else if (toks[0] == Inang && toks[1] == Inpar)
  	    YYERRORV;
  	break;
- 
      case READ:
! 	if (toks[0] == Inang && toks[1] == Inpar)
  	    /* < <(...) */
  	    fn->type = INPIPE;
! 	else if (toks[0] == Outang && toks[1] == Inpar)
  	    YYERRORV;
  	break;
      case READWRITE:
! 	if ((toks[0] == Inang || toks[0] == Outang) && toks[1] == Inpar)
! 	    fn->type = toks[0] == Inang ? INPIPE : OUTPIPE;
  	break;
      }
      addlinknode(l, fn);
  }
  
--- 1128,1178 ----
  	nocorrect = 1;
      fn->type = redirtab[tok - OUTANG];
      fn->fd1 = tokfd;
      yylex();
      if (tok != STRING && tok != ENVSTRING)
  	YYERRORV;
      incmdpos = oldcmdpos;
      nocorrect = oldnc;
  
+     /* assign default fd */
      if (fn->fd1 == -1)
  	fn->fd1 = IS_READFD(fn->type) ? 0 : 1;
  
!     fn->name = tokstr;
  
      switch (fn->type) {
      case HEREDOC:
      case HEREDOCDASH: {
  	/* <<[-] name */
! 	struct heredocs **hd;
  
! 	for (hd = &hdocs; *hd; hd = &(*hd)->next);
! 	*hd = zalloc(sizeof(struct heredocs));
! 	(*hd)->next = NULL;
! 	(*hd)->rd = fn;
  	break;
      }
      case WRITE:
      case WRITENOW:
! 	if (tokstr[0] == Outang && tokstr[1] == Inpar)
  	    /* > >(...) */
  	    fn->type = OUTPIPE;
! 	else if (tokstr[0] == Inang && tokstr[1] == Inpar)
  	    YYERRORV;
  	break;
      case READ:
! 	if (tokstr[0] == Inang && tokstr[1] == Inpar)
  	    /* < <(...) */
  	    fn->type = INPIPE;
! 	else if (tokstr[0] == Outang && tokstr[1] == Inpar)
  	    YYERRORV;
  	break;
      case READWRITE:
! 	if ((tokstr[0] == Inang || tokstr[0] == Outang) && tokstr[1] == Inpar)
! 	    fn->type = tokstr[0] == Inang ? INPIPE : OUTPIPE;
  	break;
      }
+     yylex();
      addlinknode(l, fn);
  }
  
*** Src/init.c	1996/07/07 16:03:48	2.24
--- Src/init.c	1996/07/08 00:06:51
***************
*** 737,744 ****
  {
      if (cmd) {
  	if (SHIN >= 10)
! 	    zclose(SHIN);
  	SHIN = movefd(open("/dev/null", O_RDONLY));
  	execstring(cmd, 0, 1);
  	stopmsg = 1;
  	zexit(lastval, 0);
--- 737,745 ----
  {
      if (cmd) {
  	if (SHIN >= 10)
! 	    fclose(bshin);
  	SHIN = movefd(open("/dev/null", O_RDONLY));
+ 	bshin = fdopen(SHIN, "r");
  	execstring(cmd, 0, 1);
  	stopmsg = 1;
  	zexit(lastval, 0);
*** Src/input.c	1996/06/28 02:05:24	2.7
--- Src/input.c	1996/07/07 23:05:35
***************
*** 303,324 ****
      return 0;
  }
  
- /* Read one line of at most n-1 chars from the input queue */
- 
- /**/
- char *
- ingets(char *buf, int n)
- {
-     int l;
- 
-     for (l = 0; l < n - 1 && (buf[l++] = ingetc()) != '\n' && !lexstop;);
-     if (lexstop)
- 	l--;
-     buf[l] = '\0';
- 
-     return (!lexstop || l) ? buf : NULL;
- }
- 
  /*
   * Put a string in the input queue:
   * inbuf is only freeable if the flags include INP_FREE.
--- 303,308 ----
*** Src/lex.c	1996/07/07 00:18:17	2.31
--- Src/lex.c	1996/07/07 23:36:51
***************
*** 36,41 ****
--- 36,42 ----
  static int dbparens;
  int len = 0, bsiz = 256;
  char *bptr;
+ extern int hwgetword;
  
  struct lexstack {
      struct lexstack *next;
***************
*** 55,66 ****
--- 56,70 ----
      char *hline;
      char *hptr;
      int tok;
+     int isnewlin;
      char *tokstr;
      char *bptr;
      int bsiz;
      short *chwords;
      int chwordlen;
      int chwordpos;
+     int hwgetword;
+     struct heredocs *hdocs;
  
      unsigned char *cstack;
      int csp;
***************
*** 103,116 ****
--- 107,124 ----
      ls->csp = cmdsp;
      cmdstack = (unsigned char *)zalloc(256);
      ls->tok = tok;
+     ls->isnewlin = isnewlin;
      ls->tokstr = tokstr;
      ls->bptr = bptr;
      ls->bsiz = bsiz;
      ls->chwords = chwords;
      ls->chwordlen = chwordlen;
      ls->chwordpos = chwordpos;
+     ls->hwgetword = hwgetword;
+     ls->hdocs = hdocs;
      cmdsp = 0;
      inredir = 0;
+     hdocs = NULL;
  
      ls->next = lstack;
      lstack = ls;
***************
*** 146,157 ****
--- 154,168 ----
      cmdstack = lstack->cstack;
      cmdsp = lstack->csp;
      tok = lstack->tok;
+     isnewlin = lstack->isnewlin;
      tokstr = lstack->tokstr;
      bptr = lstack->bptr;
      bsiz = lstack->bsiz;
      chwords = lstack->chwords;
      chwordlen = lstack->chwordlen;
      chwordpos = lstack->chwordpos;
+     hwgetword = lstack->hwgetword;
+     hdocs = lstack->hdocs;
      clearalstack();
      hlinesz = lstack->hlinesz;
      lexstop = errflag = 0;
***************
*** 170,175 ****
--- 181,202 ----
      do
  	tok = gettok();
      while (tok != ENDINPUT && exalias());
+     if (tok == NEWLIN || tok == ENDINPUT) {
+ 	while (hdocs) {
+ 	    struct heredocs *next = hdocs->next;
+ 
+ 	    hwbegin(0);
+ 	    cmdpush(hdocs->rd->type == HEREDOC ? CS_HEREDOC : CS_HEREDOCD);
+ 	    STOPHIST
+ 	    hdocs->rd->name = gethere(hdocs->rd->name, hdocs->rd->type);
+ 	    ALLOWHIST
+ 	    cmdpop();
+ 	    hwend();
+ 	    hdocs->rd->type = HERESTR;
+ 	    zfree(hdocs, sizeof(struct heredocs));
+ 	    hdocs = next;
+ 	}
+     }
      if (tok != NEWLIN)
  	isnewlin = 0;
      else
*** Src/hist.c	1996/07/04 19:40:08	2.16
--- Src/hist.c	1996/07/07 19:41:00
***************
*** 144,149 ****
--- 144,165 ----
      return c;
  }
  
+ /* Read one line of at most n-1 chars from the input */
+ 
+ /**/
+ char *
+ hgets(char *buf, int n)
+ {
+     int l;
+ 
+     for (l = 0; l < n - 1 && (buf[l++] = hgetc()) != '\n' && !lexstop;);
+     if (lexstop)
+ 	l--;
+     buf[l] = '\0';
+ 
+     return (!lexstop || l) ? buf : NULL;
+ }
+ 
  /**/
  void
  safeinungetc(int c)
***************
*** 725,731 ****
  }
  
  /* Gives current expansion word if not last word before chwordpos. */
! static int hwgetword = -1;
  
  /* begin a word */
  
--- 741,747 ----
  }
  
  /* Gives current expansion word if not last word before chwordpos. */
! int hwgetword = -1;
  
  /* begin a word */
  
***************
*** 794,809 ****
  {
      int pos = hwgetword > -1 ? hwgetword : chwordpos - 2;
  
! #if 0
      /* debugging only */
      if (hwgetword == -1 && !chwordpos) {
  	/* no words available */
! 	zerr("hwget called with no words.", NULL, 0);
  	*startptr = "";
  	return;
      } 
      else if (hwgetword == -1 && chwordpos%2) {
! 	zerr("hwget called in middle of word.", NULL, 0);
  	*startptr = "";
  	return;
      }
--- 810,825 ----
  {
      int pos = hwgetword > -1 ? hwgetword : chwordpos - 2;
  
! #ifdef DEBUG
      /* debugging only */
      if (hwgetword == -1 && !chwordpos) {
  	/* no words available */
! 	DPUTS(1, "hwget called with no words.");
  	*startptr = "";
  	return;
      } 
      else if (hwgetword == -1 && chwordpos%2) {
! 	DPUTS(1, "hwget called in middle of word.");
  	*startptr = "";
  	return;
      }
*** Src/exec.c	1996/07/04 19:40:08	2.53
--- Src/exec.c	1996/07/08 00:10:03
***************
*** 1442,1447 ****
--- 1442,1449 ----
      /* Do io redirections */
      while (nonempty(cmd->redir)) {
  	fn = (Redir) ugetnode(cmd->redir);
+ 	DPUTS(fn->type == HEREDOC || fn->type == HEREDOCDASH,
+ 	      "BUG: unexpanded here document\n");
  	if (fn->type == INPIPE) {
  	    if (fn->fd2 == -1) {
  		fixfds(save);
***************
*** 1852,1858 ****
      for (;;) {
  	char *u, *v;
  
! 	if (!ingets(pbuf, sizeof(pbuf)))
  	    break;
  	bptr = pbuf;
  	if (!siz || t[siz-1] == '\n') {
--- 1854,1860 ----
      for (;;) {
  	char *u, *v;
  
! 	if (!hgets(pbuf, sizeof(pbuf)))
  	    break;
  	bptr = pbuf;
  	if (!siz || t[siz-1] == '\n') {
***************
*** 1862,1868 ****
  	    for (u = bptr, v = str; *u != '\n' && *v; u++, v++)
  		if (*u != *v)
  		    break;
! 	    if (*u == '\n' && !*v)
  		break;
  	}
  	l = strlen(bptr);
--- 1864,1870 ----
  	    for (u = bptr, v = str; *u != '\n' && *v; u++, v++)
  		if (*u != *v)
  		    break;
! 	    if ((!*u || *u == '\n') && !*v)
  		break;
  	}
  	l = strlen(bptr);




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