zsh-workers
 help / color / mirror / code / Atom feed
* Terminal I/O handling fix
@ 1995-05-23 15:16 P.Stephenson
  1995-05-26  0:34 ` Richard Coleman
  0 siblings, 1 reply; 3+ messages in thread
From: P.Stephenson @ 1995-05-23 15:16 UTC (permalink / raw)
  To: Zsh hackers list

This is an updated form of a patch I posted some time ago which was
just too late to make it into zsh 2.4 (and which had some problems
with select() which I later fixed).  It separates the I/O of zle from
direct reliance on stdin/stdout or FD's 0 and 1.

There are are now two good reasons for this; the second I didn't know
about when I first posted this, but it should now be familiar.

1) Grown-up shells keep terminal editing separate from standard input
and output.  For example, you should be able to do

% exec >logfile
% echo foo
% exec >$TTY
% cat logfile
foo
% 

without any effect on editing.  This works in sh, bash, and ksh.  At
the moment, all the editing output in zsh goes to stdout as well.  

The difficult case is `exec < file' since that's supposed to change
where commands are being read from.  In fact, if zle was being used,
it always attempted to use zle to read from the file.  I've put an
explicit test in execcmd() for this, so that if commands are
notionally coming from stdin in an interactive shell and you do 'exec
< file' it tries to work out what to do.  The case where `file' is
actually a terminal is the hardest, since then there's in principle a
lot more work to do.  In fact, all I've done is re-open the terminal
files (so that exec <$TTY to fix up your terminal works like it always
did, in fact now it always makes editing work sensibly which it didn't
before when stdout was also used).  Ideally this probably needs to be
more sophisticated, or combined with the code in setmoreflags() which
sets up terminal handling initially.  (At the moment that does other
things, which is why I didn't use it.)

2) It won't have escaped your notice that redirecting the input of a
shell function has a dire effect on interactive shells at the moment
(I reported this a few weeks ago and it's now top of Zoltan's BUGS
file).  This patch helps since the terminal FD and file now aren't
affected by redirection (except for the exec < business I just talked
about).

% fn() { : }
% true | true
% fn < /dev/null
%		# kein Problem.

There is a remaining problem here, in that FD 0 does not recover ---
this is the same problem that was there before, it just doesn't affect
zle any more.  `exec <$TTY' fixes it, but it still probably needs some
work.  At least the shell doesn't exit any more.

The big downside is that we now need to remember to use `shout' for
all output in zle_*.c (with the exceptions noted in the comment at the
top of zle_main.c), and people are liable to forget.  There's probably
enough use of it there already to jog memories.

I'd have liked to make this patch smaller, but the central problem is
that zle is not well separated from the other parts of zsh.  That's
what's necessitated the extra couple of chunks of code.  It's quite
possible there are some remaining anomalies between stdout/shout.

*** Src/exec.c.tty	Tue May 23 15:07:40 1995
--- Src/exec.c	Tue May 23 15:36:01 1995
***************
*** 1271,1276 ****
--- 1271,1293 ----
  		    execerr();
  		}
  		addfd(forked, save, mfds, fn->fd1, fil, 0);
+ 		/* If this is 'exec < file', read from stdin, not terminal
+ 		 * --- unless `file' is a terminal.  (PWS 1995/05/23)
+ 		 */
+ 		if (nullexec && fn->fd1 == 0 && isset(SHINSTDIN) && interact)
+ 		    if (isatty(0)) {
+ 			if (shout) {
+ 			    fclose(shout);
+ 			    shout = 0;
+ 			}
+ 			SHTTY = movefd(open(ttyname(0), O_RDWR));
+ 			if (SHTTY == -1)
+ 			    opts[MONITOR] = OPT_UNSET;
+ 			else
+ 			    shout = fdopen(SHTTY, "w");
+ 			opts[USEZLE] = shout ? OPT_UNSET : OPT_SET;
+ 		    } else
+ 			opts[USEZLE] = OPT_UNSET;
  	    } else if (fn->type == CLOSE) {
  		if (!forked && fn->fd1 < 10)
  		    save[fn->fd1] = movefd(fn->fd1);
*** Src/globals.h.tty	Fri May 19 10:10:11 1995
--- Src/globals.h	Tue May 23 14:20:30 1995
***************
*** 387,393 ****
  /* the shell tty fd */
   
  EXTERN int SHTTY;
!  
  /* the stack of aliases we are expanding */
   
  EXTERN struct alias *alstack[MAXAL];
--- 387,397 ----
  /* the shell tty fd */
   
  EXTERN int SHTTY;
! 
! /* the FILE attached to the shell tty */
! 
! EXTERN FILE *shout;
! 
  /* the stack of aliases we are expanding */
   
  EXTERN struct alias *alstack[MAXAL];
*** Src/init.c.tty	Fri May 19 10:10:35 1995
--- Src/init.c	Tue May 23 15:45:03 1995
***************
*** 160,166 ****
      opts[HASHLISTALL] = OPT_SET;
      opts[HASHDIRS]    = OPT_SET;
      opts[INTERACTIVE] = (isatty(0)) ? OPT_SET : OPT_UNSET;
!     opts[USEZLE]      = (interact && SHTTY != -1) ? OPT_SET : OPT_UNSET;
  
      if (getuid() != geteuid() || getgid() != getegid())
  	opts[PRIVILEGED] = OPT_SET;
--- 160,166 ----
      opts[HASHLISTALL] = OPT_SET;
      opts[HASHDIRS]    = OPT_SET;
      opts[INTERACTIVE] = (isatty(0)) ? OPT_SET : OPT_UNSET;
!     /* USEZLE is now set in setmoreflags() after attempt to open terminal */
  
      if (getuid() != geteuid() || getgid() != getegid())
  	opts[PRIVILEGED] = OPT_SET;
***************
*** 322,328 ****
      subsh = 0;
  
  #ifdef JOB_CONTROL
! 	SHTTY = movefd((isatty(0)) ? dup(0) : open("/dev/tty", O_RDWR));
  	if (SHTTY == -1)
  	    opts[MONITOR] = OPT_UNSET;
  	else {
--- 322,329 ----
      subsh = 0;
  
  #ifdef JOB_CONTROL
! 	/* Make sure the tty is opened read/write. */
! 	SHTTY = movefd(open(isatty(0) ? ttyname(0) : "/dev/tty", O_RDWR));
  	if (SHTTY == -1)
  	    opts[MONITOR] = OPT_UNSET;
  	else {
***************
*** 331,336 ****
--- 332,339 ----
  
          ioctl(SHTTY, TIOCSETD, (char *)&ldisc);
  # endif
+ 	/* Associate terminal file descriptor with a FILE */
+ 	shout = fdopen(SHTTY, "w");
          gettyinfo(&shttyinfo);	/* get tty state */
  # if defined(__sgi)
          if (shttyinfo.tio.c_cc[VSWTCH] <= 0)	/* hack for irises */
***************
*** 357,366 ****
      }
  #else   /* no JOB_CONTROL */
      opts[MONITOR] = OPT_UNSET;
!     SHTTY = movefd((isatty(0)) ? dup(0) : open("/dev/tty", O_RDWR));
      if (SHTTY != -1)
  	gettyinfo(&shttyinfo);
  #endif
  }
  
  /**/
--- 360,372 ----
      }
  #else   /* no JOB_CONTROL */
      opts[MONITOR] = OPT_UNSET;
!     SHTTY = movefd(open(isatty(0) ? ttyname(0) : "/dev/tty", O_RDWR));
!     shout = fdopen(SHTTY, "w");
      if (SHTTY != -1)
  	gettyinfo(&shttyinfo);
  #endif
+ 
+     opts[USEZLE] = (interact && shout) ? OPT_SET : OPT_UNSET;
  }
  
  /**/
*** Src/utils.c.tty	Fri May 19 10:10:55 1995
--- Src/utils.c	Tue May 23 14:20:31 1995
***************
*** 1063,1073 ****
  {
      fflush(stdin);
      if (*s == '/')
! 	fprintf(stderr, "zsh: sure you want to delete all the files in %s? ", s);
      else
! 	fprintf(stderr, "zsh: sure you want to delete all the files in %s/%s? ",
  		(pwd[1]) ? pwd : "", s);
!     fflush(stderr);
      feep();
      return (getquery() == 'y');
  }
--- 1063,1074 ----
  {
      fflush(stdin);
      if (*s == '/')
! 	fprintf(shout, "zsh: sure you want to delete all the files in %s? ",
! 		s);
      else
! 	fprintf(shout, "zsh: sure you want to delete all the files in %s/%s? ",
  		(pwd[1]) ? pwd : "", s);
!     fflush(shout);
      feep();
      return (getquery() == 'y');
  }
***************
*** 1092,1098 ****
      if (val) {
  	if (!isem)
  	    settyinfo(&shttyinfo);
! 	write(2, "n\n", 2);
  	return 'n';
      }
  #endif
--- 1093,1099 ----
      if (val) {
  	if (!isem)
  	    settyinfo(&shttyinfo);
! 	write(SHTTY, "n\n", 2);
  	return 'n';
      }
  #endif
*** Src/zle_main.c.tty	Fri May 19 10:11:03 1995
--- Src/zle_main.c	Tue May 23 14:48:11 1995
***************
*** 29,34 ****
--- 29,49 ----
   *
   */
  
+ /*
+  * Note on output from zle (PWS 1995/05/23):
+  *
+  * All input and output from the editor should be to/from the file descriptor
+  * `SHTTY' and FILE `shout'.  (Normally, the former is used for input
+  * operations, reading one key at a time, and the latter for output
+  * operations, flushing after each refresh()).  Thus fprintf(shout, ...),
+  * putc(..., shout), etc., should be used for output within zle.
+  *
+  * However, the functions printbind() and printbinding() can be invoked from
+  * the builtin bindkey as well as zle, in which case output should be to
+  * stdout.  For this purpose, the static variable FILE *bindout exists, which
+  * is set to stdout in bin_bindkey() and shout in zleread().
+  */
+ 
  #define ZLEGLOBALS
  #define ZLE
  #include "zsh.h"
***************
*** 241,248 ****
  		expire_tv.tv_sec = exp100ths / 100;
  		expire_tv.tv_usec = (exp100ths % 100) * 10000L;
  		FD_ZERO(&foofd);
! 		FD_SET(0, &foofd);
! 		if (select(1, (SELECT_ARG_2_T) & foofd, NULL, NULL, &expire_tv) <= 0)
  		    return EOF;
  	    }
  #else
--- 256,264 ----
  		expire_tv.tv_sec = exp100ths / 100;
  		expire_tv.tv_usec = (exp100ths % 100) * 10000L;
  		FD_ZERO(&foofd);
! 		FD_SET(SHTTY, &foofd);
! 		if (select(SHTTY+1, (SELECT_ARG_2_T) & foofd,
! 			   NULL, NULL, &expire_tv) <= 0)
  		    return EOF;
  	    }
  #else
***************
*** 256,262 ****
  #  else
  	    ioctl(SHTTY, TCSETA, &ti.tio);
  #  endif
! 	    r = read(0, &cc, 1);
  #  ifdef HAVE_TERMIOS_H
  	    tcsetattr(SHTTY, TCSANOW, &ti.tio);
  #  else
--- 272,278 ----
  #  else
  	    ioctl(SHTTY, TCSETA, &ti.tio);
  #  endif
! 	    r = read(SHTTY, &cc, 1);
  #  ifdef HAVE_TERMIOS_H
  	    tcsetattr(SHTTY, TCSANOW, &ti.tio);
  #  else
***************
*** 266,272 ****
  # endif
  #endif
  	}
! 	while ((r = read(0, &cc, 1)) != 1) {
  	    if (r == 0) {
  		/* The test for IGNOREEOF was added to make zsh ignore ^Ds
  		   that were typed while commands are running.  Unfortuantely
--- 282,288 ----
  # endif
  #endif
  	}
! 	while ((r = read(SHTTY, &cc, 1)) != 1) {
  	    if (r == 0) {
  		/* The test for IGNOREEOF was added to make zsh ignore ^Ds
  		   that were typed while commands are running.  Unfortuantely
***************
*** 322,327 ****
--- 338,346 ----
      return ret;
  }
  
+ /* Where to print out bindings:  either stdout, or the zle output shout */
+ static FILE *bindout;
+ 
  /* read a line */
  
  /**/
***************
*** 340,346 ****
      tv.tv_sec = 0;
  #endif
  
!     fflush(stdout);
      fflush(stderr);
      intr();
      insmode = unset(OVERSTRIKE);
--- 359,365 ----
      tv.tv_sec = 0;
  #endif
  
!     fflush(shout);
      fflush(stderr);
      intr();
      insmode = unset(OVERSTRIKE);
***************
*** 365,370 ****
--- 384,390 ----
      addedsuffix = complexpect = vichgflag = 0;
      viinsbegin = 0;
      statusline = NULL;
+     bindout = shout;		/* always print bindings on terminal */
      if ((s = (unsigned char *)getnode(bufstack))) {
  	setline((char *)s);
  	zsfree((char *)s);
***************
*** 381,387 ****
      }
      initundo();
      if (unset(NOPROMPTCR))
! 	putchar('\r');
      if (tmout)
  	alarm(tmout);
      zleactive = 1;
--- 401,407 ----
      }
      initundo();
      if (unset(NOPROMPTCR))
! 	putc('\r', shout);
      if (tmout)
  	alarm(tmout);
      zleactive = 1;
***************
*** 438,447 ****
  	}
  #ifdef HAVE_SELECT
  	if (baud && !(lastcmd & ZLE_MENUCMP)) {
! 	    FD_SET(0, &foofd);
  	    if ((tv.tv_usec = cost * costmult) > 500000)
  		tv.tv_usec = 500000;
! 	    if (!kungetct && select(1, (SELECT_ARG_2_T) & foofd, NULL, NULL, &tv) <= 0)
  		refresh();
  	} else
  #endif
--- 458,468 ----
  	}
  #ifdef HAVE_SELECT
  	if (baud && !(lastcmd & ZLE_MENUCMP)) {
! 	    FD_SET(SHTTY, &foofd);
  	    if ((tv.tv_usec = cost * costmult) > 500000)
  		tv.tv_usec = 500000;
! 	    if (!kungetct && select(SHTTY+1, (SELECT_ARG_2_T) & foofd,
! 				    NULL, NULL, &tv) <= 0)
  		refresh();
  	} else
  #endif
***************
*** 781,801 ****
      while (len--) {
  	ch = (unsigned char)*s++;
  	if (ch & 0x80) {
! 	    printf("\\M-");
  	    ch &= 0x7f;
  	}
  	if (icntrl(ch))
  	    switch (ch) {
  	    case 0x7f:
! 		printf("^?");
  		break;
  	    default:
! 		printf("^%c", (ch | 0x40));
  		break;
  	} else {
  	    if (ch == '\\' || ch == '^')
! 		putchar('\\');
! 	    putchar(ch);
  	}
      }
  }
--- 802,822 ----
      while (len--) {
  	ch = (unsigned char)*s++;
  	if (ch & 0x80) {
! 	    fprintf(bindout, "\\M-");
  	    ch &= 0x7f;
  	}
  	if (icntrl(ch))
  	    switch (ch) {
  	    case 0x7f:
! 		fprintf(bindout, "^?");
  		break;
  	    default:
! 		fprintf(bindout, "^%c", (ch | 0x40));
  		break;
  	} else {
  	    if (ch == '\\' || ch == '^')
! 		putc('\\', bindout);
! 	    putc(ch, bindout);
  	}
      }
  }
***************
*** 808,822 ****
  
      if (k->func == z_undefinedkey)
  	return;
!     putchar('\"');
      printbind(str, (len = strlen(str)) ? len : 1);
!     printf("\"\t");
      if (k->func == z_sendstring) {
! 	putchar('\"');
  	printbind(k->str, k->len);
! 	printf("\"\n");
      } else
! 	printf("%s\n", zlecmds[k->func].name);
  }
  
  /**/
--- 829,843 ----
  
      if (k->func == z_undefinedkey)
  	return;
!     putc('\"', bindout);
      printbind(str, (len = strlen(str)) ? len : 1);
!     fprintf(bindout, "\"\t");
      if (k->func == z_sendstring) {
! 	putc('\"', bindout);
  	printbind(k->str, k->len);
! 	fprintf(bindout, "\"\n");
      } else
! 	fprintf(bindout, "%s\n", zlecmds[k->func].name);
  }
  
  /**/
***************
*** 853,858 ****
--- 874,880 ----
  	return 0;
      }
      tab = (ops['a']) ? altbindtab : mainbindtab;
+     bindout = stdout;	/* print bindings to stdout */
      if (!*argv) {
  	char buf[2];
  
***************
*** 1038,1044 ****
      }
      else
  	printbind(cky->nam, (len = strlen(cky->nam)) ? len : 1);
!     printf(" is ");
      if (cmd == z_sendstring) {
  	if (!cky) {
  	    char buf[2];
--- 1060,1066 ----
      }
      else
  	printbind(cky->nam, (len = strlen(cky->nam)) ? len : 1);
!     fprintf(shout, " is ");
      if (cmd == z_sendstring) {
  	if (!cky) {
  	    char buf[2];
***************
*** 1047,1062 ****
  	    buf[1] = '\0';
  	    cky = (Key) gethnode(buf, xbindtab);
  	}
! 	putchar('"');
  	printbind(cky->str, cky->len);
! 	putchar('"');
      }
      else
! 	printf("%s", zlecmds[cmd].name);
      if (clearflag)
! 	putchar('\r'), tcmultout(TCUP, TCMULTUP, nlnct);
      else
! 	putchar('\n');
  }
  
  static int func, funcfound;
--- 1069,1084 ----
  	    buf[1] = '\0';
  	    cky = (Key) gethnode(buf, xbindtab);
  	}
! 	fputc('"', shout);
  	printbind(cky->str, cky->len);
! 	putc('"', shout);
      }
      else
! 	fprintf(shout, "%s", zlecmds[cmd].name);
      if (clearflag)
! 	putc('\r', shout), tcmultout(TCUP, TCMULTUP, nlnct);
      else
! 	putc('\n', shout);
  }
  
  static int func, funcfound;
***************
*** 1070,1077 ****
      if (k->func != func || funcfound >= MAXFOUND || len <= 1)
  	return;
      if (!funcfound++)
! 	printf(" on");
!     putchar(' ');
      printbind(str, len);
  }
  
--- 1092,1099 ----
      if (k->func != func || funcfound >= MAXFOUND || len <= 1)
  	return;
      if (!funcfound++)
! 	fprintf(shout, " on");
!     putc(' ', shout);
      printbind(str, len);
  }
  
***************
*** 1089,1114 ****
  		 (isset(ALWAYSLASTPROMPT) && mult == 1)) ||
  	(unset(ALWAYSLASTPROMPT) && mult != 1);
      if (func == z_selfinsert)
! 	printf("%s is on many keys", zlecmds[func].name);
      else {
! 	printf("%s is", zlecmds[func].name);
  	for (i = 0; funcfound < MAXFOUND && i < 256; i++)
  	    if (mainbindtab[i] == func) {
  		char ch = i;
  		if (!funcfound++)
! 		    printf(" on");
! 		putchar(' ');
  		printbind(&ch, 1);
  	    }
  	if (funcfound < MAXFOUND)
  	    listhtable(xbindtab, (HFunc) printfuncbind);
  	if (!funcfound)
! 	    printf(" not bound to any key");
      }
      if (clearflag)
! 	putchar('\r'), tcmultout(TCUP, TCMULTUP, nlnct);
      else
! 	putchar('\n');
  }
  
  /**/
--- 1111,1136 ----
  		 (isset(ALWAYSLASTPROMPT) && mult == 1)) ||
  	(unset(ALWAYSLASTPROMPT) && mult != 1);
      if (func == z_selfinsert)
! 	fprintf(shout, "%s is on many keys", zlecmds[func].name);
      else {
! 	fprintf(shout, "%s is", zlecmds[func].name);
  	for (i = 0; funcfound < MAXFOUND && i < 256; i++)
  	    if (mainbindtab[i] == func) {
  		char ch = i;
  		if (!funcfound++)
! 		    fprintf(shout, " on");
! 		putc(' ', shout);
  		printbind(&ch, 1);
  	    }
  	if (funcfound < MAXFOUND)
  	    listhtable(xbindtab, (HFunc) printfuncbind);
  	if (!funcfound)
! 	    fprintf(shout, " not bound to any key");
      }
      if (clearflag)
! 	putc('\r', shout), tcmultout(TCUP, TCMULTUP, nlnct);
      else
! 	putc('\n', shout);
  }
  
  /**/
***************
*** 1123,1130 ****
  	    clearflag = 0;
  	}
  	if (postedit)
! 	    printf("%s", postedit);
! 	fflush(stdout);
  	resetneeded = 1;
  	settyinfo(&shttyinfo);
      }
--- 1145,1152 ----
  	    clearflag = 0;
  	}
  	if (postedit)
! 	    fprintf(shout, "%s", postedit);
! 	fflush(shout);
  	resetneeded = 1;
  	settyinfo(&shttyinfo);
      }
*** Src/zle_misc.c.tty	Fri May 19 10:11:05 1995
--- Src/zle_misc.c	Tue May 23 14:20:33 1995
***************
*** 680,686 ****
  {
      if (termok && !isset(SINGLELINEZLE) && tcstr[cap]) {
  	if (flag == 0) 
! 	    tputs(tcstr[cap], 1, putraw);
  	else {
  	    if (docount) {
  		int  t0;
--- 680,686 ----
  {
      if (termok && !isset(SINGLELINEZLE) && tcstr[cap]) {
  	if (flag == 0) 
! 	    tputs(tcstr[cap], 1, putshout);
  	else {
  	    if (docount) {
  		int  t0;
*** Src/zle_refresh.c.tty	Fri May 19 10:11:08 1995
--- Src/zle_refresh.c	Tue May 23 14:23:24 1995
***************
*** 194,204 ****
          if (isset(SINGLELINEZLE) || !termok)
              vcs = 0;
          else if (pptlen && !clearflag) {
!             fwrite(pptbuf, pptlen, 1, stdout);
! 	    fflush(stdout);
  	}
  	if (clearflag)
! 	    putchar('\r'), vcs = 0, moveto(0, pptw);
  	clearf = clearflag;
      } else if (winw != columns)
  	resetvideo();
--- 194,204 ----
          if (isset(SINGLELINEZLE) || !termok)
              vcs = 0;
          else if (pptlen && !clearflag) {
!             fwrite(pptbuf, pptlen, 1, shout);
! 	    fflush(shout);
  	}
  	if (clearflag)
! 	    putc('\r', shout), vcs = 0, moveto(0, pptw);
  	clearf = clearflag;
      } else if (winw != columns)
  	resetvideo();
***************
*** 338,344 ****
      /* output the right-prompt if appropriate */
  	if (put_rpmpt && !ln && !oput_rpmpt) {
  	    moveto(0, winw - 1 - rpw);
! 	    fwrite(pptbuf, pptlen, 1, stdout);
  	    vcs = winw - 1;
  	/* reset character attributes to that set by the main prompt */
  	    txtchange = pmpt_attr;
--- 338,344 ----
      /* output the right-prompt if appropriate */
  	if (put_rpmpt && !ln && !oput_rpmpt) {
  	    moveto(0, winw - 1 - rpw);
! 	    fwrite(pptbuf, pptlen, 1, shout);
  	    vcs = winw - 1;
  	/* reset character attributes to that set by the main prompt */
  	    txtchange = pmpt_attr;
***************
*** 398,404 ****
      oput_rpmpt = put_rpmpt;
      if (nlnct > vmaxln)
  	vmaxln = nlnct;
!     fflush(stdout);		/* make sure everything is written out */
  }
  
  #define tcinscost(X)   (tccan(TCMULTINS) ? tclen[TCMULTINS] : (X)*tclen[TCINS])
--- 398,404 ----
      oput_rpmpt = put_rpmpt;
      if (nlnct > vmaxln)
  	vmaxln = nlnct;
!     fflush(shout);		/* make sure everything is written out */
  }
  
  #define tcinscost(X)   (tccan(TCMULTINS) ? tclen[TCMULTINS] : (X)*tclen[TCINS])
***************
*** 495,501 ****
  	if (!*ol) {
  	    i = (col_cleareol != -1) ? col_cleareol : nllen;
  	    i -= ccs;
! 	    fwrite(nl, i, 1, stdout);
  	    SELECT_ADD_COST(i);
  	    vcs += i;
  	    if (col_cleareol != -1) {
--- 495,501 ----
  	if (!*ol) {
  	    i = (col_cleareol != -1) ? col_cleareol : nllen;
  	    i -= ccs;
! 	    fwrite(nl, i, 1, shout);
  	    SELECT_ADD_COST(i);
  	    vcs += i;
  	    if (col_cleareol != -1) {
***************
*** 535,541 ****
  		    if (tcinscost(i) < pfxlen(p1, ol)) {
  			tc_inschars(i);
  			SELECT_ADD_COST(2 * i);
! 			fwrite(nl, i, 1, stdout);
  			ccs = (vcs += i);
  			nl = p1;
  			break;
--- 535,541 ----
  		    if (tcinscost(i) < pfxlen(p1, ol)) {
  			tc_inschars(i);
  			SELECT_ADD_COST(2 * i);
! 			fwrite(nl, i, 1, shout);
  			ccs = (vcs += i);
  			nl = p1;
  			break;
***************
*** 546,552 ****
  	}
      /* we can't do any fancy tricks, so just dump the single character
         and keep on trying */
! 	putchar(*nl);
  	SELECT_ADD_COST(1);
  	nl++, ol++;
  	ccs++, vcs++;
--- 546,552 ----
  	}
      /* we can't do any fancy tricks, so just dump the single character
         and keep on trying */
! 	putc(*nl, shout);
  	SELECT_ADD_COST(1);
  	nl++, ol++;
  	ccs++, vcs++;
***************
*** 565,575 ****
  
      if (vcs == winw) {
  	if (!hasam) {
! 	    putchar('\r');
! 	    putchar('\n');
  	    SELECT_ADD_COST(2);
  	} else {
! 	    putchar(am_char);
  	    tcout(TCLEFT);
  	    SELECT_ADD_COST(1 + tclen[TCLEFT]);
  	}
--- 565,575 ----
  
      if (vcs == winw) {
  	if (!hasam) {
! 	    putc('\r', shout);
! 	    putc('\n', shout);
  	    SELECT_ADD_COST(2);
  	} else {
! 	    putc(am_char, shout);
  	    tcout(TCLEFT);
  	    SELECT_ADD_COST(1 + tclen[TCLEFT]);
  	}
***************
*** 597,606 ****
  		vln = ln;
  		continue;
  	    }
! 	putchar('\r'), vcs = 0; /* safety precaution */
  	SELECT_ADD_COST(1);
  	while (ln > vln) {
! 	    putchar('\n');
  	    SELECT_ADD_COST(1);
  	    vln++;
  	}
--- 597,606 ----
  		vln = ln;
  		continue;
  	    }
! 	putc('\r', shout), vcs = 0; /* safety precaution */
  	SELECT_ADD_COST(1);
  	while (ln > vln) {
! 	    putc('\n', shout);
  	    SELECT_ADD_COST(1);
  	    vln++;
  	}
***************
*** 608,614 ****
  /* choose cheapest movements for ttys without multiple movement capabilities -
     do this now because it's easier (to code) */
      if (cl <= vcs / 2) {
! 	putchar('\r');
  	SELECT_ADD_COST(1);
  	vcs = 0;
      }
--- 608,614 ----
  /* choose cheapest movements for ttys without multiple movement capabilities -
     do this now because it's easier (to code) */
      if (cl <= vcs / 2) {
! 	putc('\r', shout);
  	SELECT_ADD_COST(1);
  	vcs = 0;
      }
***************
*** 690,698 ****
      for (j = 0, t = nbuf[vln]; *t && (j < i); j++, t++);
      if (j == i)
  	for ( ; *t && ct; ct--, t++)
! 	    putchar(*t);
      while (ct--)
! 	putchar(' ');		/* not my fault your terminal can't go right */
  }
  
  /**/
--- 690,698 ----
      for (j = 0, t = nbuf[vln]; *t && (j < i); j++, t++);
      if (j == i)
  	for ( ; *t && ct; ct--, t++)
! 	    putc(*t, shout);
      while (ct--)
! 	putc(' ', shout);	/* not my fault your terminal can't go right */
  }
  
  /**/
***************
*** 704,711 ****
      if (ct && !tcmultout(TCDOWN, TCMULTDOWN, ct)) {
  	SELECT_ADD_COST(ct + 1);
  	while (ct--)
! 	    putchar('\n');
! 	putchar('\r'), ret = -1;
      }
      return ret;
  }
--- 704,711 ----
      if (ct && !tcmultout(TCDOWN, TCMULTDOWN, ct)) {
  	SELECT_ADD_COST(ct + 1);
  	while (ct--)
! 	    putc('\n', shout);
! 	putc('\r', shout), ret = -1;
      }
      return ret;
  }
***************
*** 713,729 ****
  /* I'm NOT going to worry about padding unless anyone complains. */
  
  /**/
  void
  tcout(int cap)
  {
!     tputs(tcstr[cap], 1, putraw);
  }
  
  /**/
  void
  tcoutarg(int cap, int arg)
  {
!     tputs(tgoto(tcstr[cap], arg, arg), 1, putraw);
  }
  
  /**/
--- 713,737 ----
  /* I'm NOT going to worry about padding unless anyone complains. */
  
  /**/
+ int
+ putshout(int c)
+ {
+     putc(c, shout);
+     return 0;
+ }
+ 
+ /**/
  void
  tcout(int cap)
  {
!     tputs(tcstr[cap], 1, putshout);
  }
  
  /**/
  void
  tcoutarg(int cap, int arg)
  {
!     tputs(tgoto(tcstr[cap], arg, arg), 1, putshout);
  }
  
  /**/
***************
*** 740,746 ****
  redisplay(void)
  {
      moveto(0, pptw);
!     putchar('\r');
      resetneeded = 1;
      clearflag = 0;
  }
--- 748,754 ----
  redisplay(void)
  {
      moveto(0, pptw);
!     putc('\r', shout);
      resetneeded = 1;
      clearflag = 0;
  }
***************
*** 818,824 ****
  
  	if (!*refreshop) {
  	    if ((t0 = strlen(vp)))
! 		fwrite(vp, t0, 1, stdout);
  	    vcs += t0;
  	    break;
  	}
--- 826,832 ----
  
  	if (!*refreshop) {
  	    if ((t0 = strlen(vp)))
! 		fwrite(vp, t0, 1, shout);
  	    vcs += t0;
  	    break;
  	}
***************
*** 827,836 ****
  		tcout(TCCLEAREOL);
  	    else
  		for (; *refreshop++; vcs++)
! 		    putchar(' ');
  	    break;
  	}
! 	putchar(*vp);
  	vcs++, t0++;
  	vp++, refreshop++;
      }
--- 835,844 ----
  		tcout(TCCLEAREOL);
  	    else
  		for (; *refreshop++; vcs++)
! 		    putc(' ', shout);
  	    break;
  	}
! 	putc(*vp, shout);
  	vcs++, t0++;
  	vp++, refreshop++;
      }
***************
*** 840,846 ****
      qbuf = nbuf;
      nbuf = obuf;
      obuf = qbuf;
!     fflush(stdout);		/* make sure everything is written out */
  }
  
  /**/
--- 848,854 ----
      qbuf = nbuf;
      nbuf = obuf;
      obuf = qbuf;
!     fflush(shout);		/* make sure everything is written out */
  }
  
  /**/
***************
*** 850,856 ****
      if (pos == vcs)
  	return;
      if (pos <= vcs / 2) {
! 	putchar('\r');
  	vcs = 0;
      }
      if (pos < vcs) {
--- 858,864 ----
      if (pos == vcs)
  	return;
      if (pos <= vcs / 2) {
! 	putc('\r', shout);
  	vcs = 0;
      }
      if (pos < vcs) {
***************
*** 862,868 ****
  	    vcs = pos;
  	else
  	    while (pos > vcs) {
! 		putchar(nbuf[0][vcs]);
  		vcs++;
  	    }
      }
--- 870,876 ----
  	    vcs = pos;
  	else
  	    while (pos > vcs) {
! 		putc(nbuf[0][vcs], shout);
  		vcs++;
  	    }
      }
*** Src/zle_tricky.c.tty	Fri May 19 10:11:13 1995
--- Src/zle_tricky.c	Tue May 23 14:20:34 1995
***************
*** 2981,2987 ****
  
  	if (clearflag)
  	    tcmultout(TCUP, TCMULTUP, up + nlnct);
! 	fflush(stdout);
      }
      ll = strlen((char *)line);
      if (cs > ll)
--- 2981,2987 ----
  
  	if (clearflag)
  	    tcmultout(TCUP, TCMULTUP, up + nlnct);
! 	fflush(shout);
      }
      ll = strlen((char *)line);
      if (cs > ll)
***************
*** 3401,3413 ****
  		switch (*p) {
  		case '%':
  		    if (dopr)
! 			putchar('%');
  		    cc++;
  		    break;
  		case 'n':
  		    sprintf(nc, "%d", n);
  		    if (dopr)
! 			printf(nc);
  		    cc += strlen(nc);
  	    } else
  		break;
--- 3401,3413 ----
  		switch (*p) {
  		case '%':
  		    if (dopr)
! 			putc('%', shout);
  		    cc++;
  		    break;
  		case 'n':
  		    sprintf(nc, "%d", n);
  		    if (dopr)
! 			fprintf(shout, nc);
  		    cc += strlen(nc);
  	    } else
  		break;
***************
*** 3418,3428 ****
  		cc = 0;
  	    }
  	    if (dopr)
! 		putchar(*p);
  	}
      }
      if (dopr)
! 	putchar('\n');
  
      return l + (cc / columns);
  }
--- 3418,3428 ----
  		cc = 0;
  	    }
  	    if (dopr)
! 		putc(*p, shout);
  	}
      }
      if (dopr)
! 	putc('\n', shout);
  
      return l + (cc / columns);
  }
***************
*** 3492,3515 ****
      /* Maybe we have to ask if the user wants to see the list. */
      if ((listmax && ct > listmax) || (!listmax && up >= lines)) {
  	setterm();
! 	fprintf(stdout, "zsh: do you wish to see all %d possibilities? ", ct);
! 	fflush(stdout);
  	if (getzlequery() != 'y') {
  	    if (clearflag) {
! 		putchar('\r');
  		if (tccan(TCCLEAREOD))
  		    tcout(TCCLEAREOD);
  		tcmultout(TCUP, TCMULTUP, nlnct);
  	    } else
! 		putchar('\n');
  	    return;
  	}
  	if (clearflag) {
! 	    putchar('\r');
  	    if (tccan(TCCLEAREOD))
  		tcout(TCCLEAREOD);
  	} else
! 	    putchar('\n');
  	settyinfo(&shttyinfo);
      }
      /* After the query, the explanation string was deleted, print it
--- 3492,3515 ----
      /* Maybe we have to ask if the user wants to see the list. */
      if ((listmax && ct > listmax) || (!listmax && up >= lines)) {
  	setterm();
! 	fprintf(shout, "zsh: do you wish to see all %d possibilities? ", ct);
! 	fflush(shout);
  	if (getzlequery() != 'y') {
  	    if (clearflag) {
! 		putc('\r', shout);
  		if (tccan(TCCLEAREOD))
  		    tcout(TCCLEAREOD);
  		tcmultout(TCUP, TCMULTUP, nlnct);
  	    } else
! 		putc('\n', shout);
  	    return;
  	}
  	if (clearflag) {
! 	    putc('\r', shout);
  	    if (tccan(TCCLEAREOD))
  		tcout(TCCLEAREOD);
  	} else
! 	    putc('\n', shout);
  	settyinfo(&shttyinfo);
      }
      /* After the query, the explanation string was deleted, print it
***************
*** 3532,3556 ****
  		if (ispattern) {
  		    sav = ap[0][t2 - boff];
  		    ap[0][t2 - boff] = '\0';
! 		    printf("%s", *ap + off);
  		    ap[0][t2 - boff] = sav;
  		    pb = *ap;
  		    t2 -= off + boff - 1;
  		} else {
! 		    printf("%s%s%s", fpre, *ap, fsuf);
  		    sprintf(pb = pbuf, "%s%s%s%s",
  			    (prpre && *prpre) ? prpre : "./", fpre, *ap, fsuf);
  		}
  		if (ztat(pb, &buf, 1))
! 		    putchar(' ');
  		else
  		    /* Print the file type character. */
! 		    putchar(file_type(buf.st_mode));
  		for (t0 = colsz; t0 && *ap; t0--, ap++);
  		if (*ap)
  		    /* And add spaces to make the columns aligned. */
  		    for (; t2 < fw; t2++)
! 			putchar(' ');
  	    }
  	} else
  	    while (*ap) {
--- 3532,3556 ----
  		if (ispattern) {
  		    sav = ap[0][t2 - boff];
  		    ap[0][t2 - boff] = '\0';
! 		    fprintf(shout, "%s", *ap + off);
  		    ap[0][t2 - boff] = sav;
  		    pb = *ap;
  		    t2 -= off + boff - 1;
  		} else {
! 		    fprintf(shout, "%s%s%s", fpre, *ap, fsuf);
  		    sprintf(pb = pbuf, "%s%s%s%s",
  			    (prpre && *prpre) ? prpre : "./", fpre, *ap, fsuf);
  		}
  		if (ztat(pb, &buf, 1))
! 		    putc(' ', shout);
  		else
  		    /* Print the file type character. */
! 		    putc(file_type(buf.st_mode), shout);
  		for (t0 = colsz; t0 && *ap; t0--, ap++);
  		if (*ap)
  		    /* And add spaces to make the columns aligned. */
  		    for (; t2 < fw; t2++)
! 			putc(' ', shout);
  	    }
  	} else
  	    while (*ap) {
***************
*** 3560,3582 ****
  		if (ispattern) {
  		    sav = ap[0][t2 - boff];
  		    ap[0][t2 - boff] = '\0';
! 		    printf("%s", *ap + off);
  		    ap[0][t2 - boff] = sav;
  		    t2 -= off + boff;
  		} else if (!(haswhat & HAS_MISC)) {
! 		    printf("%s%s%s", fpre, *ap, fsuf);
  		    t2 += fpl + fsl;
  		} else {
! 		    printf("%s%s%s", lpre, *ap, lsuf);
  		    t2 += lpl + lsl;
  		}
  		for (t0 = colsz; t0 && *ap; t0--, ap++);
  		if (*ap)
  		    for (; t2 < fw; t2++)
! 			putchar(' ');
  	    }
  	if (t1 != colsz - 1 || !clearflag)
! 	    putchar('\n');
      }
      if (clearflag)
  	/* Move the cursor up to the prompt, if always_last_prompt is set
--- 3560,3582 ----
  		if (ispattern) {
  		    sav = ap[0][t2 - boff];
  		    ap[0][t2 - boff] = '\0';
! 		    fprintf(shout, "%s", *ap + off);
  		    ap[0][t2 - boff] = sav;
  		    t2 -= off + boff;
  		} else if (!(haswhat & HAS_MISC)) {
! 		    fprintf(shout, "%s%s%s", fpre, *ap, fsuf);
  		    t2 += fpl + fsl;
  		} else {
! 		    fprintf(shout, "%s%s%s", lpre, *ap, lsuf);
  		    t2 += lpl + lsl;
  		}
  		for (t0 = colsz; t0 && *ap; t0--, ap++);
  		if (*ap)
  		    for (; t2 < fw; t2++)
! 			putc(' ', shout);
  	    }
  	if (t1 != colsz - 1 || !clearflag)
! 	    putc('\n', shout);
      }
      if (clearflag)
  	/* Move the cursor up to the prompt, if always_last_prompt is set
***************
*** 3584,3594 ****
  	if (up < lines)
  	    tcmultout(TCUP, TCMULTUP, up);
  	else
! 	    clearflag = 0, putchar('\n');
  
      expl = NULL;
  
!     fflush(stdout);
  }
  
  /* A list printing function, used for COMP_LIST_COMPLETE, it sorts the
--- 3584,3594 ----
  	if (up < lines)
  	    tcmultout(TCUP, TCMULTUP, up);
  	else
! 	    clearflag = 0, putc('\n', shout);
  
      expl = NULL;
  
!     fflush(shout);
  }
  
  /* A list printing function, used for COMP_LIST_COMPLETE, it sorts the
*** Src/zle_utils.c.tty	Fri May 19 10:11:14 1995
--- Src/zle_utils.c	Tue May 23 14:20:34 1995
***************
*** 300,306 ****
      /* check for typeahead, which is treated as a negative response */
      ioctl(SHTTY, FIONREAD, (char *)&val);
      if (val) {
! 	putchar('n');
  	return 'n';
      }
  #endif
--- 300,306 ----
      /* check for typeahead, which is treated as a negative response */
      ioctl(SHTTY, FIONREAD, (char *)&val);
      if (val) {
! 	putc('n', shout);
  	return 'n';
      }
  #endif
***************
*** 315,320 ****
  	c = tulower(c);
  
      /* echo response and return */
!     putchar(c);
      return (int)c;
  }
--- 315,320 ----
  	c = tulower(c);
  
      /* echo response and return */
!     putc(c, shout);
      return (int)c;
  }

-- 
Peter Stephenson <P.Stephenson@swansea.ac.uk>  Tel: +44 1792 205678 extn. 4461
WWW:  http://python.swan.ac.uk/~pypeters/      Fax: +44 1792 295324
Department of Physics, University of Wales, Swansea,
Singleton Park, Swansea, SA2 8PP, U.K.


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: Terminal I/O handling fix
  1995-05-23 15:16 Terminal I/O handling fix P.Stephenson
@ 1995-05-26  0:34 ` Richard Coleman
  1995-05-26 10:10   ` P.Stephenson
  0 siblings, 1 reply; 3+ messages in thread
From: Richard Coleman @ 1995-05-26  0:34 UTC (permalink / raw)
  To: zsh-workers

> This is an updated form of a patch I posted some time ago which was
> just too late to make it into zsh 2.4 (and which had some problems
> with select() which I later fixed).  It separates the I/O of zle from
> direct reliance on stdin/stdout or FD's 0 and 1.

This is a change that is definitely needed.  The mishandling of
internal fd's seems to be the source of most of zsh's worst
(in the sense of being the hardest to fix) bugs.

> The difficult case is `exec < file' since that's supposed to change
> where commands are being read from.  In fact, if zle was being used,
> it always attempted to use zle to read from the file.  I've put an
> explicit test in execcmd() for this, so that if commands are
> notionally coming from stdin in an interactive shell and you do 'exec
> < file' it tries to work out what to do.  The case where `file' is
> actually a terminal is the hardest, since then there's in principle a
> lot more work to do.  In fact, all I've done is re-open the terminal
> files (so that exec <$TTY to fix up your terminal works like it always
> did, in fact now it always makes editing work sensibly which it didn't
> before when stdout was also used).  Ideally this probably needs to be
> more sophisticated, or combined with the code in setmoreflags() which
> sets up terminal handling initially.  (At the moment that does other
> things, which is why I didn't use it.)

This is the part that I like the least.  I'm wary of adding more tricky
logic to exec.c since it's basically incomprehensible already.  I've
started a little cleanup of the tty initialization in setmoreflags in
beta9-test5 (which unfortunately causes your patch to fail, but it
is easy to fix by hand).  What type of things would need to be added
here to fix the problems you are talking about.  I guess I don't
understand the issues involved.

> I'd have liked to make this patch smaller, but the central problem is
> that zle is not well separated from the other parts of zsh.  That's
> what's necessitated the extra couple of chunks of code.  It's quite
> possible there are some remaining anomalies between stdout/shout.

The zle code could definitely stand to be modularized a bit.  I'm open
to suggestions and/or patches on how to clean this up.

This go for the rest of zsh.  If anyone has suggestions on how to
restructure/cleanup parts of the code, let me know.  This can
include adding comments, moving functions from one file to another,
or whatever.  Of course this doesn't fix any bugs, but anything to
improve the readability of the code will help maintainability.

rc


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: Terminal I/O handling fix
  1995-05-26  0:34 ` Richard Coleman
@ 1995-05-26 10:10   ` P.Stephenson
  0 siblings, 0 replies; 3+ messages in thread
From: P.Stephenson @ 1995-05-26 10:10 UTC (permalink / raw)
  To: Zsh hackers list

coleman@math.gatech.edu wrote:
> > The difficult case is `exec < file' since that's supposed to change
> > where commands are being read from.  In fact, if zle was being used,
> > it always attempted to use zle to read from the file.  I've put an
> > explicit test in execcmd() for this, so that if commands are
> > notionally coming from stdin in an interactive shell and you do 'exec
> > < file' it tries to work out what to do.  The case where `file' is
> > actually a terminal is the hardest, since then there's in principle a
> > lot more work to do.  In fact, all I've done is re-open the terminal
> > files (so that exec <$TTY to fix up your terminal works like it always
> > did, in fact now it always makes editing work sensibly which it didn't
> > before when stdout was also used).  Ideally this probably needs to be
> > more sophisticated, or combined with the code in setmoreflags() which
> > sets up terminal handling initially.  (At the moment that does other
> > things, which is why I didn't use it.)
> 
> This is the part that I like the least.  I'm wary of adding more tricky
> logic to exec.c since it's basically incomprehensible already.  I've
> started a little cleanup of the tty initialization in setmoreflags in
> beta9-test5 (which unfortunately causes your patch to fail, but it
> is easy to fix by hand).  What type of things would need to be added
> here to fix the problems you are talking about.  I guess I don't
> understand the issues involved.

I agree it would be an improvement to have this code in some function
rather than in execcmd(). I don't think there's anything basically
wrong with setmoreflags(); I should think adding a few more checks for
things which were done already would do the trick, such as

(1) the malloc(BUFSIZ)'s (I don't know if you need to call setbuffer
again, but presumably it's harmless as long as you keep a static
variable for the buffer --- though if it does need redoing, the right
time is presumably when fd's 1 and 2 change, not 0)

(2) checking shout/SHTTY and closing them if they're already open
(though if you fclose(shout) you won't need to close(SHTTY),
presumably)

(3) moving out that `subsh = 0' (don't quite know what it's doing,
shouldn't it always be 0 at that point if it needs to be?).

At a cursory look, anything else can be stand to be done over again
(and probably should be if the shell's stdin changes).  Probably
setmoreflags() could then become initterm() or something like that;
perhaps it's natural place is then next to setterm() in zle_main.c.

Then changing the block following the `if (nullexec ... interact)'
added in execcmd() to call the revamped function ought to work.  If
`exec <...' is to work properly, I think some test or other at that
point is inescapable.

-- 
Peter Stephenson <P.Stephenson@swansea.ac.uk>  Tel: +44 1792 205678 extn. 4461
WWW:  http://python.swan.ac.uk/~pypeters/      Fax: +44 1792 295324
Department of Physics, University of Wales, Swansea,
Singleton Park, Swansea, SA2 8PP, U.K.


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~1995-05-26 10:14 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1995-05-23 15:16 Terminal I/O handling fix P.Stephenson
1995-05-26  0:34 ` Richard Coleman
1995-05-26 10:10   ` P.Stephenson

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).