[comp.os.minix] more tty changes: wrap, null, ins/del char, etc.

hedrick@athos.rutgers.edu (Charles Hedrick) (09/04/88)

Here are a few more tty-related changes.  You must have installed my
previous tty diffs.  As far as I know, only the insert-delete char
depends upon them, so you should be able to take the other changes
from this file alone if you are interested in one of them
specifically.  (That is possible, since lots of people have asked for
line wrap.)

  - removing locks from at_wini and xt_wini.  (Yet another
	attempt to avoid losing RS232 input characters.  These are
	from brucee.  I'm fairly confident of the patches to at_wini.
	I have no way to check the patches for xt_wini, but Bruce
	believes they are right.)

  - allow you to type null's on the console.  Don't turn nulls
	into ^D.  There was a basic design problem in handling
	nulls.  It's not possible to fix it completely, but after
	my changes, the only problem is that you won't be able
	to generate 0200 from the console keyboard when in cooked mode.
	I believe that's not going to be a problem.  In raw or 
	cbreak mode, you will be able to (if you can figure out
	the right combination of shift and control keys).

  - added line wrap.  That is, when output is too long for a line
	it will go onto a new line.  This is the simple form.  When
	you put a character in the last position on the line, the
	cursor goes to the next line.  So if you put out lines of
	exactly 80 chars, you'll get an extra blank line between
	them.  It's possible to keep this from happening by creating
	a phantom 81-st position on the line, but that complicates
	the code and in my opinion doesn't gain enough to make it
	worth doing.  Some real terminals seem to do it each way.

  - added insert/delete character ANSI escape codes.  Tested only
	on EGA with my hardware scrolling, but I don't think there
	will be problems with other configurations.  ESC [ n @
	inserts n blanks at the cursor, moving the right of the
	line to the right.  ESC [ n P deletes the next n characters
	starting at the cursor, filling the right end of the line
	with blanks.

Here are Unix termcap entries to describe the result.  This assumes
that color users are running with black on white characters and
monochrome with white on black.  This is probably a reasonable
assumption, since most monochrome monitors are amber or green, and
black on green looks really wierd.  However with a good color monitor,
black on white is noticably more readable than white on black.  (To go
into black on white mode, use \E[30m\E[47m, where \E represents
"escape" (octal 33).)

In|minix|minix console support for color monitor:\
	:do=^J:up=^K:co#80:li#25:am:cl=\E[;H\E[J:\
	:al=\E[L:dl=\E[M:AL=\E[%dL:DL=\E[%dM:\
	:ic=\E[@:dc=\E[P:IC=\E[%d@:DC=\E[%dP:\
	:le=^H:nd=^N:bs:am:cm=\E[%i%d;%dH:\
	:ce=\E[K:cd=\E[J:so=\E[42m:se=\E[47m:us=\E[4m:ue=\E[m:\
	:md=\E[1m:mr=\E[7m:mb=\E[5m:me=\E[0m\E[47m:\
	:ho=\E[H:
Im|minix-bw|minix console support for monochrome monitor:\
	:do=^J:up=^K:co#80:li#25:am:cl=\E[;H\E[J:\
	:al=\E[L:dl=\E[M:AL=\E[%dL:DL=\E[%dM:\
	:ic=\E[@:dc=\E[P:IC=\E[%d@:DC=\E[%dP:\
	:le=^H:nd=^N:bs:am:cm=\E[%i%d;%dH:\
	:ce=\E[K:cd=\E[J:so=\E[7m:se=\E[0m:us=\E[4m:ue=\E[m:\
	:md=\E[1m:mr=\E[7m:mb=\E[5m:me=\E[0m:\
	:ho=\E[H:


*** at_wini.c.ORIG	Thu Jan  1 00:11:21 1970
--- at_wini.c	Thu Sep  1 06:00:34 1988
***************
*** 212,220 ****
    if (wn->wn_opcode == DISK_READ) {
  	for (i=0; i<BLOCK_SIZE/SECTOR_SIZE; i++) {
  		receive(HARDWARE, &w_mess);
! 		old_state = lock();
! 		dma_read((unsigned)(usr_buf >> 4), (unsigned)(usr_buf & 0x0F));
! 		restore(old_state);
  		usr_buf += 0x200;
  		if (win_results() != OK) {
  			w_need_reset = TRUE;
--- 212,220 ----
    if (wn->wn_opcode == DISK_READ) {
  	for (i=0; i<BLOCK_SIZE/SECTOR_SIZE; i++) {
  		receive(HARDWARE, &w_mess);
! /*		old_state = lock(); */
! 		dma_read((unsigned)(usr_buf >> 4), (unsigned)(usr_buf & 0x0F));
! /*		restore(old_state); */
  		usr_buf += 0x200;
  		if (win_results() != OK) {
  			w_need_reset = TRUE;
***************
*** 230,238 ****
  		return(ERR);
  	}
  	for (i=0; i<BLOCK_SIZE/SECTOR_SIZE; i++) {
! 		old_state = lock();
! 		dma_write((unsigned)(usr_buf >> 4), (unsigned)(usr_buf&0x0F));
! 		restore(old_state);
  		usr_buf += 0x200;
  		receive(HARDWARE, &w_mess);
  		if (win_results() != OK) {
--- 230,238 ----
  		return(ERR);
  	}
  	for (i=0; i<BLOCK_SIZE/SECTOR_SIZE; i++) {
! /*		old_state = lock(); */
! 		dma_write((unsigned)(usr_buf >> 4), (unsigned)(usr_buf&0x0F));
! /*		restore(old_state); */
  		usr_buf += 0x200;
  		receive(HARDWARE, &w_mess);
  		if (win_results() != OK) {
*** xt_wini.c.ORIG	Thu Jan  1 00:12:15 1970
--- xt_wini.c	Thu Sep  1 06:02:15 1988
***************
*** 615,621 ****
  	}
  
  
! 	old_state = lock();
  
  	for (i=0; i<6; i++) {
  		if(hd_wait(WST_REQ) != OK)
--- 615,621 ----
  	}
  
  
! /*	old_state = lock(); */
  
  	for (i=0; i<6; i++) {
  		if(hd_wait(WST_REQ) != OK)
***************
*** 630,636 ****
  		port_out(WIN_DATA, command[i]);
  	}
  
! 	restore(old_state);
  
  	if(i != 6) {
  		return(ERR);
--- 630,636 ----
  		port_out(WIN_DATA, command[i]);
  	}
  
! /*	restore(old_state); */
  
  	if(i != 6) {
  		return(ERR);
*** tty.c.HOLD	Thu Jan  1 00:11:12 1970
--- tty.c	Fri Sep  2 00:18:26 1988
***************
*** 74,81 ****
  #define XOFF_CHAR (char) 023	/* default x-off character (CTRL-S) */
  #define XON_CHAR  (char) 021	/* default x-on character (CTRL-Q) */
  #define EOT_CHAR  (char) 004	/* CTRL-D */
! #define MARKER    (char) 000	/* non-escaped CTRL-D stored as MARKER */
! #define AT_SIGN         0200	/* code to yield for CTRL-@ */
  #define SCODE1            71	/* scan code for Home on numeric pad */
  #define SCODE2            81	/* scan code for PgDn on numeric pad */
  #define DEL_CODE   (char) 83	/* DEL for use in CTRL-ALT-DEL reboot */
--- 74,89 ----
  #define XOFF_CHAR (char) 023	/* default x-off character (CTRL-S) */
  #define XON_CHAR  (char) 021	/* default x-on character (CTRL-Q) */
  #define EOT_CHAR  (char) 004	/* CTRL-D */
! /*
!  * This MARKER is used as an unambiguous flag for an unescaped end of
!  * file character.  It is meaningful only in cooked mode.  That's
!  * fairly safe because cooked mode isn't supposed to return things
!  * with the high-order bit on anyway.  Be careful that code only checks
!  * for MARKER in cooked mode.  This kludge is needed because
!  * chars are stored in char arrays, so there's no way to have a
!  * completely out of band value.
!  */
! #define MARKER    (char) 0200	/* non-escaped CTRL-D stored as MARKER */
  #define SCODE1            71	/* scan code for Home on numeric pad */
  #define SCODE2            81	/* scan code for PgDn on numeric pad */
  #define DEL_CODE   (char) 83	/* DEL for use in CTRL-ALT-DEL reboot */
***************
*** 389,396 ****
  /* A character has just been typed in.  Process, save, and echo it. */
  
    register struct tty_struct *tp;
!   int mode, sig, scode;
!   char make_break();
  
    scode = ch;			/* save the scan code */
    tp = &tty_struct[line];	/* set 'tp' to point to proper struct */
--- 397,404 ----
  /* A character has just been typed in.  Process, save, and echo it. */
  
    register struct tty_struct *tp;
!   int mode, sig, scode, c;
!   int make_break();
  
    scode = ch;			/* save the scan code */
    tp = &tty_struct[line];	/* set 'tp' to point to proper struct */
***************
*** 403,410 ****
    if (tp->tty_incount >= TTY_IN_BYTES) return;	/* no room, discard char */
    mode = tp->tty_mode & (RAW | CBREAK);
    if (tp->tty_makebreak == TWO_INTS) {
! 	ch = make_break(ch);	/* console give 2 ints/ch */
! 	if (ch == 0) return;
    }
    else
  	if (mode != RAW) ch &= 0177;	/* 7-bit chars except in raw mode */
--- 411,419 ----
    if (tp->tty_incount >= TTY_IN_BYTES) return;	/* no room, discard char */
    mode = tp->tty_mode & (RAW | CBREAK);
    if (tp->tty_makebreak == TWO_INTS) {
! 	c = make_break(ch);	/* console give 2 ints/ch */
! 	if (c == -1) return;
! 	ch = c;
    }
    else
  	if (mode != RAW) ch &= 0177;	/* 7-bit chars except in raw mode */
***************
*** 445,451 ****
  			 * line feed in terms of knowing whether a full line
  			 * has been typed already.
  			 */
! 			if (ch == tp->tty_eof) ch = MARKER;
  		} else {
  			/* Previous character was backslash. */
  			tp->tty_escaped = NOT_ESCAPED;	/* turn escaping off */
--- 454,463 ----
  			 * line feed in terms of knowing whether a full line
  			 * has been typed already.
  			 */
! 			if (ch == tp->tty_eof) {
! 				ch = MARKER;
!   				tp->tty_lfct++;	/* counts as LF */
! 			}
  		} else {
  			/* Previous character was backslash. */
  			tp->tty_escaped = NOT_ESCAPED;	/* turn escaping off */
***************
*** 485,491 ****
    }
  
    /* All 3 modes come here. */
!   if (ch == '\n' || ch == MARKER) tp->tty_lfct++;	/* count line feeds */
  
    /* The numeric pad generates ASCII escape sequences: ESC [ letter */
    if (line == 0 && scode >= SCODE1 && scode <= SCODE2 && 
--- 497,503 ----
    }
  
    /* All 3 modes come here. */
!   if (ch == '\n') tp->tty_lfct++;	/* count line feeds */
  
    /* The numeric pad generates ASCII escape sequences: ESC [ letter */
    if (line == 0 && scode >= SCODE1 && scode <= SCODE2 && 
***************
*** 516,522 ****
  /*===========================================================================*
   *				make_break				     *
   *===========================================================================*/
! PRIVATE char make_break(ch)
  char ch;			/* scan code of key just struck or released */
  {
  /* This routine can handle keyboards that interrupt only on key depression,
--- 528,534 ----
  /*===========================================================================*
   *				make_break				     *
   *===========================================================================*/
! PRIVATE int make_break(ch)
  char ch;			/* scan code of key just struck or released */
  {
  /* This routine can handle keyboards that interrupt only on key depression,
***************
*** 559,566 ****
  			code -= 'a' - 'A';
  	if (alt) code |= 0200;	/* alt key ORs 0200 into code */
  	if (control) code &= 037;
! 	if (code == 0) code = AT_SIGN;	/* @ is 0100, so CTRL-@ = 0 */
! 	if (make == 0) code = 0;	/* key release */
  	return(code);
    }
  
--- 571,578 ----
  			code -= 'a' - 'A';
  	if (alt) code |= 0200;	/* alt key ORs 0200 into code */
  	if (control) code &= 037;
! /*	if (code == 0) code = AT_SIGN;	/* @ is 0100, so CTRL-@ = 0 */
! 	if (make == 0) return(-1);	/* key release */
  	return(code);
    }
  
***************
*** 583,589 ****
  		num_off = 1 - make;
  		break;	/* num lock */
    }
!   return(0);
  }
  #endif
  
--- 595,601 ----
  		num_off = 1 - make;
  		break;	/* num lock */
    }
!   return(-1);
  }
  #endif
  
***************
*** 598,604 ****
  /* Echo a character on the terminal. */
  
    if ( (tp->tty_mode & ECHO) == 0) return;	/* if no echoing, don't echo */
!   if (c != MARKER) {
  	if (tp - tty_struct < NR_CONS)
  		out_char(tp, c);	/* echo to console */
  	else
--- 610,617 ----
  /* Echo a character on the terminal. */
  
    if ( (tp->tty_mode & ECHO) == 0) return;	/* if no echoing, don't echo */
!   /* MARKER is meaningful only in cooked mode */
!   if (c != MARKER || tp->tty_mode  & (CBREAK | RAW)) {
  	if (tp - tty_struct < NR_CONS)
  		out_char(tp, c);	/* echo to console */
  	else
***************
*** 706,714 ****
  			tp->tty_intail = tp->tty_inqueue;
  		*tty_ptr++ = ch;
  		ct++;
! 		if (ch == '\n' || ch == MARKER) {
! 			tp->tty_lfct--;
! 			if (cooked && ch == MARKER) eot_seen++;
  			enough++;	/* exit loop */
  			if (cooked) break;	/* only provide 1 line */
  		}
--- 719,727 ----
  			tp->tty_intail = tp->tty_inqueue;
  		*tty_ptr++ = ch;
  		ct++;
! 		if (ch == '\n' || ch == MARKER && cooked) {
! 			tp->tty_lfct--;
! 			if (ch == MARKER) eot_seen++;
  			enough++;	/* exit loop */
  			if (cooked) break;	/* only provide 1 line */
  		}
***************
*** 1159,1164 ****
--- 1172,1181 ----
    }
  
    switch(c) {
+ 	/* null is typically used for padding, so it better do nothing
+ 	 * It displays as space, so we don't lose anything */
+ 	case 000:
+ 		return;
  	case 007:		/* ring the bell */
  		flush(tp);	/* print any chars queued for output */
  		beep(BEEP_FREQ);/* BEEP_FREQ gives bell tone */
***************
*** 1210,1219 ****
  		return;
  
  	default:		/* printable chars are stored in ramqueue */
! 		if (tp->tty_column >= LINE_WIDTH) return;	/* long line */
  		if (tp->tty_rwords == TTY_RAM_WORDS) flush(tp);
  		tp->tty_ramqueue[tp->tty_rwords++]=tp->tty_attribute|(c & BYTE);
  		tp->tty_column++;	/* next column */
  		return;
    }
  }
--- 1227,1247 ----
  		return;
  
  	default:		/* printable chars are stored in ramqueue */
  		if (tp->tty_rwords == TTY_RAM_WORDS) flush(tp);
  		tp->tty_ramqueue[tp->tty_rwords++]=tp->tty_attribute|(c & BYTE);
  		tp->tty_column++;	/* next column */
+ 		if (tp->tty_column >= LINE_WIDTH) {
+ 			flush(tp);
+ 			if (tp->tty_row == SCR_LINES-1)
+ 				scroll_screen(tp, GO_FORWARD);
+ 			else
+ 				tp->tty_row++;
+ 			move_to(tp, 0, tp->tty_row);
+ 		}
  		return;
    }
  }
***************
*** 1668,1673 ****
--- 1696,1754 ----
  			long_vid_copy(NIL_PTR, vid_base, dst - limit, count);
  		}
  		break;
+ 	case 'P':		/* delete chars */
+ 		{int src, dst, count;
+ 
+ 		n = tp->tty_esc_parmv[0];
+ 		if (n < 1)
+ 			n = 1;
+ 		if (n > (LINE_WIDTH - tp->tty_column))
+ 			n = LINE_WIDTH - tp->tty_column;
+ 		src = (tp->tty_row * LINE_WIDTH + tp->tty_column + n) * 2;
+ 		dst = (tp->tty_row * LINE_WIDTH + tp->tty_column) * 2;
+ 		count = LINE_WIDTH - tp->tty_column - n;
+ 		src += tp->tty_org;
+ 		dst += tp->tty_org;
+ 		if ((! softscroll) && ega) {
+ 			if (src > SCR_BYTES)
+ 				src -= SCR_BYTES;
+ 			if (dst > SCR_BYTES)
+ 				dst -= SCR_BYTES;
+ 		}
+ 		scr_up(vid_base, src, dst, count);
+ 		vid_copy(NIL_PTR, vid_base, dst + count * 2, n);
+ 		}
+ 		break;
+ 	case '@':  /* insert chars (actually blanks) */
+ 		{int src, dst, count;
+ 
+ 		n = tp->tty_esc_parmv[0];
+ 		if (n < 1)
+ 			n = 1;
+ 		if (n > (LINE_WIDTH - tp->tty_column))
+ 			n = LINE_WIDTH - tp->tty_column;
+ 		src = (tp->tty_row * LINE_WIDTH + LINE_WIDTH - n - 1) * 2;
+ 		dst = (tp->tty_row * LINE_WIDTH + LINE_WIDTH - 1) * 2;
+ 		count = LINE_WIDTH - tp->tty_column - n;
+ 		src += tp->tty_org;
+ 		dst += tp->tty_org;
+ 		if ((! softscroll) && ega) {
+ 			if (src > SCR_BYTES)
+ 				src -= SCR_BYTES;
+ 			if (dst > SCR_BYTES)
+ 				dst -= SCR_BYTES;
+ 		}
+ 		scr_down(vid_base, src, dst, count);
+ 		dst = (tp->tty_row * LINE_WIDTH + tp->tty_column) * 2;
+ 		dst += tp->tty_org;
+ 		if ((! softscroll) && ega) {
+ 			if (dst > SCR_BYTES)
+ 				dst -= SCR_BYTES;
+ 		}
+ 		vid_copy(NIL_PTR, vid_base, dst, n);
+ 		}
+ 		break;
+ 
  	case 'm':		/* Set graphic rendition */
   		switch (tp->tty_esc_parmv[0]) {
   			case 1: /*  BOLD  */