patch-2.1.111 linux/drivers/char/console.c

Next file: linux/drivers/char/console_macros.h
Previous file: linux/drivers/char/bttv.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.110/linux/drivers/char/console.c linux/drivers/char/console.c
@@ -137,7 +137,6 @@
 		    unsigned int cols, int do_clear);
 static void blank_screen(void);
 static void unblank_screen(void);
-static void update_attr(int currcons);
 static void gotoxy(int currcons, int new_x, int new_y);
 static void save_cur(int currcons);
 static void reset_terminal(int currcons, int do_clear);
@@ -145,8 +144,6 @@
 
 static int printable = 0;		/* Is console ready for printing? */
 
-static unsigned short console_charmask = 0x0ff;
-
 int do_poke_blanked_console = 0;
 int console_blanked = 0;
 
@@ -191,12 +188,6 @@
 	return p;
 }
 
-/* FIXME: Can we do the whole scrollback logic here and call the driver
- *	  only for changing the display? Yes, there is some magic with
- *	  blanked screens, but we could unblank here. (Argh, there might
- *	  be some problems with unblanking since this is called from real
- *	  interrupts...)  --mj
- */
 static inline void scrolldelta(int lines)
 {
 	int currcons = fg_console;
@@ -226,7 +217,6 @@
 scrdown(int currcons, unsigned int t, unsigned int b, int nr)
 {
 	unsigned short *s;
-	unsigned int count;
 	unsigned int step;
 
 	if (t+nr >= b)
@@ -235,22 +225,68 @@
 		return;
 	if (IS_VISIBLE && sw->con_scroll(vc_cons[currcons].d, t, b, SM_DOWN, nr))
 		return;
-	s = (unsigned short *) (origin+video_size_row*(b-nr-1));
+	s = (unsigned short *) (origin+video_size_row*t);
 	step = video_num_columns * nr;
-	count = b - t - nr;
-	while (count--) {
-		scr_memcpyw(s + step, s, video_size_row);
-		s -= video_num_columns;
-	}
-	count = nr;
-	while (count--) {
-		s += video_num_columns;
-		scr_memsetw(s, video_erase_char, video_size_row);
+	scr_memmovew(s + step, s, (b-t-nr)*video_size_row);
+	scr_memsetw(s, video_erase_char, 2*step);
+}
+
+static void do_update_region(int currcons, unsigned long start, int count)
+{
+#ifndef VT_BUF_VRAM_ONLY
+	unsigned int xx, yy, offset;
+	u16 *p;
+
+	if (start < origin) {
+		count -= origin - start;
+		start = origin;
+	}
+	if (count <= 0)
+		return;
+	offset = (start - origin) / 2;
+	xx = offset % video_num_columns;
+	yy = offset / video_num_columns;
+	p = (u16 *) start;
+	for(;;) {
+		u16 attrib = scr_readw(p) & 0xff00;
+		int startx = xx;
+		u16 *q = p;
+		while (xx < video_num_columns && count) {
+			if (attrib != (scr_readw(p) & 0xff00)) {
+				if (p > q)
+					sw->con_putcs(vc_cons[currcons].d, q, p-q, yy, startx);
+				startx = xx;
+				q = p;
+				attrib = scr_readw(p) & 0xff00;
+			}
+			p++;
+			xx++;
+			count--;
+		}
+		if (p > q)
+			sw->con_putcs(vc_cons[currcons].d, q, p-q, yy, startx);
+		if (!count)
+			break;
+		xx = 0;
+		yy++;
 	}
+#endif
 }
 
-static void update_attr(int currcons)
+void update_region(int currcons, unsigned long start, int count)
+{
+	if (DO_UPDATE)
+		do_update_region(currcons, start, count);
+}
+
+/* Structure of attributes is hardware-dependent */
+
+static u8 build_attr(int currcons, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse)
 {
+	if (sw->con_build_attr)
+		return sw->con_build_attr(vc_cons[currcons].d, _color, _intensity, _blink, _underline, _reverse);
+
+#ifndef VT_BUF_VRAM_ONLY
 /*
  * ++roman: I completely changed the attribute format for monochrome
  * mode (!can_do_color). The formerly used MDA (monochrome display
@@ -260,74 +296,64 @@
  *  Bit 2   : underline
  *  Bit 3   : reverse
  *  Bit 7   : blink
- *
- * ++Geert: TODO: Because the attributes have different meanings
- * for monochrome and color, they should really be converted if
- * can_do_color changes...
- *
- * FIXME: Monochrome attributes on MDA/HGC/etc
  */
-	if (!can_do_color) {
-		/* Special treatment for monochrome */
-		attr = intensity |
-			(underline ? 4 : 0) |
-			((reverse ^ decscnm) ? 8 : 0) |
-			(blink ? 0x80 : 0);
-		video_erase_char = ' ' | ((reverse ^ decscnm) ? 0x800 : 0);
-		return;
-	}
-	attr = color;
-	if (can_do_color) {
-		if (underline)
-			attr = (attr & 0xf0) | ulcolor;
-		else if (intensity == 0)
-			attr = (attr & 0xf0) | halfcolor;
-	}
-	if (reverse ^ decscnm)
-		attr = reverse_video_char(attr);
-	if (blink)
-		attr ^= 0x80;
-	if (intensity == 2)
-		attr ^= 0x08;
-	if (decscnm)
-		video_erase_char = (reverse_video_char(color) << 8) | ' ';
-	else
-		video_erase_char = (color << 8) | ' ';
+	{
+	u8 a = color;
+	if (!can_do_color)
+		return _intensity |
+		       (_underline ? 4 : 0) |
+		       (_reverse ? 8 : 0) |
+		       (_blink ? 0x80 : 0);
+	if (_underline)
+		a = (a & 0xf0) | ulcolor;
+	else if (_intensity == 0)
+		a = (a & 0xf0) | halfcolor;
+	if (_reverse)
+		a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77);
+	if (_blink)
+		a ^= 0x80;
+	if (_intensity == 2)
+		a ^= 0x08;
+	return a;
+	}
+#else
+	return 0;
+#endif
+}
+
+static void update_attr(int currcons)
+{
+	attr = build_attr(currcons, color, intensity, blink, underline, reverse ^ decscnm);
+	video_erase_char = (build_attr(currcons, color, 1, 0, 0, decscnm) << 8) | ' ';
 }
 
 /* Note: inverting the screen twice should revert to the original state */
+
 void invert_screen(int currcons, int offset, int count, int viewed)
 {
 	unsigned short *p;
-	int xx = (offset >> 1) % video_num_columns;
-	int yy = (offset >> 1) / video_num_columns;
 
 	count /= 2;
 	p = screenpos(currcons, offset, viewed);
-	if (can_do_color)
-		while (count--) {
-			unsigned short old = scr_readw(p);
-			unsigned short new = reverse_video_short(old);
-			scr_writew(new, p);
-			p++;
-			if (DO_UPDATE) {
-				sw->con_putc(vc_cons[currcons].d, new, yy, xx);
-				if (++xx == video_num_columns)
-					xx = 0, ++yy;
-			}
-		}
-	else
-		while (count--) {
-			unsigned short old = scr_readw(p);
-			unsigned short new = reverse_video_short_mono(old);
-			scr_writew(new, p);
-			p++;
-			if (DO_UPDATE) {
-				sw->con_putc(vc_cons[currcons].d, new, yy, xx);
-				if (++xx == video_num_columns)
-					xx = 0, ++yy;
-			}
+	if (sw->con_invert_region)
+		sw->con_invert_region(vc_cons[currcons].d, p, count);
+#ifndef VT_BUF_VRAM_ONLY
+	else {
+		int col = can_do_color;
+		u16 *q = p;
+		int cnt = count;
+
+		while (cnt--) {
+			u16 a = *q;
+			if (col)
+				a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
+			else
+				a ^= 0x0800;
+			*q++ = a;
 		}
+	}
+#endif
+	update_region(currcons, (unsigned long) p, count);
 }
 
 /* used by selection: complement pointer position */
@@ -348,23 +374,16 @@
 		unsigned short new;
 		p = screenpos(currcons, offset, 1);
 		old = scr_readw(p);
-		oldx = (offset >> 1) % video_num_columns;
-		oldy = (offset >> 1) / video_num_columns;
-		new = complement_video_short(old);
+		new = old ^ complement_mask;
 		scr_writew(new, p);
-		if (DO_UPDATE)
+		if (DO_UPDATE) {
+			oldx = (offset >> 1) % video_num_columns;
+			oldy = (offset >> 1) / video_num_columns;
 			sw->con_putc(vc_cons[currcons].d, new, oldy, oldx);
+		}
 	}
 }
 
-/* used by selection - convert a screen word to a glyph number */
-int scrw2glyph(unsigned short scr_word)
-{
-	return ( video_mode_512ch )
-		? ((scr_word & 0x0800) >> 3) + (scr_word & 0x00ff)
-		: scr_word & 0x00ff;
-}
-
 static void insert_char(int currcons, unsigned int nr)
 {
 	unsigned short *p, *q = (unsigned short *) pos;
@@ -410,18 +429,45 @@
 	}
 }
 
-static inline void hide_cursor(int currcons)
+static int softcursor_original;
+
+static void add_softcursor(int currcons)
+{
+	int i = scr_readw((u16 *) pos);
+	u32 type = cursor_type;
+
+	if (softcursor_original != -1) return;
+	softcursor_original = i;
+	if (! (type & 0x10)) return;
+	i |= ((type >> 8) & 0xff00 );
+	i ^= ((type) & 0xff00 );
+	if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000;
+	if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700;
+	scr_writew(i, (u16 *) pos);
+	if (DO_UPDATE)
+		sw->con_putc(vc_cons[currcons].d, i, y, x);
+}
+
+static void hide_cursor(int currcons)
 {
-    sw->con_cursor(vc_cons[currcons].d,CM_ERASE);
+	if (softcursor_original != -1) {
+		scr_writew(softcursor_original,(u16 *) pos);
+		if (DO_UPDATE)
+			sw->con_putc(vc_cons[currcons].d, softcursor_original, y, x);
+		softcursor_original = -1;
+	}
+	sw->con_cursor(vc_cons[currcons].d,CM_ERASE);
 }
 
 void set_cursor(int currcons)
 {
     if (!IS_FG || console_blanked || vcmode == KD_GRAPHICS)
 	return;
-    if (deccm)
-	sw->con_cursor(vc_cons[currcons].d,CM_DRAW);
-    else
+    if (deccm) {
+	add_softcursor(currcons);
+	if ((cursor_type & 0x0f) != 1)
+	    sw->con_cursor(vc_cons[currcons].d,CM_DRAW);
+    } else
 	hide_cursor(currcons);
 }
 
@@ -451,8 +497,7 @@
 {
 	int currcons = fg_console;
 	int redraw = 1;
-	int xx, yy, startx, attrib, old_console;
-	unsigned short *p, *q;
+	int old_console;
 	static int lock = 0;
 	struct vc_data **display;
 
@@ -482,30 +527,11 @@
 	}
 	if (redraw) {
 		set_origin(currcons);
-		if (sw->con_switch (vc_cons[currcons].d)) {
+		if (sw->con_switch(vc_cons[currcons].d))
 			/* Update the screen contents */
-			p = (unsigned short *)origin;
-			attrib = scr_readw(p) & 0xff00;
-			for (yy = 0; yy < video_num_lines; yy++) {
-				q = p;
-				for (startx = xx = 0; xx < video_num_columns; xx++) {
-					if (attrib != (scr_readw(p) & 0xff00)) {
-						if (p > q)
-							sw->con_putcs (vc_cons[currcons].d, q,
-								       p - q, yy, startx);
-						startx = xx;
-						q = p;
-						attrib = (scr_readw(p) & 0xff00);
-					}
-					p++;
-				}
-				if (p > q)
-					sw->con_putcs (vc_cons[currcons].d, q,
-						       p - q, yy, startx);
-			}
-		}
+			do_update_region(currcons, origin, screenbuf_size/2);
 	}
-	set_cursor (currcons);
+	set_cursor(currcons);
 	set_leds();
 	compute_shiftstate();
 	lock = 0;
@@ -526,7 +552,11 @@
     sw = conswitchp;
     cons_num = currcons;
     display_fg = &master_display_fg;
+    hi_font_mask = 0;
+    complement_mask = 0;
     sw->con_init(vc_cons[currcons].d, 1);
+    if (!complement_mask)
+        complement_mask = can_do_color ? 0x7700 : 0x0800;
     video_size_row = video_num_columns<<1;
     video_screen_size = video_num_lines*video_size_row;
 }
@@ -577,17 +607,12 @@
  * [this is to be used together with some user program
  * like resize that changes the hardware videomode]
  */
-/* FIXME: Cursor sometimes disappears when resizing */
-/* FIXME: We could also take data from the scrollback buffer */
 int vc_resize(unsigned int lines, unsigned int cols,
 	      unsigned int first, unsigned int last)
 {
 	unsigned int cc, ll, ss, sr, todo = 0;
-	unsigned int occ, oll, oss, osr;
-	unsigned short *p;
 	unsigned int currcons = fg_console, i;
 	unsigned short *newscreens[MAX_NR_CONSOLES];
-	unsigned long ol, nl, rlth, rrem;
 
 	cc = (cols ? cols : video_num_columns);
 	ll = (lines ? lines : video_num_lines);
@@ -599,7 +624,7 @@
 		    (cc == video_num_columns && ll == video_num_lines))
 			newscreens[currcons] = NULL;
 		else {
-			p = (unsigned short *) kmalloc(ss, GFP_USER);
+			unsigned short *p = (unsigned short *) kmalloc(ss, GFP_USER);
 			if (!p) {
 				for (i = 0; i< currcons; i++)
 					if (newscreens[i])
@@ -614,6 +639,8 @@
 		return 0;
 
 	for (currcons = first; currcons <= last; currcons++) {
+		unsigned int occ, oll, oss, osr;
+		unsigned long ol, nl, nlend, rlth, rrem;
 		if (!newscreens[currcons] || !vc_cons_allocated(currcons))
 			continue;
 
@@ -631,10 +658,12 @@
 		rrem = sr - rlth;
 		ol = origin;
 		nl = (long) newscreens[currcons];
+		nlend = nl + ss;
 		if (ll < oll)
 			ol += (oll - ll) * osr;
 
 		update_attr(currcons);
+
 		while (ol < scr_end) {
 			scr_memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth);
 			if (rrem)
@@ -642,7 +671,8 @@
 			ol += osr;
 			nl += sr;
 		}
-
+		if (nlend > nl)
+			scr_memsetw((void *) nl, video_erase_char, nlend - nl);
 		if (kmalloced)
 			kfree_s(screenbuf, oss);
 		screenbuf = newscreens[currcons];
@@ -650,9 +680,6 @@
 		screenbuf_size = ss;
 		set_origin(currcons);
 
-		if (scr_end > nl)
-			scr_memsetw((void *) nl, video_erase_char, scr_end - nl);
-
 		/* do part of a reset_terminal() */
 		top = 0;
 		bottom = video_num_lines;
@@ -1111,7 +1138,6 @@
 				break;
 			case 25:		/* Cursor on/off */
 				deccm = on_off;
-				set_cursor(currcons);
 				break;
 			case 1000:
 				report_mouse = on_off ? 2 : 0;
@@ -1172,13 +1198,11 @@
 				bell_duration = DEFAULT_BELL_DURATION;
 			break;
 		case 12: /* bring specified console to the front */
-			/* FIXME: Use console_bh for switching! */
 			if (par[1] >= 1 && vc_cons_allocated(par[1]-1))
-				update_screen(par[1]-1);
+				set_console(par[1] - 1);
 			break;
 		case 13: /* unblank the screen */
-			/* FIXME: call poke_blanked_console? */
-			unblank_screen();
+			poke_blanked_console();
 			break;
 		case 14: /* set vesa powerdown interval */
 			vesa_off_interval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
@@ -1494,12 +1518,14 @@
 			set_mode(currcons,0);
 			return;
 		case 'c':
-			if (par[0])
-				cursor_type = par[0] | (par[1]<<8) | (par[2]<<16);
-			else
-				cursor_type = CUR_DEFAULT;
-			set_cursor(currcons);
-			return;
+			if (ques) {
+				if (par[0])
+					cursor_type = par[0] | (par[1]<<8) | (par[2]<<16);
+				else
+					cursor_type = CUR_DEFAULT;
+				return;
+			}
+			break;
 		case 'n':
 			if (!ques) {
 				if (par[0] == 5)
@@ -1698,6 +1724,7 @@
 	unsigned int currcons;
 	unsigned long draw_from = 0, draw_to = 0;
 	struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
+	u16 himask, charmask;
 
 #if CONFIG_AP1000
         ap_write(1,buf,count);
@@ -1721,8 +1748,11 @@
 			return 0; /* ?? are error codes legal here ?? */
 	}
 
+	himask = hi_font_mask;
+	charmask = himask ? 0x1ff : 0xff;
+
 	/* undraw cursor first */
-	if (DO_UPDATE)
+	if (IS_FG)
 		hide_cursor(currcons);
 
 	/* clear the selection */
@@ -1730,7 +1760,7 @@
 		clear_selection();
 
 	disable_bh(CONSOLE_BH);
-	while (count) {
+	while (!tty->stopped && count) {
 		enable_bh(CONSOLE_BH);
 		if (from_user)
 			__get_user(c, buf);
@@ -1810,7 +1840,7 @@
                                 /* Bad hash table -- hope for the best */
                                 tc = c;
                         }
-			if (tc & ~console_charmask)
+			if (tc & ~charmask)
                                 continue; /* Conversion failed */
 
 			if (need_wrap || decim)
@@ -1821,11 +1851,10 @@
 			}
 			if (decim)
 				insert_char(currcons, 1);
-			scr_writew(c = video_mode_512ch ?
-			   ((attr & 0xf7) << 8) + ((tc & 0x100) << 3) +
-			   (tc & 0x0ff) : (attr << 8) + tc,
-			   (unsigned short *) pos);
-
+			scr_writew(himask ?
+				     ((attr & ~himask) << 8) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
+				     (attr << 8) + tc,
+				   (u16 *) pos);
 			if (DO_UPDATE && draw_x < 0) {
 				draw_x = x;
 				draw_from = pos;
@@ -1862,6 +1891,7 @@
 	if (want_console >= 0) {
 		if (want_console != fg_console) {
 			clear_selection();
+			hide_cursor(fg_console);
 			save_screen();
 			change_console(want_console);
 			/* we only changed when the console had already
@@ -2364,6 +2394,7 @@
 void do_blank_screen(int nopowersave)
 {
 	int currcons = fg_console;
+	int i;
 
 	if (console_blanked)
 		return;
@@ -2395,8 +2426,11 @@
 	}
 
 	save_screen();
-	sw->con_blank(vc_cons[currcons].d, 1);
+	/* In case we need to reset origin, blanking hook returns 1 */
+	i = sw->con_blank(vc_cons[currcons].d, 1);
 	console_blanked = fg_console + 1;
+	if (i)
+		set_origin(currcons);
 
 	if(!nopowersave)
 	{
@@ -2523,85 +2557,80 @@
 /*
  *  Font switching
  *
- *  Currently we only support 8 pixels wide fonts, at a maximum height
- *  of 32 pixels. Userspace fontdata is stored with 32 bytes reserved
- *  for each character which is kinda wasty, but this is done in order
- *  to maintain compatibility with the EGA/VGA fonts. It is upto the
- *  actual low-level console-driver convert data into its favorite
+ *  Currently we only support fonts up to 32 pixels wide, at a maximum height
+ *  of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints, 
+ *  depending on width) reserved for each character which is kinda wasty, but 
+ *  this is done in order to maintain compatibility with the EGA/VGA fonts. It 
+ *  is upto the actual low-level console-driver convert data into its favorite
  *  format (maybe we should add a `fontoffset' field to the `display'
  *  structure so we wont have to convert the fontdata all the time.
  *  /Jes
  */
 
-#define cmapsz 8192
+#define max_font_size 32768
 
-int con_set_font (char *arg, int w, int h, int chars)
+int con_font_op(int currcons, struct console_font_op *op)
 {
-	int ch512;
-	int i = -EINVAL;
-	int s = cmapsz;
-	char *charmap;
+	int rc = -EINVAL;
+	int size, set;
+	u8 *temp;
+	struct console_font_op old_op;
 
-	if (vt_cons[fg_console]->vc_mode != KD_TEXT)
+	if (vt_cons[currcons]->vc_mode != KD_TEXT)
 		goto quit;
-	if (w != 8 || h < 0 || h >= 32)
-		goto quit;
-	if (chars == 256)
-		ch512 = 0;
-	else if (chars == 512) {
-		ch512 = 1;
-		s += s;
+	memcpy(&old_op, &op, sizeof(op));
+	if (op->op == KD_FONT_OP_SET) {
+		if (op->charcount > 512)
+			goto quit;
+		if (!op->height) {		/* Need to guess font height [compat] */
+			int h, i;
+			u8 *charmap = op->data, tmp;
+			rc = -EFAULT;
+			for (h = 32; h > 0; h--)
+				for (i = 0; i < op->charcount; i++) {
+					if (get_user(tmp, &charmap[32*i+h-1]))
+						goto quit;
+					if (tmp)
+						goto nonzero;
+				}
+			rc = -EINVAL;
+			goto quit;
+		nonzero:
+			rc = -EINVAL;
+			op->height = h;
+		}
+		if (op->width > 32 || op->height > 32)
+			goto quit;
+		size = (op->width+7)/8 * 32 * op->charcount;
+		if (size > max_font_size)
+			return -ENOSPC;
+		set = 1;
+	} else if (op->op == KD_FONT_OP_GET) {
+		size = max_font_size;
+		set = 0;
 	} else
-		goto quit;
-	s = ch512 ? 2*cmapsz : cmapsz;
-	charmap = kmalloc(s, GFP_USER);
-	if (!charmap)
+		return sw->con_font_op(vc_cons[currcons].d, op);
+	temp = kmalloc(size, GFP_KERNEL);
+	if (!temp)
 		return -ENOMEM;
-	i = -EFAULT;
-	if (copy_from_user(charmap, arg, s))
-		goto done;
-	if (!h) {			/* No height given, try guessing */
-		for (h = 32; h > 0; h--)
-			for (i = 0; i < chars; i++)
-				if (charmap[32*i+h-1])
-					goto nonzero;
-		return -EINVAL;		/* Empty fonts not allowed */
-	}
-	nonzero:
-	i = conswitchp->con_set_font(vc_cons[fg_console].d, w, h, charmap);
-	if ( !i ) {
-		hashtable_contents_valid = 0;
-		video_mode_512ch = ch512;
-		console_charmask = ch512 ? 0x1ff : 0x0ff;
-	}
-done:
-	kfree(charmap);
-quit:
-	return i;
-}
-
-int con_get_font (char *arg, int *w, int *h, int *chars)
-{
-	int num = video_mode_512ch ? 512 : 256;
-	char *charmap;
-	int s = video_mode_512ch ? 2*cmapsz : cmapsz;
-	int i;
-
-	if (num < *chars)
-		return -ENOSPC;
-	if (vt_cons[fg_console]->vc_mode != KD_TEXT)
-		return -EINVAL;
-	*chars = num;
-	*w = 8;
-	charmap = kmalloc(s, GFP_USER);
-	if (!charmap)
-		return -ENOMEM;
-	memset(charmap, 0, s);
-	i = conswitchp->con_get_font(vc_cons[fg_console].d, w, h, charmap);
-	if (!i && copy_to_user(arg, charmap, s))
-		i = -EINVAL;
-	kfree(charmap);
-	return i;
+	if (set && copy_from_user(temp, op->data, size)) {
+		rc = -EFAULT;
+		goto quit2;
+	}
+	op->data = temp;
+	rc = sw->con_font_op(vc_cons[currcons].d, op);
+	op->data = old_op.data;
+	if (!rc && !set) {
+		int c = (op->width+7)/8 * 32 * op->charcount;
+		if (op->width > old_op.width ||
+		    op->height > old_op.height ||
+		    op->charcount > old_op.charcount)
+			rc = -ENOSPC;
+		else if (copy_to_user(old_op.data, op->data, c))
+			rc = -EFAULT;
+	}
+quit2:	kfree_s(temp, size);
+quit:	return rc;
 }
 
 /*
@@ -2609,9 +2638,14 @@
  */
 
 /* used by selection */
-unsigned short screen_word(int currcons, int offset, int viewed)
+u16 screen_glyph(int currcons, int offset)
 {
-	return scr_readw(screenpos(currcons, offset, viewed));
+	u16 w = scr_readw(screenpos(currcons, offset, 1));
+	u16 c = w & 0xff;
+
+	if (w & hi_font_mask)
+		c |= 0x100;
+	return c;
 }
 
 /* used by vcs - note the word offset */

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov