[comp.sources.bugs] My screen diffs

davison@drivax.DRI (Wayne Davison) (03/08/89)

For all those who requested it, (and even those who didn't), here is the
context diffs for my modifications to screen.  Oliver Laumann has copies
of these patches (as well as many others) and will probably be releasing
an updated version in the months ahead, after his work-load subsides and
he gets a chance to do whatever else he would like to do BESIDES work on
screen.

In addition to the changes I alluded to in a previous posting (which I am
including below, for those who missed it), these diffs fix the following
bugs:

    o	A friend of mine (riddle here @ drivax) noted that if you already
	have the environment variable WINDOW defined, screen does not properly
	supersede it.

    o	If your termcap has only two of the three character-attribute-ending
	strings defined (i.e. SE, UE, & ME), and the two are identical, screen
	will output the same attribute-off sequence twice, each time you turn
	off, for example, reverse video.  If all three were defined & identical
	there was no problem.

    o	I tweeked the patch that Barton Schaefer sent out a few weeks back
	to fix the problems with opening/closing /dev/tty at the wrong times,
	in properly handling read errors and in supporting Sequent systems pty
	naming scheme.  What I couldn't understand was why he thought that
	ProcessInput() could return a negative value.  If I missed something
	here, please let me know.

So, if you apply this file to the original distribution of screen version 2,
everything will slip right into place.  If you apply it to a post-Schaefer
version of screen, you'll get about 3 rejected hunks, and a few succeeding
hunks that duplicate what was already installed.  The easiest thing to do would
be to use patch to un-install the Schaefer patch before installing this one.

Also, take a look at what I did to the Scroll{Up/Down}Map() calls and see what
you think.  They were written to be more efficient for multi-line scrolls.  In
looking at them the other day, I think they might actually be LESS efficient
for single-line scrolls, which are in the definite majority.  If so, it would
be really easy to go back to the original code.

Here's the rest of the changes (mentioned previously):

Bugfixes:
---------
    o	If MakeWindow() fails, there are cases where the opened PTY is not
	closed, nor is partially allocated memory freed.  In fact, I found
	that the "tabs" array is never freed at any point, even when you
	delete a window.  I've reordered allocation in MakeWindow and call
	a modified FreeWindow from more places in MakeWindow to fix this.

    o	Whenever a background window turns the keypad or insert mode on/off,
	screen incorrectly toggles the internal state of keypad or insert
	even though the physical mode of these items has not changed.

    o	When detaching or suspending screen, the keypad and insert mode
	need to be turned off and stdout flushed.  As it works now, screen
	might leave these on and will expect them to still be on when
	restarted.

    o	The Goto() call following the ClearScreen() call in the reset
	terminal code (Esc-c) is superfluous, since the cursor is already
	homed by the termcap string CL.  In fact, on some terminals, an
	optimized cursor move from the Goto() could leave the cursor in the
	wrong place.

    o	There's a few spots where curr->bot should be referrenced for the last
	line in the scrolling region, not rows-1 for the last screen line.

    o	I fixed auto-margin support by advertising `am' in the termcap if your
	terminal is such a terminal and then correctly emulating it.  This
	allows screen to display that last character of the last line in
	normal circumstances.  The only time it doesn't display it is when
	you switch screen into nowrap mode on an `am' terminal.

    o	As Paul Lew already noted, changing the default escape key with the
	escape command in .screenrc does not set the default escape-escape
	action.  However, the correct solution is NOT to re-order the call
	to InitKeytab(), since it could possibly override "bind" commands
	made in the .screenrc.  The correct solution is to add the line:
	    ktab[Esc].type = KEY_OTHER;
	into the processing of the escape command.

    o	Goto() erroneously forced an x,y cursor move when going to the first
	or last line of the scrolling region or when moving around outside
	the scrolling region.  It should only do this when going from inside
	to outside the scrolling region.

    o	RewriteCost() erroneously thinks that rewriting UP TO rows-1 is
	"EXPENSIVE".

    o	The DeleteChar() & InsertChar() code simply return if the emulator
	is in the "pseudo-last column" of the line (the spot after writing
	a character to the last column of a line).  It should remove the
	last character of the line.

Added features:
---------------
    o	Made flow control selectable on a per-console basis.  This lets you
	run shells with flow control, and editors (such as emacs) without
	and switch back and forth.

    o	Added flow-toggle mode that turns flow control on/off for the current
	console when the application keypad turns off/on (respectivly).

    o	Added the -f/ command line option to select the flow-toggle mode from
	the command line.

    o	Added keystroke commands and default bindings to:
	    toggle flow control on/off (C-A f, C-A C-F)
	    toggle flow-toggle on/off (C-A /)
	    toggle wrap on/off (C-A r, C-A C-R)
	    clear the screen (C-A C)
	    reset the virtual terminal (C-A Z)

    o	Added .screenrc commands to:
	    set default flow mode (flow on|off|toggle)
	    set default wrap mode (wrap on|off)

    o	I put all the windows in a most-recently-used linked list so that
	the "other" window we switch to (with C-A C-A) is always the most
	recently accessed window (besides the current window), no matter
	how many windows have been deleted.

    o	Added left margin ^H line-wrap when in wrap mode.  This kinda rounds
	out the "wrap when a second character is written into the right margin"
	feature of screen, and lets simple-minded applications (like csh)
	edit a wrapped command line.

    o	Added interrupt option (-i) which will immediately terminate the
	output when ^C is pressed.  Currently, screen might scroll another
	8 lines or more before stopping.  The only trade-off, is that the
	virtual screen memory contains the extra "8" lines of output, not
	the abbreviated version.  You won't notice that fact too often,
	however.

Optimizations:
--------------
    o	Removed the GotArg array in ansi.c.  It was completely redundant with
	a parameter value of 0.

    o	Made clear-to-eol work on non-LP terminals w/o CE but with DC.

    o	Correctly set last_x & last_y on exit of DisplayLine so that the
	Goto() kludge that forced an x,y cursor move isn't needed.

    o	Bind now requires the \ in front of an octal number.  This lets you
	bind the numeric keys without resorting to octal, and also lets the
	bind command use the same translate code as the -e option.

    o	I redid the insert code to selectivly choose between IC and IM if
	both are specified for a terminal.

    o	Made large arrays malloc'ed.

    o	Optimized scrolling of interal character maps and ClearScreen.

-----------------------------------Cut Here-----------------------------------
*** orig/ansi.c	Wed Feb  8 20:18:46 1989
--- ./ansi.c	Tue Feb 28 17:38:57 1989
***************
*** 7,13 ****
   * software, alterations are clearly marked as such, and this notice is
   * not modified.
   */
  
! char AnsiVersion[] = "ansi 2.0a 19-Oct-88";
  
  #include <stdio.h>
--- 7,15 ----
   * software, alterations are clearly marked as such, and this notice is
   * not modified.
+  *
+  * Modifed by Wayne Davison (...amdhal!drivax!davison)
   */
  
! char AnsiVersion[] = "ansi 2.0wd 28-Feb-89";
  
  #include <stdio.h>
***************
*** 47,53 ****
  int rows, cols;
  int status;
! int flowctl;
  char Term[] = "TERM=screen";
! char Termcap[1024];
  char *blank;
  char PC;
--- 49,55 ----
  int rows, cols;
  int status;
! int flowctl, wrap = 1;
  char Term[] = "TERM=screen";
! char *Termcap;
  char *blank;
  char PC;
***************
*** 55,60 ****
  time_t TimeDisplayed;
  
! static char tbuf[1024], tentry[1024];
! static char *tp = tentry;
  static char *TI, *TE, *BL, *VB, *BC, *CR, *NL, *CL, *IS, *CM;
  static char *US, *UE, *SO, *SE, *CE, *CD, *DO, *SR, *SF, *AL;
--- 57,62 ----
  time_t TimeDisplayed;
  
! static char *tbuf, *tentry;
! static char *tp;
  static char *TI, *TE, *BL, *VB, *BC, *CR, *NL, *CL, *IS, *CM;
  static char *US, *UE, *SO, *SE, *CE, *CD, *DO, *SR, *SF, *AL;
***************
*** 62,66 ****
  static char *MB, *MD, *MH, *MR, *ME, *PO, *PF;
  static char *CDC, *CDL, *CAL;
! static AM;
  static char GlobalAttr, TmpAttr, GlobalCharset, TmpCharset;
  static char *OldImage, *OldAttr, *OldFont;
--- 64,68 ----
  static char *MB, *MD, *MH, *MR, *ME, *PO, *PF;
  static char *CDC, *CDL, *CAL;
! static AM, LP;
  static char GlobalAttr, TmpAttr, GlobalCharset, TmpCharset;
  static char *OldImage, *OldAttr, *OldFont;
***************
*** 75,78 ****
--- 77,81 ----
  static insert;
  static keypad;
+ static flow;
  
  static char *KeyCaps[] = {
***************
*** 91,94 ****
--- 94,102 ----
      register char *s;
  
+     Termcap = malloc (1024);
+     tbuf = malloc (1024);
+     tp = tentry = malloc (1024);
+     if (!(Termcap && tbuf && tentry))
+ 	Msg (0, "Out of memory.");
      if ((s = getenv ("TERM")) == 0)
  	Msg (0, "No TERM in environment.");
***************
*** 113,120 ****
      if (s = tgetstr ("ps", &tp))
  	PC = s[0];
!     flowctl = !tgetflag ("NF");
      AM = tgetflag ("am");
!     if (tgetflag ("LP"))
! 	AM = 0;
      TI = tgetstr ("ti", &tp);
      TE = tgetstr ("te", &tp);
--- 121,139 ----
      if (s = tgetstr ("ps", &tp))
  	PC = s[0];
!     switch (flowctl) {
!     case 0:
! 	flow = !tgetflag ("NF");
! 	flowctl = flow+1;
! 	break;
!     case 1:
! 	flow = 0;
! 	break;
!     case 2:
!     case 3:
! 	flow = 1;
! 	break;
!     }
      AM = tgetflag ("am");
!     LP = !AM || tgetflag ("LP");
      TI = tgetstr ("ti", &tp);
      TE = tgetstr ("te", &tp);
***************
*** 148,155 ****
  	 * Anyway, we should at least look whether ME and SE/UE are equal:
  	 */
! 	if (SE && UE && ME && (strcmp (SE, UE) == 0 || strcmp (ME, UE) == 0))
  	    UE = 0;
! 	if (SE && ME && strcmp (SE, ME) == 0)
! 	    SE = 0;
      }
      CE = tgetstr ("ce", &tp);
--- 167,174 ----
  	 * Anyway, we should at least look whether ME and SE/UE are equal:
  	 */
! 	if (UE && (SE && strcmp (SE, UE) == 0) || (ME && strcmp (ME, UE) == 0))
  	    UE = 0;
! 	if (ME && (SE && strcmp (SE, ME) == 0))
! 	    ME = 0;
      }
      CE = tgetstr ("ce", &tp);
***************
*** 208,211 ****
--- 227,234 ----
  
  FinitTerm () {
+     display = 1;
+     flow = 1;
+     InsertMode (0);
+     KeypadMode (0);
      PutStr (TE);
      PutStr (IS);
***************
*** 230,233 ****
--- 253,258 ----
      sprintf (buf, "li#%d:co#%d:", rows, cols);
      AddCap (buf);
+     if (AM)
+ 	AddCap ("am:");
      if (VB)
  	AddCap ("vb=\\E[?5h\\E[?5l:");
***************
*** 323,328 ****
      if (CS)
  	PutStr (tgoto (CS, curr->bot, curr->top));
-     Redisplay ();
      KeypadMode (curr->keypad);
  }
  
--- 348,354 ----
      if (CS)
  	PutStr (tgoto (CS, curr->bot, curr->top));
      KeypadMode (curr->keypad);
+     FlowMode ();
+     Redisplay ();
  }
  
***************
*** 333,337 ****
      for (i = 8; i < cols; i += 8)
  	p->tabs[i] = 1;
!     p->wrap = 1;
      p->origin = 0;
      p->insert = 0;
--- 359,363 ----
      for (i = 8; i < cols; i += 8)
  	p->tabs[i] = 1;
!     p->wrap = wrap;
      p->origin = 0;
      p->insert = 0;
***************
*** 440,444 ****
  		intermediate = 0;
  		bzero ((char *)curr->args, MAXARGS * sizeof (int));
- 		bzero (curr->GotArg, MAXARGS);
  		curr->state = CSI;
  		break;
--- 466,469 ----
***************
*** 472,476 ****
  		    curr->args[curr->NumArgs] =
                          10 * curr->args[curr->NumArgs] + c - '0';
- 		    curr->GotArg[curr->NumArgs] = 1;
  		}
  		break;
--- 497,500 ----
***************
*** 493,496 ****
--- 517,521 ----
  	    }
  	    break;
+ 	case LIT:
  	default:
  	    if (!Special (c)) {
***************
*** 514,536 ****
  		    } else if (curr->x == cols-1) {
  			SetChar (c);
! 			if (!(AM && curr->y == curr->bot)) {
  			    if (display)
  				putchar (c);
! 			    Goto (-1, -1, curr->y, curr->x);
! 			}
! 			curr->x++;
! 		    } else {
! 			if (curr->wrap) {
! 			    Return ();
! 			    LineFeed ();
! 			    if (curr->insert) {
! 				InsertAChar (c);
  			    } else {
! 				if (display)
! 				    putchar (c);
! 				SetChar (c);
  			    }
! 			    curr->x = 1;
! 			} else curr->x = cols;
  		    }
  		    if (curr->ss) {
--- 539,571 ----
  		    } else if (curr->x == cols-1) {
  			SetChar (c);
! 			if (curr->wrap) {
  			    if (display)
  				putchar (c);
! 			    if (AM) {
! 				curr->x = 0;	/* terminal auto-wrapped */
! 				if (!LP || curr->y != curr->bot)
! 				    LineFeed (0);
  			    } else {
! 				curr->x++;
  			    }
! 			} else {
! 			    if (display && (LP || curr->y != curr->bot)) {
! 				putchar (c);
! 				if (AM)
! 				    Goto (curr->y+(curr->y!=curr->bot), 0,
! 					  curr->y, curr->x);
! 			    }
! 			}
! 		    } else {
! 			Return ();
! 			LineFeed (1);
! 			if (curr->insert) {
! 			    InsertAChar (c);
! 			} else {
! 			    if (display)
! 				putchar (c);
! 			    SetChar (c);
! 			}
! 			curr->x = 1;
  		    }
  		    if (curr->ss) {
***************
*** 554,558 ****
  	Return (); return 1;
      case '\n':
! 	LineFeed (); return 1;
      case '\007':
  	PutStr (BL);
--- 589,593 ----
  	Return (); return 1;
      case '\n':
! 	LineFeed (1); return 1;
      case '\007':
  	PutStr (BL);
***************
*** 576,583 ****
  	case 'E':
  	    Return ();
! 	    LineFeed ();
  	    break;
  	case 'D':
! 	    LineFeed (); 
  	    break;
  	case 'M':
--- 611,618 ----
  	case 'E':
  	    Return ();
! 	    LineFeed (1);
  	    break;
  	case 'D':
! 	    LineFeed (1); 
  	    break;
  	case 'M':
***************
*** 595,599 ****
  	case 'c':
  	    ClearScreen ();
- 	    Goto (curr->y, curr->x, 0, 0);
  	    NewRendition (GlobalAttr, 0);
  	    SetRendition (0);
--- 630,633 ----
***************
*** 600,607 ****
  	    NewCharset (GlobalCharset, ASCII);
  	    GlobalCharset = ASCII;
! 	    if (curr->insert)
! 		InsertMode (0);
! 	    if (curr->keypad)
! 		KeypadMode (0);
  	    if (CS)
  		PutStr (tgoto (CS, rows-1, 0));
--- 634,639 ----
  	    NewCharset (GlobalCharset, ASCII);
  	    GlobalCharset = ASCII;
! 	    InsertMode (0);
! 	    KeypadMode (0);
  	    if (CS)
  		PutStr (tgoto (CS, rows-1, 0));
***************
*** 611,614 ****
--- 643,650 ----
  	    KeypadMode (1);
  	    curr->keypad = 1;
+ 	    if (curr->toggle) {
+ 		curr->flow = 0;
+ 		FlowMode ();
+ 	    }
  	    break;
  	case '>':
***************
*** 615,618 ****
--- 651,658 ----
  	    KeypadMode (0);
  	    curr->keypad = 0;
+ 	    if (curr->toggle) {
+ 		curr->flow = 1;
+ 		FlowMode ();
+ 	    }
  	    break;
  	case 'n':   /* LS2 */
***************
*** 657,663 ****
      if (curr->NumArgs >= MAXARGS)
  	curr->NumArgs = MAXARGS;
-     for (i = 0; i < curr->NumArgs; ++i)
- 	if (curr->args[i] == 0)
- 	    curr->GotArg[i] = 0;
      switch (intermediate) {
      case 0:
--- 697,700 ----
***************
*** 664,673 ****
  	switch (c) {
  	case 'H': case 'f':
- 	    if (!curr->GotArg[0]) a1 = 1;
- 	    if (!curr->GotArg[1]) a2 = 1;
- 	    if (curr->origin)
- 		a1 += curr->top;
  	    if (a1 < 1)
  		a1 = 1;
  	    if (a1 > rows)
  		a1 = rows;
--- 701,708 ----
  	switch (c) {
  	case 'H': case 'f':
  	    if (a1 < 1)
  		a1 = 1;
+ 	    if (curr->origin)
+ 		a1 += curr->top;
  	    if (a1 > rows)
  		a1 = rows;
***************
*** 676,681 ****
  	    if (a2 > cols)
  		a2 = cols;
! 	    a1--; a2--;
! 	    Goto (curr->y, curr->x, a1, a2);
  	    curr->y = a1;
  	    curr->x = a2;
--- 711,715 ----
  	    if (a2 > cols)
  		a2 = cols;
! 	    Goto (curr->y, curr->x, --a1, --a2);
  	    curr->y = a1;
  	    curr->x = a2;
***************
*** 682,686 ****
  	    break;
  	case 'J':
! 	    if (!curr->GotArg[0] || a1 < 0 || a1 > 2)
  		a1 = 0;
  	    switch (a1) {
--- 716,720 ----
  	    break;
  	case 'J':
! 	    if (a1 < 0 || a1 > 2)
  		a1 = 0;
  	    switch (a1) {
***************
*** 696,700 ****
  	    break;
  	case 'K':
! 	    if (!curr->GotArg[0] || a1 < 0 || a1 > 2)
  		a1 %= 3;
  	    switch (a1) {
--- 730,734 ----
  	    break;
  	case 'K':
! 	    if (a1 < 0 || a1 > 2)
  		a1 %= 3;
  	    switch (a1) {
***************
*** 708,721 ****
  	    break;
  	case 'A':
! 	    CursorUp (curr->GotArg[0] ? a1 : 1);
  	    break;
  	case 'B':
! 	    CursorDown (curr->GotArg[0] ? a1 : 1);
  	    break;
  	case 'C':
! 	    CursorRight (curr->GotArg[0] ? a1 : 1);
  	    break;
  	case 'D':
! 	    CursorLeft (curr->GotArg[0] ? a1 : 1);
  	    break;
  	case 'm':
--- 742,755 ----
  	    break;
  	case 'A':
! 	    CursorUp (a1 ? a1 : 1);
  	    break;
  	case 'B':
! 	    CursorDown (a1 ? a1 : 1);
  	    break;
  	case 'C':
! 	    CursorRight (a1 ? a1 : 1);
  	    break;
  	case 'D':
! 	    CursorLeft (a1 ? a1 : 1);
  	    break;
  	case 'm':
***************
*** 723,727 ****
  	    break;
  	case 'g':
! 	    if (!curr->GotArg[0] || a1 == 0)
  		curr->tabs[curr->x] = 0;
  	    else if (a1 == 3)
--- 757,761 ----
  	    break;
  	case 'g':
! 	    if (a1 == 0)
  		curr->tabs[curr->x] = 0;
  	    else if (a1 == 3)
***************
*** 731,736 ****
  	    if (!CS)
  		break;
! 	    if (!curr->GotArg[0]) a1 = 1;
! 	    if (!curr->GotArg[1]) a2 = rows;
  	    if (a1 < 1 || a2 > rows || a1 >= a2)
  		break;
--- 765,770 ----
  	    if (!CS)
  		break;
! 	    if (!a1) a1 = 1;
! 	    if (!a2) a2 = rows;
  	    if (a1 < 1 || a2 > rows || a1 >= a2)
  		break;
***************
*** 748,752 ****
  	    break;
  	case 'I':
! 	    if (!curr->GotArg[0]) a1 = 1;
  	    while (a1--)
  		ForwardTab ();
--- 782,786 ----
  	    break;
  	case 'I':
! 	    if (!a1) a1 = 1;
  	    while (a1--)
  		ForwardTab ();
***************
*** 753,757 ****
  	    break;
  	case 'Z':
! 	    if (!curr->GotArg[0]) a1 = 1;
  	    while (a1--)
  		BackwardTab ();
--- 787,791 ----
  	    break;
  	case 'Z':
! 	    if (!a1) a1 = 1;
  	    while (a1--)
  		BackwardTab ();
***************
*** 758,771 ****
  	    break;
  	case 'L':
! 	    InsertLine (curr->GotArg[0] ? a1 : 1);
  	    break;
  	case 'M':
! 	    DeleteLine (curr->GotArg[0] ? a1 : 1);
  	    break;
  	case 'P':
! 	    DeleteChar (curr->GotArg[0] ? a1 : 1);
  	    break;
  	case '@':
! 	    InsertChar (curr->GotArg[0] ? a1 : 1);
  	    break;
  	case 'h':
--- 792,805 ----
  	    break;
  	case 'L':
! 	    InsertLine (a1 ? a1 : 1);
  	    break;
  	case 'M':
! 	    DeleteLine (a1 ? a1 : 1);
  	    break;
  	case 'P':
! 	    DeleteChar (a1 ? a1 : 1);
  	    break;
  	case '@':
! 	    InsertChar (a1 ? a1 : 1);
  	    break;
  	case 'h':
***************
*** 776,780 ****
  	    break;
  	case 'i':
! 	    if (PO && curr->GotArg[0] && a1 == 5) {
  		curr->stringp = curr->string;
  		curr->state = PRIN;
--- 810,814 ----
  	    break;
  	case 'i':
! 	    if (PO && a1 == 5) {
  		curr->stringp = curr->string;
  		curr->state = PRIN;
***************
*** 786,791 ****
  	if (c != 'h' && c != 'l')
  	    break;
- 	if (!curr->GotArg[0])
- 	    break;
  	i = (c == 'h');
  	if (a1 == 5) {
--- 820,823 ----
***************
*** 870,879 ****
   */
  static InsertMode (on) {
!     if (on) {
! 	if (!insert)
  	    PutStr (IM);
!     } else if (insert)
! 	PutStr (EI);
!     insert = on;
  }
  
--- 902,912 ----
   */
  static InsertMode (on) {
!     if (display && on != insert && IM) {
! 	insert = on;
! 	if (insert)
  	    PutStr (IM);
! 	else
! 	    PutStr (EI);
!     }
  }
  
***************
*** 881,890 ****
   */
  static KeypadMode (on) {
!     if (on) {
! 	if (!keypad)
  	    PutStr (KS);
!     } else if (keypad)
! 	PutStr (KE);
!     keypad = on;
  }
  
--- 914,936 ----
   */
  static KeypadMode (on) {
!     if (display && keypad != on) {
! 	keypad = on;
! 	if (keypad)
  	    PutStr (KS);
! 	else
! 	    PutStr (KE);
!     }
! }
! 
! static FlowMode () {
!     if (display && flow != curr->flow) {
! 	flow = curr->flow;
! 	SetFlow (flow);
!     }
! }
! 
! ToggleFlow (wp) struct win *wp; {
!     flow = wp->flow = !wp->flow;
!     SetFlow (flow);
  }
  
***************
*** 970,977 ****
      if (!display)
  	return;
!     if (x1 == cols || x2 == cols) {
! 	if (x2 == cols) --x2;
! 	goto DoCM;
!     }
      dx = x2 - x1;
      dy = y2 - y1;
--- 1016,1023 ----
      if (!display)
  	return;
!     if (x1 == cols)
! 	--x1;
!     if (x2 == cols)
! 	--x2;
      dx = x2 - x1;
      dy = y2 - y1;
***************
*** 978,982 ****
      if (dy == 0 && dx == 0)
  	return;
!     if (y1 == -1 || x1 == -1 || y2 >= curr->bot || y2 <= curr->top) {
  DoCM:
  	PutStr (tgoto (CM, x2, y2));
--- 1024,1030 ----
      if (dy == 0 && dx == 0)
  	return;
!     if (y1 == -1 || x1 == -1
!      || (y2 > curr->bot && y1 <= curr->bot)
!      || (y2 < curr->top && y1 >= curr->top)) {
  DoCM:
  	PutStr (tgoto (CM, x2, y2));
***************
*** 1024,1033 ****
  	    }
  	    if (x1 < x2) {
! 		if (curr->insert)
  		    InsertMode (0);
  		for (s = curr->image[y1]+x1; x1 < x2; x1++, s++)
  		    putchar (*s);
! 		if (curr->insert)
! 		    InsertMode (1);
  	    }
  	}
--- 1072,1080 ----
  	    }
  	    if (x1 < x2) {
! 		if (insert)
  		    InsertMode (0);
  		for (s = curr->image[y1]+x1; x1 < x2; x1++, s++)
  		    putchar (*s);
! 		InsertMode (curr->insert);
  	    }
  	}
***************
*** 1046,1055 ****
      register char *p = curr->attr[y]+x1, *f = curr->font[y]+x1;
  
-     if (AM && y == rows-1 && x2 == cols-1)
- 	return EXPENSIVE;
      cost = dx = x2 - x1;
      if (dx == 0)
  	return 0;
!     if (curr->insert)
  	cost += EIcost + IMcost;
      do {
--- 1093,1100 ----
      register char *p = curr->attr[y]+x1, *f = curr->font[y]+x1;
  
      cost = dx = x2 - x1;
      if (dx == 0)
  	return 0;
!     if (insert)
  	cost += EIcost + IMcost;
      do {
***************
*** 1069,1072 ****
--- 1114,1121 ----
  	}
  	curr->x--;
+     } else if (curr->wrap && curr->y > curr->top) {
+ 	curr->x = cols-1;
+ 	curr->y--;
+ 	Goto (curr->y+1, 0, curr->y, curr->x);
      }
  }
***************
*** 1079,1091 ****
  }
  
! static LineFeed () {
      if (curr->y == curr->bot) {
! 	ScrollUpMap (curr->image);
! 	ScrollUpMap (curr->attr);
! 	ScrollUpMap (curr->font);
      } else if (curr->y < rows-1) {
  	curr->y++;
      }
!     PutStr (NL);
  }
  
--- 1128,1139 ----
  }
  
! static LineFeed (output) {
      if (curr->y == curr->bot) {
! 	ScrollUpMap (1);
      } else if (curr->y < rows-1) {
  	curr->y++;
      }
!     if (output)
! 	PutStr (NL);
  }
  
***************
*** 1092,1098 ****
  static ReverseLineFeed () {
      if (curr->y == curr->top) {
! 	ScrollDownMap (curr->image);
! 	ScrollDownMap (curr->attr);
! 	ScrollDownMap (curr->font);
  	if (SR) {
  	    PutStr (SR);
--- 1140,1144 ----
  static ReverseLineFeed () {
      if (curr->y == curr->top) {
! 	ScrollDownMap (1);
  	if (SR) {
  	    PutStr (SR);
***************
*** 1122,1131 ****
  	return;
      if (IC || IM) {
! 	if (!curr->insert)
! 	    InsertMode (1);
! 	PutStr (IC);
  	putchar (c);
! 	if (!curr->insert)
! 	    InsertMode (0);
      } else {
  	RedisplayLine (OldImage, OldAttr, OldFont, y, x, cols-1);
--- 1168,1178 ----
  	return;
      if (IC || IM) {
! 	if (!insert)
! 	    if (IC)
! 		PutStr (IC);
! 	    else
! 		InsertMode (1);
  	putchar (c);
! 	InsertMode (curr->insert);
      } else {
  	RedisplayLine (OldImage, OldAttr, OldFont, y, x, cols-1);
***************
*** 1139,1143 ****
  
      if (x == cols)
! 	return;
      bcopy (curr->image[y], OldImage, cols);
      bcopy (curr->attr[y], OldAttr, cols);
--- 1186,1190 ----
  
      if (x == cols)
! 	--x;
      bcopy (curr->image[y], OldImage, cols);
      bcopy (curr->attr[y], OldAttr, cols);
***************
*** 1151,1164 ****
      if (!display)
  	return;
!     if (IC || IM) {
! 	if (!curr->insert)
! 	    InsertMode (1);
! 	for (i = n; i; i--) {
! 	    PutStr (IC);
  	    putchar (' ');
! 	}
! 	if (!curr->insert)
! 	    InsertMode (0);
  	Goto (y, x+n, y, x);
      } else {
  	RedisplayLine (OldImage, OldAttr, OldFont, y, x, cols-1);
--- 1198,1210 ----
      if (!display)
  	return;
!     if (insert || (IM && (n != 1 || !IC))) {
! 	InsertMode (1);
! 	for (i = n; i; i--)
  	    putchar (' ');
! 	InsertMode (curr->insert);
  	Goto (y, x+n, y, x);
+     } else if (IC) {
+ 	for (i = n; i; i--)
+ 	    PutStr (IC);
      } else {
  	RedisplayLine (OldImage, OldAttr, OldFont, y, x, cols-1);
***************
*** 1171,1175 ****
  
      if (x == cols)
! 	return;
      bcopy (curr->image[y], OldImage, cols);
      bcopy (curr->attr[y], OldAttr, cols);
--- 1217,1221 ----
  
      if (x == cols)
! 	--x;
      bcopy (curr->image[y], OldImage, cols);
      bcopy (curr->attr[y], OldAttr, cols);
***************
*** 1200,1208 ****
  	n = curr->bot-curr->y+1;
      curr->top = curr->y;
!     for (i = n; i; i--) {
! 	ScrollUpMap (curr->image);
! 	ScrollUpMap (curr->attr);
! 	ScrollUpMap (curr->font);
!     }
      if (DL || CDL) {
  	Goto (curr->y, curr->x, curr->y, 0);
--- 1246,1250 ----
  	n = curr->bot-curr->y+1;
      curr->top = curr->y;
!     ScrollUpMap (n);
      if (DL || CDL) {
  	Goto (curr->y, curr->x, curr->y, 0);
***************
*** 1231,1239 ****
  	n = curr->bot-curr->y+1;
      curr->top = curr->y;
!     for (i = n; i; i--) {
! 	ScrollDownMap (curr->image);
! 	ScrollDownMap (curr->attr);
! 	ScrollDownMap (curr->font);
!     }
      if (AL || CAL) {
  	Goto (curr->y, curr->x, curr->y, 0);
--- 1273,1277 ----
  	n = curr->bot-curr->y+1;
      curr->top = curr->y;
!     ScrollDownMap (n);
      if (AL || CAL) {
  	Goto (curr->y, curr->x, curr->y, 0);
***************
*** 1256,1281 ****
  }
  
! static ScrollUpMap (pp) char **pp; {
!     register char *tmp = pp[curr->top];
  
!     bcopy ((char *)(pp+curr->top+1), (char *)(pp+curr->top),
! 	(curr->bot-curr->top) * sizeof (char *));
!     if (pp == curr->image)
! 	bclear (tmp, cols);
!     else
! 	bzero (tmp, cols);
!     pp[curr->bot] = tmp;
! }
! 
! static ScrollDownMap (pp) char **pp; {
!     register char *tmp = pp[curr->bot];
! 
!     bcopy ((char *)(pp+curr->top), (char *)(pp+curr->top+1),
! 	(curr->bot-curr->top) * sizeof (char *));
!     if (pp == curr->image)
! 	bclear (tmp, cols);
!     else
! 	bzero (tmp, cols);
!     pp[curr->top] = tmp;
  }
  
--- 1294,1348 ----
  }
  
! static ScrollUpMap (n) {
!     char tmp[128*sizeof (char *)];
!     register i, cnt1, cnt2;
!     register char **ppi, **ppa, **ppf;
  
!     i = curr->top+n;
!     cnt1 = n * sizeof (char *);
!     cnt2 = (curr->bot - i + 1) * sizeof (char *);
!     ppi = curr->image+i;
!     ppa = curr->attr +i;
!     ppf = curr->font +i;
!     for (i = n; i; --i) {
! 	bclear (*--ppi, cols);
! 	bzero (*--ppa, cols);
! 	bzero (*--ppf, cols);
!     }
!     Scroll ((char *)ppi, cnt1, cnt2, tmp);
!     Scroll ((char *)ppa, cnt1, cnt2, tmp);
!     Scroll ((char *)ppf, cnt1, cnt2, tmp);
! }
! 
! static ScrollDownMap (n) {
!     char tmp[128*sizeof (char *)];
!     register i, cnt1, cnt2;
!     register char **ppi, **ppa, **ppf;
! 
!     i = curr->top;
!     cnt1 = (curr->bot - i - n + 1) * sizeof (char *);
!     cnt2 = n * sizeof (char *);
!     Scroll ((char *)(ppi = curr->image+i), cnt1, cnt2, tmp);
!     Scroll ((char *)(ppa = curr->attr +i), cnt1, cnt2, tmp);
!     Scroll ((char *)(ppf = curr->font +i), cnt1, cnt2, tmp);
!     for (i = n; i; --i) {
! 	bclear (*ppi++, cols);
! 	bzero (*ppa++, cols);
! 	bzero (*ppf++, cols);
!     }
! }
! 
! Scroll (cp, cnt1, cnt2, tmp) char *cp, *tmp; int cnt1, cnt2; {
!     if (!cnt1 || !cnt2)
! 	return;
!     if (cnt1 <= cnt2) {
! 	bcopy (cp, tmp, cnt1);
! 	bcopy (cp+cnt1, cp, cnt2);
! 	bcopy (tmp, cp+cnt2, cnt1);
!     } else {
! 	bcopy (cp+cnt1, tmp, cnt2);
! 	bcopy (cp, cp+cnt2, cnt1);
! 	bcopy (tmp, cp, cnt2);
!     }
  }
  
***************
*** 1304,1313 ****
  static ClearScreen () {
      register i;
  
      PutStr (CL);
      for (i = 0; i < rows; ++i) {
! 	bclear (curr->image[i], cols);
! 	bzero (curr->attr[i], cols);
! 	bzero (curr->font[i], cols);
      }
  }
--- 1371,1381 ----
  static ClearScreen () {
      register i;
+     register char **ppi = curr->image, **ppa = curr->attr, **ppf = curr->font;
  
      PutStr (CL);
      for (i = 0; i < rows; ++i) {
! 	bclear (*ppi++, cols);
! 	bzero (*ppa++, cols);
! 	bzero (*ppf++, cols);
      }
  }
***************
*** 1369,1387 ****
  	bzero (curr->font[y]+x1, n);
  	if (displ && display) {
! 	    if (x2 == cols-1 && CE) {
! 		Goto (curr->y, curr->x, y, x1);
! 		curr->y = y; curr->x = x1;
! 		PutStr (CE);
! 		return;
  	    }
- 	    if (y == rows-1 && AM)
- 		--n;
  	    if (n == 0)
  		return;
  	    SaveAttr (0);
- 	    Goto (curr->y, curr->x, y, x1);
  	    for (i = n; i > 0; i--)
  		putchar (' ');
! 	    curr->y = y; curr->x = x1 + n;
  	    RestoreAttr (0);
  	}
--- 1437,1462 ----
  	bzero (curr->font[y]+x1, n);
  	if (displ && display) {
! 	    Goto (curr->y, curr->x, y, x1);
! 	    curr->y = y; curr->x = x1;
! 	    if (x2 == cols-1) {
! 		if (CE) {
! 		    PutStr (CE);
! 		    return;
! 		} else {
! 		    if (!LP && y == curr->bot) {
! 			if (DC)
! 			    PutStr (DC);
! 			else if (CDC)
! 			    CPutStr (CDC, 1);
! 			--n;
! 		    }
! 		}
  	    }
  	    if (n == 0)
  		return;
  	    SaveAttr (0);
  	    for (i = n; i > 0; i--)
  		putchar (' ');
! 	    curr->x += n;
  	    RestoreAttr (0);
  	}
***************
*** 1519,1524 ****
      NewRendition (oldattr, GlobalAttr);
      NewCharset (ASCII, GlobalCharset);
!     if (curr->insert)
! 	InsertMode (1);
  }
  
--- 1594,1598 ----
      NewRendition (oldattr, GlobalAttr);
      NewCharset (ASCII, GlobalCharset);
!     InsertMode (curr->insert);
  }
  
***************
*** 1552,1557 ****
  	DisplayLine (blank, null, null, curr->image[i], curr->attr[i],
  	    curr->font[i], i, 0, cols-1);
!     if (curr->insert)
! 	InsertMode (1);
      NewRendition (TmpAttr, GlobalAttr);
      NewCharset (TmpCharset, GlobalCharset);
--- 1626,1630 ----
  	DisplayLine (blank, null, null, curr->image[i], curr->attr[i],
  	    curr->font[i], i, 0, cols-1);
!     InsertMode (curr->insert);
      NewRendition (TmpAttr, GlobalAttr);
      NewCharset (TmpCharset, GlobalCharset);
***************
*** 1563,1570 ****
      register i, x, a, f;
  
!     if (to == cols)
  	--to;
-     if (AM && y == rows-1 && to == cols-1)
- 	--to;
      a = TmpAttr;
      f = TmpCharset;
--- 1636,1641 ----
      register i, x, a, f;
  
!     if (!LP && y == curr->bot && to == cols-1)
  	--to;
      a = TmpAttr;
      f = TmpCharset;
***************
*** 1587,1595 ****
  	last_x++;
      }
  }
  
  static RedisplayLine (os, oa, of, y, from, to) char *os, *oa, *of; {
!     if (curr->insert)
! 	InsertMode (0);
      NewRendition (GlobalAttr, 0);
      TmpAttr = 0;
--- 1658,1672 ----
  	last_x++;
      }
+     if (last_x == cols) {
+ 	if (AM) {
+ 	    last_x = 0;
+ 	    if (++last_y == rows)
+ 		--last_y;
+ 	}
+     }
  }
  
  static RedisplayLine (os, oa, of, y, from, to) char *os, *oa, *of; {
!     InsertMode (0);
      NewRendition (GlobalAttr, 0);
      TmpAttr = 0;
***************
*** 1602,1607 ****
      NewRendition (TmpAttr, GlobalAttr);
      NewCharset (TmpCharset, GlobalCharset);
!     if (curr->insert)
! 	InsertMode (1);
  }
  
--- 1679,1683 ----
      NewRendition (TmpAttr, GlobalAttr);
      NewCharset (TmpCharset, GlobalCharset);
!     InsertMode (curr->insert);
  }
  
***************
*** 1615,1619 ****
      int odisplay = display;
      register char *s, *t;
!     register max = AM ? cols-1 : cols;
  
      for (s = t = msg; *s && t - msg < max; ++s)
--- 1691,1695 ----
      int odisplay = display;
      register char *s, *t;
!     register max = !LP ? cols-1 : cols;
  
      for (s = t = msg; *s && t - msg < max; ++s)
*** orig/screen.1	Mon Feb 13 16:01:04 1989
--- ./screen.1	Fri Feb 17 18:03:17 1989
***************
*** 168,178 ****
  over 1, 5, and 15 minutes (if this is available on your system),
  the cursor position of the current window in the form \*Q(colum,row)\*U
! starting with \*U(0,0)\*U, an indication if flow control
! and (for the current window)
  insert mode, origin mode, wrap mode, and keypad application
! mode are enabled or not (indicated by a '+' or '-'),
  the currently active character set (\fIG0\fP, \fIG1\fP, \fIG2\fP,
  or \fIG3\fP), and the terminal character sets that are currently
  designated as \fIG0\fP through \fIG3\fP.
  .IP "\fBC-a v\fP or \fBC-a C-v\fP"
  Display the version.
--- 168,180 ----
  over 1, 5, and 15 minutes (if this is available on your system),
  the cursor position of the current window in the form \*Q(colum,row)\*U
! starting with \*U(0,0)\*U, and an indication of the current window's:
! flow control,
  insert mode, origin mode, wrap mode, and keypad application
! mode ('+' if enabled, '-' if not),
  the currently active character set (\fIG0\fP, \fIG1\fP, \fIG2\fP,
  or \fIG3\fP), and the terminal character sets that are currently
  designated as \fIG0\fP through \fIG3\fP.
+ Also, a '/' will appear before the word "flow" if flow control
+ is set to "toggle".
  .IP "\fBC-a v\fP or \fBC-a C-v\fP"
  Display the version.
***************
*** 183,186 ****
--- 185,199 ----
  .IP "\fBC-a q\fP or \fBC-a C-q\fP"
  Send a Control-q to the program running in the window.
+ .IP "\fBC-a r\fP or \fBC-a C-r\fP"
+ Toggle the current window's line-wrap setting.
+ .IP "\fBC-a f\fP or \fBC-a C-f\fP"
+ Toggle the current window's flow-control setting.
+ .IP "\fBC-a /\fP"
+ Toggle the current window's flow-control-toggle setting.
+ .IP "\fBC-a C\fP"
+ Clear the screen.
+ .IP "\fBC-a Z\fP"
+ Reset the terminal and its internal representation to the "power-on"
+ settings.
  .IP
  .PP
***************
*** 218,221 ****
--- 231,236 ----
  Set the command character to \fIx\fP and the character generating a literal
  command character to \fIy\fP (see the \-e option above).
+ Control characters may be specified by the two character sequence, ^X, or as
+ octal (e.g. \\033).
  .PP
  .ne 3
***************
*** 243,252 ****
  .PP
  .ne 3
! .B "screen [\fIn\fP] [\fIcmds args\fP]"
  .PP
  Establish a window.
  If an optional number \fIn\fP in the range 0..9 is given, the window
  number \fIn\fP is assigned to the newly created window (or, if this
! number is already in use, the next higher number).
  Note that \fIn\fP has a value of zero for the standard shell window
  created after \*Q.screenrc\*U has been read.
--- 258,268 ----
  .PP
  .ne 3
! .B "screen [\fIopts\fP] [\fIn\fP] [\fIcmds args\fP]"
  .PP
  Establish a window.
+ The flow control options (-n, -f and -f/) may be specified for each command.
  If an optional number \fIn\fP in the range 0..9 is given, the window
  number \fIn\fP is assigned to the newly created window (or, if this
! number is already in use, the next higher available number).
  Note that \fIn\fP has a value of zero for the standard shell window
  created after \*Q.screenrc\*U has been read.
***************
*** 259,263 ****
  	# example for .screenrc:
  	screen 1
! 	screen 2 telnet foobar
  .fi
  .PP
--- 275,279 ----
  	# example for .screenrc:
  	screen 1
! 	screen -n 2 telnet foobar
  .fi
  .PP
***************
*** 264,268 ****
  .I screen
  creates a shell window (window #1), a window with a TELNET connection
! to the machine foobar (window #2), and, finally, a second shell window
  (the default window) which gets a window number of zero.
  When the initialization is completed,
--- 280,285 ----
  .I screen
  creates a shell window (window #1), a window with a TELNET connection
! to the machine foobar with no flow control (window #2), and, finally,
! a second shell window
  (the default window) which gets a window number of zero.
  When the initialization is completed,
***************
*** 289,292 ****
--- 306,330 ----
  .PP
  .ne 3
+ .B "wrap on|off"
+ .sp
+ Set the line wrap for to-be-created windows on or off.  By default,
+ line wrap is on, which,
+ for an auto-margin (`am') terminal, is the usual mode.  For non-`am'
+ terminals, we try to be the best of both worlds, and emulate a line wrap
+ if a second character write is attempted at the last position of a line.
+ As an added feature, backspace (^H) will wrap through the left margin
+ to the previous line when wrap is on.  When wrap is off, neither type
+ of terminal will wrap through the right or left margins.  The only
+ difference being that `am' terminals cannot display the last character of
+ the last line in the scroll region when wrap is off.
+ .PP
+ .ne 3
+ .B "flow on|off|toggle"
+ .sp
+ Set the default flow control mode.  Specifying "flow on" is the same
+ as the command line option, -f; "flow off" is the same as -n;
+ "flow toggle" is the same as -f/.
+ .PP
+ .ne 3
  .B "bind \fIkey\fP [\fIfunction\fP | \fIcmd args\fP]"
  .PP
***************
*** 323,326 ****
--- 361,369 ----
  	xoff	Send Control-s
  	version	Display the version
+ 	wrap	Toggle the current window's line wrap
+ 	flow	Toggle the current window's flow control
+ 	toggle	Toggle the current window's flow-ctrl toggle
+ 	clear	Clear the screen
+ 	reset	Reset the terminal to the "power-on" settings
  	select0	Switch to window #0
  	\0\0...
***************
*** 337,341 ****
  	bind ' ' windows
  	bind ^f telnet foobar
! 	bind 033 su
  .fi
  .PP
--- 380,384 ----
  	bind ' ' windows
  	bind ^f telnet foobar
! 	bind \\033 su
  .fi
  .PP
***************
*** 363,367 ****
  terminal on which
  .I screen
! has been started, flow control is turned off for the terminal.
  This enables the user to send XON and XOFF characters to the
  program running in a window (this is required by the \fIemacs\fP
--- 406,410 ----
  terminal on which
  .I screen
! has been started, the default flow control is turned off for the terminal.
  This enables the user to send XON and XOFF characters to the
  program running in a window (this is required by the \fIemacs\fP
***************
*** 368,391 ****
  editor, for instance).
  The command line options 
! .B \-n
  and
! .B \-f
! can be used to turn flow control off or on, respectively, independently
! of the `NF' capability.
! .PP
! .I
! Screen
! never writes in the last position of the screen, unless the boolean
! capability `LP' is found in the termcap entry of the terminal.
! Usually,
! .I screen
! cannot predict whether or not a particular terminal scrolls when
! a character is written in the last column of the last line;
! `LP' indicates that it is safe to write in this position.
! Note that the `LP' capability is independent of `am' (automatic
! margins); for certain terminals, such as the VT100, it is reasonable
! to set `am' as well as `LP' in the corresponding termcap entry
! (the VT100 does not move the cursor when a character is written in
! the last column of each line).
  .PP
  .I Screen
--- 411,438 ----
  editor, for instance).
  The command line options 
! .B \-n ,
! .B \-f ,
  and
! .B \-f/
! can be used to turn flow control off, on, or on-with-toggle, respectively,
! independently of the `NF' capability.  The flow-control-toggle mode will
! enable/disable flow control on the fly for the current window, based on the
! current setting of the application keypad -- when it is enabled, flow
! control is turned off and visa versa.  Also, the "screen" and "flow"
! commands in the .screenrc file can be used to manipulate the flow control
! on a window by window basis.
! .PP
! If your termcap has `am' (automatic margins) set, this will cause
! .I screen
! to assume that your terminal not only wraps automatically at the end of
! lines but scrolls when a character is placed into the last position of the
! screen.  If it does not scroll automatically, you must set the
! boolean capability `LP' in the termcap entry of the terminal.  This
! indicates that it is safe to write in the last position on the screen.
! Note that the `LP' capability is assumed if your termcap does not include
! the `am' capability. If your terminal does scroll automatically, and wrap
! mode is turned off (either by command or escape sequence), the lower right
! character on the screen will not be updated.  Normally, wrap mode is turned
! on and the entire screen is updated correctly.
  .PP
  .I Screen
***************
*** 441,445 ****
  For instance, `dl' (delete line) is only put into the TERMCAP
  variable if the terminal supports either delete line itself or
! scrolling regions.
  If
  .I screen
--- 488,493 ----
  For instance, `dl' (delete line) is only put into the TERMCAP
  variable if the terminal supports either delete line itself or
! scrolling regions, and  `am' is included only if it is in
! the original termcap.
  If
  .I screen
***************
*** 446,450 ****
  is called with the
  .B \-a
! option, \fIall\fP capabilities are put into the environment,
  even if
  .I screen
--- 494,499 ----
  is called with the
  .B \-a
! option, \fIall\fP capabilities (with a few exceptions)
! are put into the environment,
  even if
  .I screen
***************
*** 690,696 ****
  Standout mode is not cleared before newline or cursor addressing.
  .PP
! If `LP' is not set but `am' is set, the last character in the last line is never
! written, and it is not correctly re-displayed when the screen is
  scrolled up or when a character is deleted in the last line.
  .PP
  The VT100 \*Qwrap around with cursor addressing\*U bug is not compensated
--- 739,748 ----
  Standout mode is not cleared before newline or cursor addressing.
  .PP
! If `LP' is not set but `am' is set AND the window has been changed into the
! no-wrap mode, the last character in the last line of the scrolling region
! will not be updated, nor is it correctly re-displayed when the screen is
  scrolled up or when a character is deleted in the last line.
+ In normal (wrap mode) operation, this troublesome character is updated
+ correctly for both `am' and non-`am' terminals.
  .PP
  The VT100 \*Qwrap around with cursor addressing\*U bug is not compensated
-----------------------------------Cut Here-----------------------------------
 Wayne Davison                                        ...amdahl!drivax!davison

davison@drivax.DRI (Wayne Davison) (03/08/89)

Part two of the screen diffs.  See part 1 for a description.
-----------------------------------Cut Here-----------------------------------
*** orig/screen.c	Wed Feb  8 20:18:38 1989
--- ./screen.c	Tue Feb 22 18:49:21 1989
***************
*** 7,13 ****
   * software, alterations are clearly marked as such, and this notice is
   * not modified.
   */
  
! static char ScreenVersion[] = "screen 2.0a 19-Oct-88";
  
  #include <stdio.h>
--- 7,15 ----
   * software, alterations are clearly marked as such, and this notice is
   * not modified.
+  *
+  * Modifed by Wayne Davison (...amdhal!drivax!davison)
   */
  
! static char ScreenVersion[] = "screen 2.0wd 22-Feb-89";
  
  #include <stdio.h>
***************
*** 55,59 ****
  extern char AnsiVersion[];
  extern short ospeed;
! extern flowctl;
  extern errno;
  extern sys_nerr;
--- 57,61 ----
  extern char AnsiVersion[];
  extern short ospeed;
! extern flowctl, wrap;
  extern errno;
  extern sys_nerr;
***************
*** 60,65 ****
  extern char *sys_errlist[];
  extern char *index(), *rindex(), *malloc(), *getenv(), *MakeTermcap();
! extern char *getlogin(), *ttyname();
! static AttacherFinit(), Finit(), SigHup(), SigChld();
  static char *MakeBellMsg(), *Filename(), **SaveArgs(), *GetTtyName();
  
--- 62,67 ----
  extern char *sys_errlist[];
  extern char *index(), *rindex(), *malloc(), *getenv(), *MakeTermcap();
! extern char *getlogin(), *ttyname(), *ParseChar();
! static AttacherFinit(), Finit(), SigHup(), SigChld(), SigInt();
  static char *MakeBellMsg(), *Filename(), **SaveArgs(), *GetTtyName();
  
***************
*** 89,93 ****
  static char *LoginName;
  static char *BellString = "Bell in window %";
! static mflag, nflag, fflag, rflag;
  static char HostName[MAXSTR];
  static Detached;
--- 91,96 ----
  static char *LoginName;
  static char *BellString = "Bell in window %";
! static mflag, nflag, fflag, rflag, iflag;
! static intrc, startc, stopc;
  static char HostName[MAXSTR];
  static Detached;
***************
*** 128,133 ****
  } OldMode, NewMode;
  
! static struct win *curr, *other;
! static CurrNum, OtherNum;
  static struct win *wtab[MAXWIN];
  
--- 131,136 ----
  } OldMode, NewMode;
  
! static struct win *curr;
! static CurrNum, WinList = -1;
  static struct win *wtab[MAXWIN];
  
***************
*** 159,163 ****
  #define KEY_QUIT          25
  #define KEY_DETACH        26
! #define KEY_CREATE        27
  
  struct key {
--- 162,171 ----
  #define KEY_QUIT          25
  #define KEY_DETACH        26
! #define KEY_WRAP          27
! #define KEY_FLOW          28
! #define KEY_TOGGLE        29
! #define KEY_CLEAR         30
! #define KEY_RESET         31
! #define KEY_CREATE       255
  
  struct key {
***************
*** 171,174 ****
--- 179,183 ----
      "select4", "select5", "select6", "select7", "select8", "select9",
      "xon", "xoff", "info", "termcap", "quit", "detach",
+     "wrap", "flow", "toggle", "clear", "reset",
      0
  };
***************
*** 176,180 ****
  main (ac, av) char **av; {
      register n, len;
!     register struct win **pp, *p;
      char *ap;
      int s, r, w, x = 0;
--- 185,189 ----
  main (ac, av) char **av; {
      register n, len;
!     register struct win *p;
      char *ap;
      int s, r, w, x = 0;
***************
*** 200,206 ****
--- 209,223 ----
  	    case 'n':
  		nflag = 1;
+ 		flowctl = 1;
  		break;
  	    case 'f':
  		fflag = 1;
+ 		if (ap[2] != '/')
+ 		    flowctl = 2;
+ 		else
+ 		    flowctl = 3;
+ 		break;
+ 	    case 'i':
+ 		iflag = 1;
  		break;
  	    case 'r':
***************
*** 220,227 ****
  		    ap = *++av;
  		}
! 		if (strlen (ap) != 2)
  		    Msg (0, "Two characters are required with -e option.");
- 		Esc = ap[0];
- 		MetaEsc = ap[1];
  		break;
  	    default:
--- 237,242 ----
  		    ap = *++av;
  		}
! 		if (!ParseEscape (ap))
  		    Msg (0, "Two characters are required with -e option.");
  		break;
  	    default:
***************
*** 264,269 ****
      strcat (SockPath, "/");
      SockNamePtr = SockPath + strlen (SockPath);
-     if ((DevTty = open ("/dev/tty", O_RDWR|O_NDELAY)) == -1)
- 	Msg (errno, "/dev/tty");
      if (rflag) {
  	Attach (MSG_ATTACH);
--- 279,282 ----
***************
*** 273,280 ****
      if (GetSockName ()) {
  	s = MakeClientSocket (1);
! 	SendCreateMsg (s, ac, av, aflag);
  	close (s);
  	exit (0);
      }
      switch (fork ()) {
      case -1:
--- 286,295 ----
      if (GetSockName ()) {
  	s = MakeClientSocket (1);
! 	SendCreateMsg (s, ac, av, aflag, flowctl);
  	close (s);
  	exit (0);
      }
+     if ((DevTty = open ("/dev/tty", O_RDWR|O_NDELAY)) == -1)
+ 	Msg (errno, "/dev/tty");
      switch (fork ()) {
      case -1:
***************
*** 290,297 ****
      ServerSocket = s = MakeServerSocket ();
      InitTerm ();
-     if (fflag)
- 	flowctl = 1;
-     else if (nflag)
- 	flowctl = 0;
      MakeNewEnv ();
      GetTTY (0, &OldMode);
--- 305,308 ----
***************
*** 302,306 ****
  #endif
      signal (SIGHUP, SigHup);
!     signal (SIGINT, Finit);
      signal (SIGQUIT, Finit);
      signal (SIGTERM, Finit);
--- 313,317 ----
  #endif
      signal (SIGHUP, SigHup);
!     signal (SIGINT, SigInt);
      signal (SIGQUIT, Finit);
      signal (SIGTERM, Finit);
***************
*** 310,318 ****
      sprintf (rc, "%.*s/.screenrc", 245, home);
      ReadRc (rc);
!     if ((n = MakeWindow (*av, av, aflag, 0, (char *)0)) == -1) {
! 	SetTTY (0, &OldMode);
! 	FinitTerm ();
! 	Kill (AttacherPid, SIGHUP);
! 	exit (1);
      }
      SetCurrWindow (n);
--- 321,327 ----
      sprintf (rc, "%.*s/.screenrc", 245, home);
      ReadRc (rc);
!     if ((n = MakeWindow (*av, av, aflag, flowctl, 0, (char *)0)) == -1) {
! 	Finit ();
! 	/*NOTREACHED*/
      }
      SetCurrWindow (n);
***************
*** 335,346 ****
  	else
  	    r |= 1 << 0;
! 	for (pp = wtab; pp < wtab+MAXWIN; ++pp) {
! 	    if (!(p = *pp))
! 		continue;
! 	    if ((*pp)->active && status)
  		continue;
! 	    if ((*pp)->outlen > 0)
  		continue;
! 	    r |= 1 << (*pp)->ptyfd;
  	}
  	r |= 1 << s;
--- 344,354 ----
  	else
  	    r |= 1 << 0;
! 	for (n = WinList; n != -1; n = p->WinLink) {
! 	    p = wtab[n];
! 	    if (p->active && status)
  		continue;
! 	    if (p->outlen > 0)
  		continue;
! 	    r |= 1 << p->ptyfd;
  	}
  	r |= 1 << s;
***************
*** 351,358 ****
  	}
  	if (select (32, &r, &w, &x, status ? &tv : (struct timeval *)0) == -1) {
! 	    if (errno == EINTR)
  		continue;
! 	    HasWindow = 0;
! 	    Msg (errno, "select");
  	    /*NOTREACHED*/
  	}
--- 359,368 ----
  	}
  	if (select (32, &r, &w, &x, status ? &tv : (struct timeval *)0) == -1) {
! 	    if (errno == EINTR) {
! 		errno = 0;
  		continue;
! 	    }
! 	    perror ("select");
! 	    Finit ();
  	    /*NOTREACHED*/
  	}
***************
*** 376,379 ****
--- 386,393 ----
  	    if (inlen > 0)
  		inlen = ProcessInput (inbuf, inlen);
+ 	    else {
+ 		perror ("read");
+ 		Finit ();
+ 	    }
  	    if (inlen > 0)
  		continue;
***************
*** 393,399 ****
  	    continue;
  	}
! 	for (pp = wtab; pp < wtab+MAXWIN; ++pp) {
! 	    if (!(p = *pp))
! 		continue;
  	    if (p->outlen) {
  		WriteString (p, p->outbuf, p->outlen);
--- 407,412 ----
  	    continue;
  	}
! 	for (n = WinList; n != -1; n = p->WinLink) {
! 	    p = wtab[n];
  	    if (p->outlen) {
  		WriteString (p, p->outbuf, p->outlen);
***************
*** 408,412 ****
  	    if (p->bell) {
  		p->bell = 0;
! 		Msg (0, MakeBellMsg (pp-wtab));
  	    }
  	}
--- 421,425 ----
  	    if (p->bell) {
  		p->bell = 0;
! 		Msg (0, MakeBellMsg (n));
  	    }
  	}
***************
*** 432,447 ****
  }
  
  static DoWait () {
!     register pid;
!     register struct win **pp;
      union wait wstat;
  
      while ((pid = wait3 (&wstat, WNOHANG|WUNTRACED, NULL)) > 0) {
! 	for (pp = wtab; pp < wtab+MAXWIN; ++pp) {
! 	    if (*pp && pid == (*pp)->wpid) {
  		if (WIFSTOPPED (wstat)) {
! 		    (void) killpg (getpgrp ((*pp)->wpid), SIGCONT);
  		} else {
! 		    KillWindow (pp);
  		}
  	    }
--- 445,465 ----
  }
  
+ static SigInt () {
+     inlen = 0;
+     write (curr->ptyfd, "\003", 1);
+ }
+ 
  static DoWait () {
!     register n, next, pid;
      union wait wstat;
  
      while ((pid = wait3 (&wstat, WNOHANG|WUNTRACED, NULL)) > 0) {
! 	for (n = WinList; n != -1; n = next) {
! 	    next = wtab[n]->WinLink;
! 	    if (pid == wtab[n]->wpid) {
  		if (WIFSTOPPED (wstat)) {
! 		    (void) killpg (getpgrp (wtab[n]->wpid), SIGCONT);
  		} else {
! 		    KillWindow (n);
  		}
  	    }
***************
*** 451,498 ****
  }
  
! static KillWindow (pp) struct win **pp; {
!     if (*pp == curr)
  	curr = 0;
!     if (*pp == other)
! 	other = 0;
!     FreeWindow (*pp);
!     *pp = 0;
  }
  
  static CheckWindows () {
!     register struct win **pp;
! 
!     /* If the current window disappeared and the "other" window is still
!      * there, switch to the "other" window, else switch to the window
!      * with the lowest index.
!      * If there current window is still there, but the "other" window
!      * vanished, "SetCurrWindow" is called in order to assign a new value
!      * to "other".
       * If no window is alive at all, exit.
       */
!     if (!curr && other) {
! 	SwitchWindow (OtherNum);
! 	return;
!     }
!     if (curr && !other) {
! 	SetCurrWindow (CurrNum);
! 	return;
!     }
!     for (pp = wtab; pp < wtab+MAXWIN; ++pp) {
! 	if (*pp) {
! 	    if (!curr)
! 		SwitchWindow (pp-wtab);
! 	    return;
! 	}
!     }
!     Finit ();
  }
  
  static Finit () {
!     register struct win *p, **pp;
  
!     for (pp = wtab; pp < wtab+MAXWIN; ++pp) {
! 	if (p = *pp)
! 	    FreeWindow (p);
      }
      SetTTY (0, &OldMode);
--- 469,508 ----
  }
  
! static KillWindow (n) {
!     register i;
! 
!     /*
!      * Remove window from linked list.
!      */
!     if (n == WinList) {
! 	WinList = curr->WinLink;
  	curr = 0;
!     } else {
! 	i = WinList;
! 	while (wtab[i]->WinLink != n)
! 	    i = wtab[i]->WinLink;
! 	wtab[i]->WinLink = wtab[n]->WinLink;
!     }
!     FreeWindow (wtab[n]);
!     wtab[n] = 0;
  }
  
  static CheckWindows () {
!     /* If the current window disappeared check the head of the linked
!      * list of windows for the most recently used window.
       * If no window is alive at all, exit.
       */
!     if (WinList == -1)
! 	Finit ();
!     if (!curr)
! 	SwitchWindow (WinList);
  }
  
  static Finit () {
!     register n, next;
  
!     for (n = WinList; n != -1; n = next) {
! 	next = wtab[n]->WinLink;
! 	FreeWindow (wtab[n]);
      }
      SetTTY (0, &OldMode);
***************
*** 522,525 ****
--- 532,540 ----
      ktab[Ctrl('\\')].type = KEY_QUIT;
      ktab['d'].type = ktab[Ctrl('d')].type = KEY_DETACH;
+     ktab['r'].type = ktab[Ctrl('r')].type = KEY_WRAP;
+     ktab['f'].type = ktab[Ctrl('f')].type = KEY_FLOW;
+     ktab['/'].type = KEY_TOGGLE;
+     ktab['C'].type = KEY_CLEAR;
+     ktab['Z'].type = KEY_RESET;
      ktab[Esc].type = KEY_OTHER;
      for (i = 0; i <= 9; i++)
***************
*** 530,534 ****
      register n, k;
      register char *s, *p;
-     register struct win **pp;
  
      for (s = p = buf; len > 0; len--, s++) {
--- 545,548 ----
***************
*** 558,562 ****
  		    p = buf;
  		    if ((n = MakeWindow (ShellProg, ShellArgs,
! 			    0, 0, (char *)0)) != -1)
  			SwitchWindow (n);
  		    break;
--- 572,576 ----
  		    p = buf;
  		    if ((n = MakeWindow (ShellProg, ShellArgs,
! 			    0, flowctl, 0, (char *)0)) != -1)
  			SwitchWindow (n);
  		    break;
***************
*** 573,585 ****
  		case KEY_KILL:
  		    p = buf;
! 		    FreeWindow (wtab[CurrNum]);
! 		    if (other == curr)
! 			other = 0;
! 		    curr = wtab[CurrNum] = 0;
  		    CheckWindows ();
  		    break;
  		case KEY_QUIT:
- 		    for (pp = wtab; pp < wtab+MAXWIN; ++pp)
- 			if (*pp) FreeWindow (*pp);
  		    Finit ();
  		    /*NOTREACHED*/
--- 587,594 ----
  		case KEY_KILL:
  		    p = buf;
! 		    KillWindow (CurrNum);
  		    CheckWindows ();
  		    break;
  		case KEY_QUIT:
  		    Finit ();
  		    /*NOTREACHED*/
***************
*** 590,594 ****
  		case KEY_REDISPLAY:
  		    p = buf;
! 		    Activate (wtab[CurrNum]);
  		    break;
  		case KEY_WINDOWS:
--- 599,603 ----
  		case KEY_REDISPLAY:
  		    p = buf;
! 		    Activate (curr);
  		    break;
  		case KEY_WINDOWS:
***************
*** 607,611 ****
  		    p = buf;
  		    if (MoreWindows ())
! 			SwitchWindow (OtherNum);
  		    break;
  		case KEY_XON:
--- 616,620 ----
  		    p = buf;
  		    if (MoreWindows ())
! 			SwitchWindow (curr->WinLink);
  		    break;
  		case KEY_XON:
***************
*** 618,624 ****
  		    p = buf;
  		    if ((n = MakeWindow (ktab[*s].args[0], ktab[*s].args,
! 			    0, 0, (char *)0)) != -1)
  			SwitchWindow (n);
  		    break;
  		}
  	    } else ESCseen = 1;
--- 627,656 ----
  		    p = buf;
  		    if ((n = MakeWindow (ktab[*s].args[0], ktab[*s].args,
! 			    0, flowctl, 0, (char *)0)) != -1)
  			SwitchWindow (n);
  		    break;
+ 		case KEY_WRAP:
+ 		    curr->wrap = !curr->wrap;
+ 		    Msg (0, "%cwrap", curr->wrap ? '+' : '-');
+ 		    break;
+ 		case KEY_FLOW:
+ 		    ToggleFlow (curr);
+ 		    goto flow_msg;
+ 		case KEY_TOGGLE:
+ 		    if ((curr->toggle = !curr->toggle) != 0
+ 		     && curr->flow == curr->keypad)
+ 			ToggleFlow (curr);
+ 		flow_msg:
+ 		    Msg (0, "%c%sflow", curr->flow ? '+' : '-',
+ 			curr->toggle ? "/" : "");
+ 		    break;
+ 		case KEY_CLEAR:
+ 		    if (curr->state == LIT)
+ 			WriteString (curr, "\033[2J\033[H", 7);
+ 		    break;
+ 		case KEY_RESET:
+ 		    if (curr->state == LIT)
+ 			WriteString (curr, "\033c", 2);
+ 		    break;
  		}
  	    } else ESCseen = 1;
***************
*** 629,636 ****
  
  static SwitchWindow (n) {
!     if (!wtab[n])
  	return;
      SetCurrWindow (n);
!     Activate (wtab[n]);
  }
  
--- 661,670 ----
  
  static SwitchWindow (n) {
!     if (!wtab[n]) {
! 	Msg (0, "No such window.");
  	return;
+     }
      SetCurrWindow (n);
!     Activate (curr);
  }
  
***************
*** 637,647 ****
  static SetCurrWindow (n) {
      /*
!      * If we come from another window, this window becomes the
!      * "other" window:
       */
      if (curr) {
  	curr->active = 0;
- 	other = curr;
- 	OtherNum = CurrNum;
      }
      CurrNum = n;
--- 671,678 ----
  static SetCurrWindow (n) {
      /*
!      * If we come from another window, make it inactive.
       */
      if (curr) {
  	curr->active = 0;
      }
      CurrNum = n;
***************
*** 649,659 ****
      curr->active = 1;
      /*
!      * If the "other" window is currently undefined (at program start
!      * or because it has died), or if the "other" window is equal to the
!      * one just selected, we try to find a new one:
       */
!     if (other == 0 || other == curr) {
! 	OtherNum = NextWindow ();
! 	other = wtab[OtherNum];
      }
  }
--- 680,691 ----
      curr->active = 1;
      /*
!      * Place the window at the head of the most-recently-used list.
       */
!     if ((n = WinList) != CurrNum) {
! 	while (wtab[n]->WinLink != CurrNum)
! 	    n = wtab[n]->WinLink;
! 	wtab[n]->WinLink = curr->WinLink;
! 	curr->WinLink = WinList;
! 	WinList = CurrNum;
      }
  }
***************
*** 684,697 ****
  
  static MoreWindows () {
!     register struct win **pp;
!     register n;
! 
!     for (n = 0, pp = wtab; pp < wtab+MAXWIN; ++pp)
! 	if (*pp) ++n;
!     if (n <= 1)
! 	Msg (0, "No other window.");
!     return n > 1;
  }
  
  static FreeWindow (wp) struct win *wp; {
      register i;
--- 716,730 ----
  
  static MoreWindows () {
!     if (curr->WinLink != -1)
! 	return 1;
!     Msg (0, "No other window.");
!     return 0;
  }
  
+ void Free (p) register char *p; {
+     if (p)
+ 	free (p);
+ }
+ 
  static FreeWindow (wp) struct win *wp; {
      register i;
***************
*** 702,716 ****
      close (wp->ptyfd);
      for (i = 0; i < rows; ++i) {
! 	free (wp->image[i]);
! 	free (wp->attr[i]);
! 	free (wp->font[i]);
      }
!     free (wp->image);
!     free (wp->attr);
!     free (wp->font);
      free (wp);
  }
  
! static MakeWindow (prog, args, aflag, StartAt, dir)
  	char *prog, **args, *dir; {
      register struct win **pp, *p;
--- 735,750 ----
      close (wp->ptyfd);
      for (i = 0; i < rows; ++i) {
! 	Free (wp->image[i]);
! 	Free (wp->attr[i]);
! 	Free (wp->font[i]);
      }
!     Free (wp->image);
!     Free (wp->attr);
!     Free (wp->font);
!     Free (wp->tabs);
      free (wp);
  }
  
! static MakeWindow (prog, args, aflag, flowflag, StartAt, dir)
  	char *prog, **args, *dir; {
      register struct win **pp, *p;
***************
*** 739,748 ****
      (void) fcntl (f, F_SETFL, FNDELAY);
      if ((p = *pp = (struct win *)malloc (sizeof (struct win))) == 0) {
  nomem:
  	Msg (0, "Out of memory.");
  	return -1;
      }
-     if ((p->image = (char **)malloc (rows * sizeof (char *))) == 0)
- 	goto nomem;
      for (cp = p->image; cp < p->image+rows; ++cp) {
  	if ((*cp = malloc (cols)) == 0)
--- 773,800 ----
      (void) fcntl (f, F_SETFL, FNDELAY);
      if ((p = *pp = (struct win *)malloc (sizeof (struct win))) == 0) {
+ 	close (f);
+ 	Msg (0, "Out of memory.");
+ 	return -1;
+     }
+     bzero (p, sizeof (struct win));
+     p->ptyfd = f;
+     p->aflag = aflag;
+     if (!flowflag)
+ 	flowflag = flowctl;
+     p->flow = (flowflag != 1);
+     p->toggle = (flowflag == 3);
+     strncpy (p->cmd, Filename (args[0]), MAXSTR-1);
+     strncpy (p->tty, TtyName, MAXSTR-1);
+     (void) chown (TtyName, getuid (), getgid ());
+     (void) chmod (TtyName, TtyMode);
+     p->slot = SetUtmp (TtyName);
+ 
+     if ((p->image = (char **)malloc (rows * sizeof (char *))) == 0) {
  nomem:
+ 	FreeWindow (p);
+ 	*pp = 0;
  	Msg (0, "Out of memory.");
  	return -1;
      }
      for (cp = p->image; cp < p->image+rows; ++cp) {
  	if ((*cp = malloc (cols)) == 0)
***************
*** 767,785 ****
  	goto nomem;
      ResetScreen (p);
-     p->aflag = aflag;
-     p->active = 0;
-     p->bell = 0;
-     p->outlen = 0;
-     p->ptyfd = f;
-     strncpy (p->cmd, Filename (args[0]), MAXSTR-1);
-     p->cmd[MAXSTR-1] = '\0';
-     strncpy (p->tty, TtyName, MAXSTR-1);
-     (void) chown (TtyName, getuid (), getgid ());
-     (void) chmod (TtyName, TtyMode);
-     p->slot = SetUtmp (TtyName);
      switch (p->wpid = fork ()) {
      case -1:
  	Msg (errno, "fork");
! 	free ((char *)p);
  	return -1;
      case 0:
--- 819,826 ----
  	goto nomem;
      ResetScreen (p);
      switch (p->wpid = fork ()) {
      case -1:
  	Msg (errno, "fork");
! 	FreeWindow (p);
  	return -1;
      case 0:
***************
*** 817,820 ****
--- 858,869 ----
  	exit (1);
      }
+     /*
+      * Place the newly created window at the head of the most-recently-used
+      * list.  Since this spot is reserved for the "curr"ent window, you MUST
+      * call SetCurrWindow (with "n" or "CurrNum") when you finish creating
+      * your windows.
+      */
+     p->WinLink = WinList;
+     WinList = n;
      return n;
  }
***************
*** 910,915 ****
      register char *s;
      register struct win **pp, *p;
  
!     for (s = buf, pp = wtab; pp < wtab+MAXWIN; ++pp) {
  	if ((p = *pp) == 0)
  	    continue;
--- 959,965 ----
      register char *s;
      register struct win **pp, *p;
+     register i, OtherNum = curr->WinLink;
  
!     for (i = 0, s = buf, pp = wtab; pp < wtab+MAXWIN; ++i, ++pp) {
  	if ((p = *pp) == 0)
  	    continue;
***************
*** 919,926 ****
  	    *s++ = ' '; *s++ = ' ';
  	}
! 	*s++ = pp - wtab + '0';
! 	if (p == curr)
  	    *s++ = '*';
! 	else if (p == other)
  	    *s++ = '-';
  	*s++ = ' ';
--- 969,976 ----
  	    *s++ = ' '; *s++ = ' ';
  	}
! 	*s++ = i + '0';
! 	if (i == CurrNum)
  	    *s++ = '*';
! 	else if (i == OtherNum)
  	    *s++ = '-';
  	*s++ = ' ';
***************
*** 960,965 ****
  #endif
      p = buf + strlen (buf);
!     sprintf (p, " (%d,%d) %cflow %cins %corg %cwrap %cpad", wp->y, wp->x,
! 	flowctl ? '+' : '-',
  	wp->insert ? '+' : '-', wp->origin ? '+' : '-',
  	wp->wrap ? '+' : '-', wp->keypad ? '+' : '-');
--- 1010,1015 ----
  #endif
      p = buf + strlen (buf);
!     sprintf (p, " (%d,%d) %c%sflow %cins %corg %cwrap %cpad", wp->y, wp->x,
! 	wp->flow ? '+' : '-', wp->toggle ? "/" : "",
  	wp->insert ? '+' : '-', wp->origin ? '+' : '-',
  	wp->wrap ? '+' : '-', wp->keypad ? '+' : '-');
***************
*** 982,987 ****
--- 1032,1042 ----
      strcpy (TtyName, TtyProto);
      for (p = PtyName, i = 0; *p != 'X'; ++p, ++i) ;
+ #ifdef sequent
+     for (l = "p"; *p = *l; ++l) { /*}*/
+ 	for (d = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; p[1] = *d; ++d) { /*}*/
+ #else
      for (l = "qpr"; *p = *l; ++l) {
  	for (d = "0123456789abcdef"; p[1] = *d; ++d) {
+ #endif
  	    if ((f = open (PtyName, O_RDWR)) != -1) {
  		TtyName[i] = p[0];
***************
*** 1016,1024 ****
  static SetMode (op, np) struct mode *op, *np; {
      *np = *op;
      np->m_ttyb.sg_flags &= ~(CRMOD|ECHO);
      np->m_ttyb.sg_flags |= CBREAK;
-     np->m_tchars.t_intrc = -1;
      np->m_tchars.t_quitc = -1;
!     if (!flowctl) {
  	np->m_tchars.t_startc = -1;
  	np->m_tchars.t_stopc = -1;
--- 1071,1085 ----
  static SetMode (op, np) struct mode *op, *np; {
      *np = *op;
+     startc = op->m_tchars.t_startc;
+     stopc = op->m_tchars.t_stopc;
+     if (iflag)
+ 	intrc = op->m_tchars.t_intrc;
+     else
+ 	intrc = np->m_tchars.t_intrc = -1;
      np->m_ttyb.sg_flags &= ~(CRMOD|ECHO);
      np->m_ttyb.sg_flags |= CBREAK;
      np->m_tchars.t_quitc = -1;
!     if (flowctl == 1) {
! 	np->m_tchars.t_intrc = -1;
  	np->m_tchars.t_startc = -1;
  	np->m_tchars.t_stopc = -1;
***************
*** 1030,1033 ****
--- 1091,1107 ----
  }
  
+ SetFlow (on) {
+     if (on) {
+ 	NewMode.m_tchars.t_intrc  = intrc;
+ 	NewMode.m_tchars.t_startc = startc;
+ 	NewMode.m_tchars.t_stopc  = stopc;
+     } else {
+ 	NewMode.m_tchars.t_intrc  = -1;
+ 	NewMode.m_tchars.t_startc = -1;
+ 	NewMode.m_tchars.t_stopc  = -1;
+     }
+     ioctl (0, TIOCSETC, &NewMode.m_tchars);
+ }
+ 
  static char *GetTtyName () {
      register char *p;
***************
*** 1103,1106 ****
--- 1177,1181 ----
  static Attacher () {
      signal (SIGHUP, AttacherFinit);
+     signal (SIGINT, SIG_IGN);
      signal (SIGCONT, ReAttach);
      while (1)
***************
*** 1109,1113 ****
  
  static Detach (suspend) {
!     register struct win **pp;
  
      if (Detached)
--- 1184,1188 ----
  
  static Detach (suspend) {
!     register n;
  
      if (Detached)
***************
*** 1117,1124 ****
      FinitTerm ();
      if (suspend) {
  	Kill (AttacherPid, SIGTSTP);
      } else {
! 	for (pp = wtab; pp < wtab+MAXWIN; ++pp)
! 	    if (*pp) RemoveUtmp ((*pp)->slot);
  	printf ("\n[detached]\n");
  	Kill (AttacherPid, SIGHUP);
--- 1192,1200 ----
      FinitTerm ();
      if (suspend) {
+ 	(void) fflush (stdout);
  	Kill (AttacherPid, SIGTSTP);
      } else {
! 	for (n = WinList; n != -1; n = wtab[n]->WinLink)
! 	    RemoveUtmp (wtab[n]->slot);
  	printf ("\n[detached]\n");
  	Kill (AttacherPid, SIGHUP);
***************
*** 1129,1132 ****
--- 1205,1209 ----
      close (2);
      ioctl (DevTty, TIOCNOTTY, (char *)0);
+     close (DevTty);
      Detached = 1;
      do {
***************
*** 1133,1139 ****
  	ReceiveMsg (ServerSocket); 
      } while (Detached);
      if (!suspend)
! 	for (pp = wtab; pp < wtab+MAXWIN; ++pp)
! 	    if (*pp) (*pp)->slot = SetUtmp ((*pp)->tty);
      signal (SIGHUP, SigHup);
  }
--- 1210,1218 ----
  	ReceiveMsg (ServerSocket); 
      } while (Detached);
+     if ((DevTty = open ("/dev/tty", O_RDWR|O_NDELAY)) == -1)
+ 	Msg (errno, "/dev/tty");
      if (!suspend)
! 	for (n = WinList; n != -1; n = wtab[n]->WinLink)
! 	    wtab[n]->slot = SetUtmp (wtab[n]->tty);
      signal (SIGHUP, SigHup);
  }
***************
*** 1205,1209 ****
  }
  
! static SendCreateMsg (s, ac, av, aflag) char **av; {
      struct msg m;
      register char *p;
--- 1284,1288 ----
  }
  
! static SendCreateMsg (s, ac, av, aflag, flowflag) char **av; {
      struct msg m;
      register char *p;
***************
*** 1221,1224 ****
--- 1300,1304 ----
      m.m.create.nargs = n;
      m.m.create.aflag = aflag;
+     m.m.create.flowflag = flowflag;
      if (getwd (m.m.create.dir) == 0)
  	Msg (0, "%s", m.m.create.dir);
***************
*** 1274,1278 ****
  	if (Detached) {
  	    if (kill (m.m.attach.apid, 0) == 0 &&
! 		    open (m.m.attach.tty, O_RDWR) == 0) {
  		(void) dup (0);
  		(void) dup (0);
--- 1354,1358 ----
  	if (Detached) {
  	    if (kill (m.m.attach.apid, 0) == 0 &&
! 		    open (m.m.attach.tty, O_RDWR|O_NDELAY) == 0) {
  		(void) dup (0);
  		(void) dup (0);
***************
*** 1282,1286 ****
  		SetMode (&OldMode, &NewMode);
  		SetTTY (0, &NewMode);
! 		Activate (wtab[CurrNum]);
  	    }
  	} else {
--- 1362,1366 ----
  		SetMode (&OldMode, &NewMode);
  		SetTTY (0, &NewMode);
! 		Activate (curr);
  	    }
  	} else {
***************
*** 1307,1312 ****
      }
      *pp = 0;
!     if ((n = MakeWindow (mp->m.create.line, args, mp->m.create.aflag, 0,
! 	    mp->m.create.dir)) != -1)
  	SwitchWindow (n);
  }
--- 1387,1392 ----
      }
      *pp = 0;
!     if ((n = MakeWindow (mp->m.create.line, args, mp->m.create.aflag,
! 	    mp->m.create.flowflag, 0, mp->m.create.dir)) != -1)
  	SwitchWindow (n);
  }
***************
*** 1318,1322 ****
      char buf[256];
      char *args[MAXARGS];
!     int key;
  
      ap = args;
--- 1398,1402 ----
      char buf[256];
      char *args[MAXARGS];
!     char key, flowflag;
  
      ap = args;
***************
*** 1331,1339 ****
  	    continue;
  	if (strcmp (ap[0], "escape") == 0) {
! 	    p = ap[1];
! 	    if (argc < 2 || strlen (p) != 2)
  		Msg (0, "%s: two characters required after escape.", fn);
! 	    Esc = *p++;
! 	    MetaEsc = *p;
  	} else if (strcmp (ap[0], "chdir") == 0) {
  	    p = argc < 2 ? home : ap[1];
--- 1411,1417 ----
  	    continue;
  	if (strcmp (ap[0], "escape") == 0) {
! 	    if (argc < 2 || !ParseEscape (ap[1]))
  		Msg (0, "%s: two characters required after escape.", fn);
! 	    ktab[Esc].type = KEY_OTHER;
  	} else if (strcmp (ap[0], "chdir") == 0) {
  	    p = argc < 2 ? home : ap[1];
***************
*** 1354,1358 ****
--- 1432,1485 ----
  		strcpy (BellString, ap[1]);
  	    }
+ 	} else if (strcmp (ap[0], "wrap") == 0) {
+ 	    num = 0;
+ 	    if (argc == 2 && ap[1][0] == 'o') {
+ 		if (ap[1][1] == 'f')
+ 		    num = 1;
+ 		else if (ap[1][1] == 'n')
+ 		    num = 2;
+ 	    }
+ 	    if (!num) {
+ 		Msg (0, "%s: wrap: invalid argument.", fn);
+ 	    } else {
+ 		wrap = num-1;
+ 	    }
+ 	} else if (strcmp (ap[0], "flow") == 0) {
+ 	    flowflag = 0;
+ 	    if (argc == 2) {
+ 		if (ap[1][0] == 'o') {
+ 		    if (ap[1][1] == 'f')
+ 			flowflag = 1;
+ 		    else if (ap[1][1] == 'n')
+ 			flowflag = 2;
+ 		} else if (ap[1][0] == 't')
+ 		    flowflag = 3;
+ 	    }
+ 	    if (!flowflag) {
+ 		Msg (0, "%s: flow: invalid argument.", fn);
+ 	    } else {
+ 		flowctl = flowflag;
+ 	    }
  	} else if (strcmp (ap[0], "screen") == 0) {
+ 	    flowflag = flowctl;
+ 	    while (argc > 1 && ap[1][0] == '-') {
+ 		switch (ap[1][1]) {
+ 		case 'n':
+ 		    flowflag = 1;
+ 		    break;
+ 		case 'f':
+ 		    if (ap[1][2] != '/')
+ 			flowflag = 2;
+ 		    else
+ 			flowflag = 3;
+ 		    break;
+ 		case 'a':
+ 		    break;
+ 		default:
+ 		    Msg (0, "%s: screen: invalid option -%c.", fn, ap[1][1]);
+ 		    break;
+ 		}
+ 		--argc; ++ap;
+ 	    }
  	    num = 0;
  	    if (argc > 1 && IsNum (ap[1], 10)) {
***************
*** 1366,1370 ****
  	    }
  	    ap[argc] = 0;
! 	    (void) MakeWindow (ap[1], ap+1, 0, num, (char *)0);
  	} else if (strcmp (ap[0], "bind") == 0) {
  	    p = ap[1];
--- 1493,1497 ----
  	    }
  	    ap[argc] = 0;
! 	    (void) MakeWindow (ap[1], ap+1, 0, flowflag, num, (char *)0);
  	} else if (strcmp (ap[0], "bind") == 0) {
  	    p = ap[1];
***************
*** 1371,1386 ****
  	    if (argc < 2 || *p == '\0')
  		Msg (0, "%s: key expected after bind.", fn);
! 	    if (p[1] == '\0') {
! 		key = *p;
! 	    } else if (p[0] == '^' && p[1] != '\0' && p[2] == '\0') {
! 		c = p[1];
! 		if (isupper (c))
! 		    p[1] = tolower (c);    
! 		key = Ctrl(c);
! 	    } else if (IsNum (p, 7)) {
! 		(void) sscanf (p, "%o", &key);
! 	    } else {
  		Msg (0,
! 		    "%s: bind: character, ^x, or octal number expected.", fn);
  	    }
  	    if (argc < 3) {
--- 1498,1504 ----
  	    if (argc < 2 || *p == '\0')
  		Msg (0, "%s: key expected after bind.", fn);
! 	    if (!(p = ParseChar (p, &key)) || *p) {
  		Msg (0,
! 		    "%s: bind: character, ^x, or (octal) \\032 expected.", fn);
  	    }
  	    if (argc < 3) {
***************
*** 1430,1433 ****
--- 1548,1576 ----
  }
  
+ static int ParseEscape (p) char *p; {
+     if (!(p = ParseChar (p, &Esc)) || !(p = ParseChar (p, &MetaEsc)) || *p)
+ 	return 0;
+     return 1;
+ }
+ 
+ static char *ParseChar (p, cp) char *p, *cp; {
+     if (*p == '^') {
+ 	if (*++p == '?')
+ 	    *cp = '\177';
+ 	else if (*p >= '@')
+ 	    *cp = Ctrl(*p);
+ 	else
+ 	    return 0;
+ 	++p;
+     } else if (*p == '\\' && *++p <= '7' && *p >= '0') {
+ 	*cp = 0;
+ 	do
+ 	    *cp = *cp * 8 + *p - '0';
+ 	while (*++p <= '7' && *p >= '0');
+     } else
+ 	*cp = *p++;
+     return p;
+ }
+ 
  static char **SaveArgs (argc, argv) register argc; register char **argv; {
      register char **ap, **pp;
***************
*** 1459,1463 ****
  	    break;
  	if (!IsSymbol (*op, "TERM") && !IsSymbol (*op, "TERMCAP")
! 		&& !IsSymbol (*op, "STY"))
  	    *np++ = *op;
      }
--- 1602,1606 ----
  	    break;
  	if (!IsSymbol (*op, "TERM") && !IsSymbol (*op, "TERMCAP")
! 		&& !IsSymbol (*op, "STY") && !IsSymbol (*op, "WINDOW"))
  	    *np++ = *op;
      }
*** orig/screen.h	Wed Feb  8 20:19:02 1989
--- ./screen.h	Fri Feb 17 16:46:27 1989
***************
*** 43,47 ****
      char tty[MAXSTR];
      int args[MAXARGS];
-     char GotArg[MAXARGS];
      int NumArgs;
      int slot;
--- 43,46 ----
***************
*** 72,75 ****
--- 71,77 ----
      int vbwait;
      int bell;
+     int flow;
+     int toggle;
+     int WinLink;
  };
  
***************
*** 86,89 ****
--- 88,92 ----
  	struct {
  	    int aflag;
+ 	    int flowflag;
  	    int nargs;
  	    char line[MAXLINE];
-----------------------------------Cut Here-----------------------------------
 Wayne Davison                                        ...amdahl!drivax!davison