From: pmacdona@sanjuan (Peter MacDonald)
Newsgroups: comp.os.linux
Subject: extended char set and direct screen writes
Date: 30 Jun 92 16:50:52 GMT
Organization: University of Victoria, Victoria, BC, CANADA
Nntp-Posting-Host: sanjuan.uvic.ca


Following are patches to allow the full extended char sets under Linux,
via two methods.  The first, and the preferred method, is a modification
of the console driver to add a new translation mode.  (Linus tells me
that someone already sent him a patch to do this some time ago, but
that he hasn't used it yet).  Since it was so simple, I did it again.

The second is a modification of the screen dump ioctl call used
by setterm (but still backward compatable), to allow direct screen
reading and writing as well.  While I am in no way condoning its
use, it may be that the dos emulator can not map all direct screen IO 
to the curses model, and thus will need to use this method.  Eventually,
the DOS emulator should use curses, so that it can be made to work even
on terminals.  

I am posting it for your critique.  Feel free to be brutal, but please
don't tell me that "you have no use for DOS".  Frankly, I don't either,
but if Linux gets DOS support, it can attract very many more users,
which translates to more supporters/developers.

Also included is a simple test program to display a popup menu 
ala DOS, and to show a few extended chars via the console driver.
Note the later uses ESC(U to use extended chars and ESC(B to get
back to normal chars.

Peter.
pmacdona@tadpole.bcsc.gov.bc.ca

-----extchar.cdif--------------------------------------------------
*** kernel/chr_drv/console.c.save	Sun Jun 28 17:00:19 1992
--- kernel/chr_drv/console.c	Mon Jun 29 22:15:04 1992
***************
*** 221,227 ****
  #define VT100ID "\033[?1;2c"
  #define VT102ID "\033[?6c"
  
! static char * translations[] = {
  /* 8-bit Latin-1 mapped to the PC charater set: '\0' means non-printable */
  	"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  	"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
--- 221,227 ----
  #define VT100ID "\033[?1;2c"
  #define VT102ID "\033[?6c"
  
! static char translations[3][257] = {
  /* 8-bit Latin-1 mapped to the PC charater set: '\0' means non-printable */
  	"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  	"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
***************
*** 250,260 ****
  	"\376\376\376\376\216\217\222\200\376\220\376\376\376\376\376\376"
  	"\376\245\376\376\376\376\231\376\376\376\376\376\232\376\376\341"
  	"\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213"
! 	"\376\244\225\242\223\376\224\366\376\227\243\226\201\376\376\230"
  };
  
  #define NORM_TRANS (translations[0])
  #define GRAF_TRANS (translations[1])
  
  static unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
  				       8,12,10,14, 9,13,11,15 };
--- 250,263 ----
  	"\376\376\376\376\216\217\222\200\376\220\376\376\376\376\376\376"
  	"\376\245\376\376\376\376\231\376\376\376\376\376\232\376\376\341"
  	"\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213"
! 	"\376\244\225\242\223\376\224\366\376\227\243\226\201\376\376\230",
! /* notranslations  */
! 	0
  };
  
  #define NORM_TRANS (translations[0])
  #define GRAF_TRANS (translations[1])
+ #define NULL_TRANS (translations[2])
  
  static unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
  				       8,12,10,14, 9,13,11,15 };
***************
*** 1157,1162 ****
--- 1160,1167 ----
  					G0_charset = GRAF_TRANS;
  				else if (c == 'B')
  					G0_charset = NORM_TRANS;
+ 				else if (c == 'U')
+ 					G0_charset = NULL_TRANS;
  				if (charset == 0)
  					translate = G0_charset;
  				state = ESnormal;
***************
*** 1166,1171 ****
--- 1171,1178 ----
  					G1_charset = GRAF_TRANS;
  				else if (c == 'B')
  					G1_charset = NORM_TRANS;
+ 				else if (c == 'U')
+ 					G1_charset = NULL_TRANS;
  				if (charset == 1)
  					translate = G1_charset;
  				state = ESnormal;
***************
*** 1232,1238 ****
--- 1239,1249 ----
  	long base;
  	int orig_x = ORIG_X;
  	int orig_y = ORIG_Y;
+ 	int i;
  
+ 	for (i=0; i<=256; i++)
+ 		translations[2][i] = i;
+ 	translations[2][27] = 0;
  	vc_scrmembuf = (unsigned short *) kmem_start;
  	video_num_columns = ORIG_VIDEO_COLS;
  	video_size_row = video_num_columns * 2;
***************
*** 1425,1443 ****
  
  int do_screendump(int arg)
  {
! 	char *sptr, *buf = (char *)arg;
! 	int currcons, l;
  
! 	verify_area(buf,2+video_num_columns*video_num_lines);
! 	currcons = get_fs_byte(buf+1);
  	if ((currcons<0) || (currcons>=NR_CONSOLES))
  		return -EIO;
- 	put_fs_byte((char)(video_num_lines),buf++);	
- 	put_fs_byte((char)(video_num_columns),buf++);
  	currcons = (currcons ? currcons-1 : fg_console);
! 	sptr = (char *) origin;
! 	for (l=video_num_lines*video_num_columns; l>0 ; l--, sptr++)
! 		put_fs_byte(*sptr++,buf++);	
  	return(0);
  }
  
--- 1436,1483 ----
  
  int do_screendump(int arg)
  {
! 	char *sptr, *buf = (char *)(arg);
! 	int row, col,len;
! 	int currcons, l, n, op;
  
! 	op = (int)get_fs_byte((char *)arg);
! 	if (op == 0)
! 	{
! 		currcons = (int)get_fs_byte(buf+1);
! 		row = 0; 
! 		col = 0;
! 		len = video_num_lines*video_num_columns*2;
! 		put_fs_byte((char)(video_num_lines),buf);	
! 		put_fs_byte((char)(video_num_columns),buf+1);
! 		buf += 2;
! 	}
! 	else
! 	{
! 		verify_area(buf,6);
! 		currcons = (int)get_fs_byte(buf+1);
! 		row = (int)get_fs_byte(buf+2);
! 		col = (int)get_fs_byte(buf+3);
! 		len = (int)get_fs_word((unsigned short *)(buf+4));
! 		buf += 6;
! 	}
! 	verify_area(buf,len);
  	if ((currcons<0) || (currcons>=NR_CONSOLES))
  		return -EIO;
  	currcons = (currcons ? currcons-1 : fg_console);
! 	n = (2*(col+video_num_columns*row));
! 	if ((n<0) || ((n+len)>(video_num_lines*video_num_columns*2)))
! 		return -EIO;
! 	sptr = ((char *)origin) + n;
! 	if (op == 2)  /* write to screen */
! 		for (l=len; l>0 ; l--)
! 			*sptr++ = get_fs_byte(buf++);	
! 	else
! 	if (op == 3)
! 		for (l=len; l>0 ; l--)  /* read from screen */
! 			put_fs_byte(*sptr++,buf++);	
! 	else
! 		for (l=len/2; l>0 ; l--, sptr++)  /* dump just text of screen */
! 			put_fs_byte(*sptr++,buf++);	
  	return(0);
  }
  
*** kernel/chr_drv/tty_ioctl.c.sa	Sat Jan 11 00:59:51 1992
--- kernel/chr_drv/tty_ioctl.c	Mon Jun 29 08:17:35 1992
***************
*** 376,381 ****
--- 376,383 ----
  			switch (get_fs_byte((char *)arg))
  			{
  				case 0: 
+ 				case 2: 
+ 				case 3: 
  					return do_screendump(arg);
  				case 1: 
  					return do_get_ps_info(arg);
----testext.c----------------------------------------------------------

#include < unistd.h>
#include < stdio.h>
#include < stdlib.h>
#include < termios.h>

int checkonvc(void);

/* Load the vc screen with the image with the image in buf+10, starting at
   row and col, and continuing for len bytes. Len is even cause one char is 
   two bytes  because of the attribute.  No conversion on chars is done, so 
   in effect, this is a direct screen write (just like in dos), except
   that virtual consoles are honored, so blanked ones work to.  A 
   VC = -1 implies use the one the program was executed from. 
   Remember, first 10 bytes of buf are reserved.
*/
int directcreenwrite(int vc, int row, int col, int len, char buf[])
{
	char *sb;
	if (vc == -1)
		vc = checkonvc();
	sb = buf+4;
	sb[0] = 2;  /* screen write */
	sb[1] = vc; /* VC num, zero means currently active VC. */
	sb[2] = row; /* Starting row */
	sb[3] = col; /* Starting col */
	*((short *)(sb+4)) = len; /* length in bytes (should be even cause of attr) */
	if (ioctl(0,TIOCLINUX,sb)<0)
		fprintf(stderr,"can not ioctl screenwrite\n");
	return(0);
}

/* Read an area of the screen into buf+10, starting at row and col, and 
   continuing for len bytes.  Remember, first 10 bytes of buf are reserved.
*/
int directcreenread(int vc, int row, int col, int len, char buf[])
{
	char *sb;
	if (vc == -1)
		vc = checkonvc();
	sb = buf+4;
	sb[0] = 3;  /* screen read */
	sb[1] = vc; /* VC num, zero means currently active VC. */
	sb[2] = row; /* Starting row */
	sb[3] = col; /* Starting col */
	*((short *)(sb+4)) = len; /* length in bytes (should be even cause of attr) */
	if (ioctl(0,TIOCLINUX,sb)<0)
		fprintf(stderr,"can not ioctl screenread\n");
}

/**************************************************************************************/
/* Some code to test the above. */


void rowfill(int len,char chr,char attr, char begin, char end, char *buf) 
{	int j; 
	for (j=0; j< len; j++, j++) 
	{  buf[j+10] = chr;  buf[j+11] = attr;  } 
	buf[10] = begin;  buf[len+8] = end;
}

popmenu(int row, int col, int length,int height, char backattr)
{
	char buf[1000];
	int i;
	length *= 2;
	rowfill(length, 205, backattr, 201, 187, buf);
	directcreenwrite(-1, row, col, length, buf);
	for (i=1; i<(height-1); i++)
	{
		rowfill(length, 176, backattr, 186, 186, buf);
		directcreenwrite(-1, row+i, col, length, buf);
	}
	rowfill(length, 205, backattr, 200, 188, buf);
	directcreenwrite(-1, row+i, col, length, buf);
	
}

saveunder(int row, int col, int length,int height, char buf[])
{
	int i;
	length *= 2;
	for (i=height-1; i>=0; i--)
	{
		directcreenread(-1, row+i, col, length, buf+10+i*length);
	}
	
}

restoreunder(int row, int col, int length,int height, char buf[])
{
	int i;
	length *= 2;
	for (i=0; i< height; i++)
	{
		directcreenwrite(-1, row+i, col, length, buf+10+i*length);
	}
	
}

/* Direct screen access from anywhere but the console make no sense. */
int checkonvc(void)
{	
	int vc;
	char *tt = ttyname(0);
	if (!strncmp(tt,"/dev/tty",8))
		vc = atoi(tt+8);
	if ((vc <= 0) || (vc >= 10))
	{
		puts("error: must be on console to use direct screen access");
		return(-1);
	}
	return(vc);
}		

main()
{
	char buf[10000];
	/* Use direct screen write */
	saveunder(10, 10, 30, 10, buf);
	popmenu(10, 10, 30, 10, 67);
	sleep(3);
	restoreunder(10, 10, 30, 10, buf);
	
	/* Now display some untranslated chars via console driver. */
	printf("%c(U%c%c%c%c%c(B", 27,187,201,200,188,27);
}