Home | History | Annotate | Line # | Download | only in rcons
rcons_subr.c revision 1.10.8.1
      1 /*	$NetBSD: rcons_subr.c,v 1.10.8.1 2002/07/15 10:35:54 gehenna Exp $ */
      2 
      3 /*
      4  * Copyright (c) 1991, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * This software was developed by the Computer Systems Engineering group
      8  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
      9  * contributed to Berkeley.
     10  *
     11  * All advertising materials mentioning features or use of this software
     12  * must display the following acknowledgement:
     13  *	This product includes software developed by the University of
     14  *	California, Lawrence Berkeley Laboratory.
     15  *
     16  * Redistribution and use in source and binary forms, with or without
     17  * modification, are permitted provided that the following conditions
     18  * are met:
     19  * 1. Redistributions of source code must retain the above copyright
     20  *    notice, this list of conditions and the following disclaimer.
     21  * 2. Redistributions in binary form must reproduce the above copyright
     22  *    notice, this list of conditions and the following disclaimer in the
     23  *    documentation and/or other materials provided with the distribution.
     24  * 3. All advertising materials mentioning features or use of this software
     25  *    must display the following acknowledgement:
     26  *	This product includes software developed by the University of
     27  *	California, Berkeley and its contributors.
     28  * 4. Neither the name of the University nor the names of its contributors
     29  *    may be used to endorse or promote products derived from this software
     30  *    without specific prior written permission.
     31  *
     32  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     33  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     34  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     35  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     36  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     40  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     41  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     42  * SUCH DAMAGE.
     43  *
     44  *	@(#)rcons_subr.c	8.1 (Berkeley) 6/11/93
     45  */
     46 
     47 #include <sys/cdefs.h>
     48 __KERNEL_RCSID(0, "$NetBSD: rcons_subr.c,v 1.10.8.1 2002/07/15 10:35:54 gehenna Exp $");
     49 
     50 #include <sys/param.h>
     51 #ifdef _KERNEL
     52 #include <sys/device.h>
     53 #include <sys/systm.h>
     54 #else
     55 #include "myfbdevice.h"
     56 #endif
     57 
     58 #include <dev/rcons/rcons.h>
     59 #include <dev/wscons/wsdisplayvar.h>
     60 
     61 extern void rcons_bell(struct rconsole *);
     62 
     63 #if 0
     64 #define RCONS_ISPRINT(c) ((((c) >= ' ') && ((c) <= '~')) || ((c) > 160))
     65 #else
     66 #define RCONS_ISPRINT(c) (((((c) >= ' ') && ((c) <= '~'))) || ((c) > 127))
     67 #endif
     68 #define RCONS_ISDIGIT(c) ((c) >= '0' && (c) <= '9')
     69 
     70 /* Initialize our operations set */
     71 void
     72 rcons_init_ops(rc)
     73 	struct rconsole *rc;
     74 {
     75 	long tmp;
     76 	int i, m;
     77 
     78 	m = sizeof(rc->rc_charmap) / sizeof(rc->rc_charmap[0]);
     79 
     80 	for (i = 0; i < m; i++)
     81 		rc->rc_ops->mapchar(rc->rc_cookie, i, rc->rc_charmap + i);
     82 
     83 	/* Determine which attributes the device supports. */
     84 #ifdef RASTERCONSOLE_FGCOL
     85 	rc->rc_deffgcolor = RASTERCONSOLE_FGCOL;
     86 #endif
     87 #ifdef RASTERCONSOLE_BGCOL
     88 	rc->rc_defbgcolor = RASTERCONSOLE_BGCOL;
     89 #endif
     90 	rc->rc_fgcolor = rc->rc_deffgcolor;
     91 	rc->rc_bgcolor = rc->rc_defbgcolor;
     92 	rc->rc_supwsflg = 0;
     93 
     94 	for (i = 1; i < 256; i <<= 1)
     95 		if (rc->rc_ops->allocattr(rc->rc_cookie, 0, 0, i, &tmp) == 0)
     96 			rc->rc_supwsflg |= i;
     97 
     98 	/* Allocate kernel output attribute */
     99 	rc->rc_wsflg = WSATTR_HILIT;
    100 	rcons_setcolor(rc, rc->rc_deffgcolor, rc->rc_defbgcolor);
    101 	rc->rc_kern_attr = rc->rc_attr;
    102 
    103 	rc->rc_wsflg = 0;
    104 	rcons_setcolor(rc, rc->rc_deffgcolor, rc->rc_defbgcolor);
    105 	rc->rc_defattr = rc->rc_attr;
    106 }
    107 
    108 /* Output (or at least handle) a string sent to the console */
    109 void
    110 rcons_puts(rc, str, n)
    111 	struct rconsole *rc;
    112 	unsigned char *str;
    113  	int n;
    114 {
    115 	int c, i, j;
    116 	unsigned char *cp;
    117 
    118 	/* Jump scroll */
    119 	/* XXX maybe this should be an option? */
    120 	if ((rc->rc_bits & FB_INESC) == 0) {
    121 		/* Count newlines up to an escape sequence */
    122 		i = 0;
    123 		j = 0;
    124 		for (cp = str; j++ < n && *cp != '\033'; ++cp) {
    125 			if (*cp == '\n')
    126 				++i;
    127 			else if (*cp == '\013')
    128 				--i;
    129 		}
    130 
    131 		/* Only jump scroll two or more rows */
    132 		if (rc->rc_row + i > rc->rc_maxrow + 1) {
    133 			/* Erase the cursor (if necessary) */
    134 			if (rc->rc_bits & FB_CURSOR)
    135 				rcons_cursor(rc);
    136 
    137 			rcons_scroll(rc, i);
    138 		}
    139 	}
    140 
    141 	/* Process characters */
    142 	while (--n >= 0) {
    143 		c = *str;
    144 		if (c == '\033') {
    145 			/* Start an escape (perhaps aborting one in progress) */
    146 			rc->rc_bits |= FB_INESC | FB_P0_DEFAULT | FB_P1_DEFAULT;
    147 			rc->rc_bits &= ~(FB_P0 | FB_P1);
    148 
    149 			/* Most parameters default to 1 */
    150 			rc->rc_p0 = rc->rc_p1 = 1;
    151 		} else if (rc->rc_bits & FB_INESC) {
    152 			rcons_esc(rc, c);
    153 		} else {
    154 			/* Erase the cursor (if necessary) */
    155 			if (rc->rc_bits & FB_CURSOR)
    156 				rcons_cursor(rc);
    157 
    158 			/* Display the character */
    159 			if (RCONS_ISPRINT(c)) {
    160 				/* Try to output as much as possible */
    161 				j = rc->rc_maxcol - rc->rc_col;
    162 				if (j > n)
    163 					j = n;
    164 				for (i = 1; i < j && RCONS_ISPRINT(str[i]); ++i)
    165 					continue;
    166 				rcons_text(rc, str, i);
    167 				--i;
    168 				str += i;
    169 				n -= i;
    170 			} else
    171 				rcons_pctrl(rc, c);
    172 		}
    173 		++str;
    174 	}
    175 	/* Redraw the cursor (if necessary) */
    176 	if ((rc->rc_bits & FB_CURSOR) == 0)
    177 		rcons_cursor(rc);
    178 }
    179 
    180 
    181 /* Handle a control character sent to the console */
    182 void
    183 rcons_pctrl(rc, c)
    184 	struct rconsole *rc;
    185 	int c;
    186 {
    187 
    188 	switch (c) {
    189 	case '\r':	/* Carriage return */
    190 		rc->rc_col = 0;
    191 		break;
    192 
    193 	case '\b':	/* Backspace */
    194 		if (rc->rc_col > 0)
    195 			(rc->rc_col)--;
    196 		break;
    197 
    198 	case '\v':	/* Vertical tab */
    199 		if (rc->rc_row > 0)
    200 			(rc->rc_row)--;
    201 		break;
    202 
    203 	case '\f':	/* Formfeed */
    204 		rc->rc_row = rc->rc_col = 0;
    205 		rcons_clear2eop(rc);
    206 		break;
    207 
    208 	case '\n':	/* Linefeed */
    209 		(rc->rc_row)++;
    210 		if (rc->rc_row >= rc->rc_maxrow)
    211 			rcons_scroll(rc, 1);
    212 		break;
    213 
    214 	case '\a':	/* Bell */
    215 		rcons_bell(rc);
    216 		break;
    217 
    218 	case '\t':	/* Horizontal tab */
    219 		rc->rc_col = (rc->rc_col + 8) & ~7;
    220 		if (rc->rc_col >= rc->rc_maxcol)
    221 			rc->rc_col = rc->rc_maxcol;
    222 		break;
    223 	}
    224 }
    225 
    226 /* Handle the next character in an escape sequence */
    227 void
    228 rcons_esc(rc, c)
    229 	struct rconsole *rc;
    230 	int c;
    231 {
    232 
    233 	if (c == '[') {
    234 		/* Parameter 0 */
    235 		rc->rc_bits &= ~FB_P1;
    236 		rc->rc_bits |= FB_P0;
    237 	} else if (c == ';') {
    238 		/* Parameter 1 */
    239 		rc->rc_bits &= ~FB_P0;
    240 		rc->rc_bits |= FB_P1;
    241 	} else if (RCONS_ISDIGIT(c)) {
    242 		/* Add a digit to a parameter */
    243 		if (rc->rc_bits & FB_P0) {
    244 			/* Parameter 0 */
    245 			if (rc->rc_bits & FB_P0_DEFAULT) {
    246 				rc->rc_bits &= ~FB_P0_DEFAULT;
    247 				rc->rc_p0 = 0;
    248 			}
    249 			rc->rc_p0 *= 10;
    250 			rc->rc_p0 += c - '0';
    251 		} else if (rc->rc_bits & FB_P1) {
    252 			/* Parameter 1 */
    253 			if (rc->rc_bits & FB_P1_DEFAULT) {
    254 				rc->rc_bits &= ~FB_P1_DEFAULT;
    255 				rc->rc_p1 = 0;
    256 			}
    257 			rc->rc_p1 *= 10;
    258 			rc->rc_p1 += c - '0';
    259 		}
    260 	} else {
    261 		/* Erase the cursor (if necessary) */
    262 		if (rc->rc_bits & FB_CURSOR)
    263 			rcons_cursor(rc);
    264 
    265 		/* Process the completed escape sequence */
    266 		rcons_doesc(rc, c);
    267 		rc->rc_bits &= ~FB_INESC;
    268 	}
    269 }
    270 
    271 
    272 /* Handle an SGR (Select Graphic Rendition) escape */
    273 void
    274 rcons_sgresc(rc, c)
    275 	struct rconsole *rc;
    276 	int c;
    277 {
    278 
    279 	switch (c) {
    280 	/* Clear all attributes || End underline */
    281 	case 0:
    282 		rc->rc_wsflg = 0;
    283 		rc->rc_fgcolor = rc->rc_deffgcolor;
    284 		rc->rc_bgcolor = rc->rc_defbgcolor;
    285 		rc->rc_attr = rc->rc_defattr;
    286 		break;
    287 
    288 	/* ANSI foreground color */
    289 	case 30: case 31: case 32: case 33:
    290 	case 34: case 35: case 36: case 37:
    291 		rcons_setcolor(rc, c - 30, rc->rc_bgcolor);
    292 		break;
    293 
    294 	/* ANSI background color */
    295 	case 40: case 41: case 42: case 43:
    296 	case 44: case 45: case 46: case 47:
    297 		rcons_setcolor(rc, rc->rc_fgcolor, c - 40);
    298 		break;
    299 
    300 	/* Begin reverse */
    301 	case 7:
    302 		rc->rc_wsflg |= WSATTR_REVERSE;
    303 		rcons_setcolor(rc, rc->rc_fgcolor, rc->rc_bgcolor);
    304 		break;
    305 
    306 	/* Begin bold */
    307 	case 1:
    308 		rc->rc_wsflg |= WSATTR_HILIT;
    309 		rcons_setcolor(rc, rc->rc_fgcolor, rc->rc_bgcolor);
    310 		break;
    311 
    312 	/* Begin underline */
    313 	case 4:
    314 		rc->rc_wsflg |= WSATTR_UNDERLINE;
    315 		rcons_setcolor(rc, rc->rc_fgcolor, rc->rc_bgcolor);
    316 		break;
    317 	}
    318 }
    319 
    320 
    321 /* Process a complete escape sequence */
    322 void
    323 rcons_doesc(rc, c)
    324 	struct rconsole *rc;
    325 	int c;
    326 {
    327 
    328 #ifdef notdef
    329 	/* XXX add escape sequence to enable visual (and audible) bell */
    330 	rc->rc_bits = FB_VISBELL;
    331 #endif
    332 
    333 	switch (c) {
    334 
    335 	case '@':
    336 		/* Insert Character (ICH) */
    337 		rcons_insertchar(rc, rc->rc_p0);
    338 		break;
    339 
    340 	case 'A':
    341 		/* Cursor Up (CUU) */
    342 		rc->rc_row -= rc->rc_p0;
    343 		if (rc->rc_row < 0)
    344 			rc->rc_row = 0;
    345 		break;
    346 
    347 	case 'B':
    348 		/* Cursor Down (CUD) */
    349 		rc->rc_row += rc->rc_p0;
    350 		if (rc->rc_row >= rc->rc_maxrow)
    351 			rc->rc_row = rc->rc_maxrow - 1;
    352 		break;
    353 
    354 	case 'C':
    355 		/* Cursor Forward (CUF) */
    356 		rc->rc_col += rc->rc_p0;
    357 		if (rc->rc_col >= rc->rc_maxcol)
    358 			rc->rc_col = rc->rc_maxcol - 1;
    359 		break;
    360 
    361 	case 'D':
    362 		/* Cursor Backward (CUB) */
    363 		rc->rc_col -= rc->rc_p0;
    364 		if (rc->rc_col < 0)
    365 			rc->rc_col = 0;
    366 		break;
    367 
    368 	case 'E':
    369 		/* Cursor Next Line (CNL) */
    370 		rc->rc_col = 0;
    371 		rc->rc_row += rc->rc_p0;
    372 		if (rc->rc_row >= rc->rc_maxrow)
    373 			rc->rc_row = rc->rc_maxrow - 1;
    374 		break;
    375 
    376 	case 'f':
    377 		/* Horizontal And Vertical Position (HVP) */
    378 	case 'H':
    379 		/* Cursor Position (CUP) */
    380 		rc->rc_col = rc->rc_p1 - 1;
    381 		if (rc->rc_col < 0)
    382 			rc->rc_col = 0;
    383 		else if (rc->rc_col >= rc->rc_maxcol)
    384 			rc->rc_col = rc->rc_maxcol - 1;
    385 
    386 		rc->rc_row = rc->rc_p0 - 1;
    387 		if (rc->rc_row < 0)
    388 			rc->rc_row = 0;
    389 		else if (rc->rc_row >= rc->rc_maxrow)
    390 			rc->rc_row = rc->rc_maxrow - 1;
    391 		break;
    392 
    393 	case 'J':
    394 		/* Erase in Display (ED) */
    395 		rcons_clear2eop(rc);
    396 		break;
    397 
    398 	case 'K':
    399 		/* Erase in Line (EL) */
    400 		rcons_clear2eol(rc);
    401 		break;
    402 
    403 	case 'L':
    404 		/* Insert Line (IL) */
    405 		rcons_insertline(rc, rc->rc_p0);
    406 		break;
    407 
    408 	case 'M':
    409 		/* Delete Line (DL) */
    410 		rcons_delline(rc, rc->rc_p0);
    411 		break;
    412 
    413 	case 'P':
    414 		/* Delete Character (DCH) */
    415 		rcons_delchar(rc, rc->rc_p0);
    416 		break;
    417 
    418 	case 'm':
    419 		/* Select Graphic Rendition (SGR) */
    420 		/* (defaults to zero) */
    421 		if (rc->rc_bits & FB_P0_DEFAULT)
    422 			rc->rc_p0 = 0;
    423 
    424 		if (rc->rc_bits & FB_P1_DEFAULT)
    425 			rc->rc_p1 = 0;
    426 
    427 		rcons_sgresc(rc, rc->rc_p0);
    428 
    429 		if (rc->rc_bits & FB_P1)
    430 			rcons_sgresc(rc, rc->rc_p1);
    431 
    432 		break;
    433 
    434 	/*
    435 	 * XXX: setting SUNBOW and SUNWOB should probably affect
    436 	 * deffgcolor, defbgcolor and defattr too.
    437 	 */
    438 	case 'p':
    439 		/* Black On White (SUNBOW) */
    440 		rcons_setcolor(rc, WSCOL_BLACK, WSCOL_WHITE);
    441 		break;
    442 
    443 	case 'q':
    444 		/* White On Black (SUNWOB) */
    445 		rcons_setcolor(rc, WSCOL_WHITE, WSCOL_BLACK);
    446 		break;
    447 
    448 	case 'r':
    449 		/* Set scrolling (SUNSCRL) */
    450 		/* (defaults to zero) */
    451 		if (rc->rc_bits & FB_P0_DEFAULT)
    452 			rc->rc_p0 = 0;
    453 		/* XXX not implemented yet */
    454 		rc->rc_scroll = rc->rc_p0;
    455 		break;
    456 
    457 	case 's':
    458 		/* Reset terminal emulator (SUNRESET) */
    459 		rc->rc_wsflg = 0;
    460 		rc->rc_scroll = 0;
    461 		rc->rc_bits &= ~FB_NO_CURSOR;
    462 		rc->rc_fgcolor = rc->rc_deffgcolor;
    463 		rc->rc_bgcolor = rc->rc_defbgcolor;
    464 		rc->rc_attr = rc->rc_defattr;
    465 
    466 		if (rc->rc_bits & FB_INVERT)
    467 			rcons_invert(rc, 0);
    468 		break;
    469 #ifdef notyet
    470 	/*
    471 	 * XXX following two read \E[?25h and \E[?25l. rcons
    472 	 * can't currently handle the '?'.
    473 	 */
    474 	case 'h':
    475 		/* Normal/very visible cursor */
    476 		if (rc->rc_p0 == 25) {
    477 			rc->rc_bits &= ~FB_NO_CURSOR;
    478 
    479 			if (rc->rc_bits & FB_CURSOR) {
    480 				rc->rc_bits ^= FB_CURSOR;
    481 				rcons_cursor(rc);
    482 			}
    483 		}
    484 		break;
    485 
    486 	case 'l':
    487 		/* Invisible cursor */
    488 		if (rc->rc_p0 == 25 && (rc->rc_bits & FB_NO_CURSOR) == 0) {
    489 			if (rc->rc_bits & FB_CURSOR)
    490 				rcons_cursor(rc);
    491 
    492 			rc->rc_bits |= FB_NO_CURSOR;
    493 		}
    494 		break;
    495 #endif
    496 	}
    497 }
    498 
    499 /* Set ANSI colors */
    500 void
    501 rcons_setcolor(rc, fg, bg)
    502 	struct rconsole *rc;
    503 	int fg, bg;
    504 {
    505 	int flg;
    506 
    507 	if (fg > WSCOL_WHITE || fg < 0)
    508 		return;
    509 
    510 	if (bg > WSCOL_WHITE || bg < 0)
    511 		return;
    512 
    513 #ifdef RASTERCONS_WONB
    514 	flg = bg;
    515 	bg = fg;
    516 	fg = flg;
    517 #endif
    518 
    519 	/* Emulate WSATTR_REVERSE attribute if it's not supported */
    520 	if ((rc->rc_wsflg & WSATTR_REVERSE) &&
    521 	    !(rc->rc_supwsflg & WSATTR_REVERSE)) {
    522 		flg = bg;
    523 		bg = fg;
    524 		fg = flg;
    525 	}
    526 
    527 	/*
    528 	 * Mask out unsupported flags and get attribute
    529 	 * XXX - always ask for WSCOLORS if supported (why shouldn't we?)
    530 	 */
    531 	flg = (rc->rc_wsflg | WSATTR_WSCOLORS) & rc->rc_supwsflg;
    532 	rc->rc_bgcolor = bg;
    533 	rc->rc_fgcolor = fg;
    534 	rc->rc_ops->allocattr(rc->rc_cookie, fg, bg, flg, &rc->rc_attr);
    535 }
    536 
    537 
    538 /* Actually write a string to the frame buffer */
    539 void
    540 rcons_text(rc, str, n)
    541 	struct rconsole *rc;
    542 	unsigned char *str;
    543 	int n;
    544 {
    545 	u_int uc;
    546 
    547 	while (n--) {
    548 		uc = rc->rc_charmap[*str++ & 255];
    549 		rc->rc_ops->putchar(rc->rc_cookie, rc->rc_row, rc->rc_col++,
    550 		    uc, rc->rc_attr);
    551 	}
    552 
    553 	if (rc->rc_col >= rc->rc_maxcol) {
    554 		rc->rc_col = 0;
    555 		rc->rc_row++;
    556 	}
    557 
    558 	if (rc->rc_row >= rc->rc_maxrow)
    559 		rcons_scroll(rc, 1);
    560 }
    561 
    562 /* Paint (or unpaint) the cursor */
    563 void
    564 rcons_cursor(rc)
    565 	struct rconsole *rc;
    566 {
    567 	rc->rc_bits ^= FB_CURSOR;
    568 
    569 	if (rc->rc_bits & FB_NO_CURSOR)
    570 		return;
    571 
    572 	rc->rc_ops->cursor(rc->rc_cookie, rc->rc_bits & FB_CURSOR,
    573 	    rc->rc_row, rc->rc_col);
    574 }
    575 
    576 /* Possibly change to SUNWOB or SUNBOW mode */
    577 void
    578 rcons_invert(rc, wob)
    579 	struct rconsole *rc;
    580 	int wob;
    581 {
    582 
    583 	rc->rc_bits ^= FB_INVERT;
    584 	/* XXX how do we do we invert the framebuffer?? */
    585 }
    586 
    587 /* Clear to the end of the page */
    588 void
    589 rcons_clear2eop(rc)
    590 	struct rconsole *rc;
    591 {
    592 	if (rc->rc_col || rc->rc_row) {
    593 		rcons_clear2eol(rc);
    594 
    595 		if (rc->rc_row < (rc->rc_maxrow - 1))
    596 			rc->rc_ops->eraserows(rc->rc_cookie, rc->rc_row + 1,
    597 			    rc->rc_maxrow, rc->rc_attr);
    598 	} else
    599 		rc->rc_ops->eraserows(rc->rc_cookie, 0, rc->rc_maxrow,
    600 		    rc->rc_attr);
    601 }
    602 
    603 /* Clear to the end of the line */
    604 void
    605 rcons_clear2eol(rc)
    606 	struct rconsole *rc;
    607 {
    608 	rc->rc_ops->erasecols(rc->rc_cookie, rc->rc_row, rc->rc_col,
    609 	    rc->rc_maxcol - rc->rc_col, rc->rc_attr);
    610 }
    611 
    612 
    613 /* Scroll up */
    614 void
    615 rcons_scroll(rc, n)
    616 	struct rconsole *rc;
    617 	int n;
    618 {
    619 	/* Can't scroll more than the whole screen */
    620 	if (n > rc->rc_maxrow)
    621 		n = rc->rc_maxrow;
    622 
    623 	/* Calculate new row */
    624 	rc->rc_row -= n;
    625 
    626 	if (rc->rc_row < 0)
    627 		rc->rc_row = 0;
    628 
    629 	rc->rc_ops->copyrows(rc->rc_cookie, n, 0, rc->rc_maxrow - n);
    630 	rc->rc_ops->eraserows(rc->rc_cookie, rc->rc_maxrow - n, n,  rc->rc_attr);
    631 }
    632 
    633 /* Delete characters */
    634 void
    635 rcons_delchar(rc, n)
    636 	struct rconsole *rc;
    637 	int n;
    638 {
    639 	/* Can't delete more chars than there are */
    640 	if (n > rc->rc_maxcol - rc->rc_col)
    641 		n = rc->rc_maxcol - rc->rc_col;
    642 
    643 	rc->rc_ops->copycols(rc->rc_cookie, rc->rc_row, rc->rc_col + n,
    644 	    rc->rc_col, rc->rc_maxcol - rc->rc_col - n);
    645 
    646 	rc->rc_ops->erasecols(rc->rc_cookie, rc->rc_row,
    647 	    rc->rc_maxcol - n, n, rc->rc_attr);
    648 }
    649 
    650 /* Delete a number of lines */
    651 void
    652 rcons_delline(rc, n)
    653 	struct rconsole *rc;
    654 	int n;
    655 {
    656 	/* Can't delete more lines than there are */
    657 	if (n > rc->rc_maxrow - rc->rc_row)
    658 		n = rc->rc_maxrow - rc->rc_row;
    659 
    660 	rc->rc_ops->copyrows(rc->rc_cookie, rc->rc_row + n, rc->rc_row,
    661 	    rc->rc_maxrow - rc->rc_row - n);
    662 
    663 	rc->rc_ops->eraserows(rc->rc_cookie, rc->rc_maxrow - n, n,
    664 	    rc->rc_attr);
    665 }
    666 
    667 /* Insert some characters */
    668 void
    669 rcons_insertchar(rc, n)
    670 	struct rconsole *rc;
    671 	int n;
    672 {
    673 	/* Can't insert more chars than can fit */
    674 	if (n > rc->rc_maxcol - rc->rc_col)
    675 		n = rc->rc_maxcol - rc->rc_col - 1;
    676 
    677 	rc->rc_ops->copycols(rc->rc_cookie, rc->rc_row, rc->rc_col,
    678 	    rc->rc_col + n, rc->rc_maxcol - rc->rc_col - n - 1);
    679 
    680 	rc->rc_ops->erasecols(rc->rc_cookie, rc->rc_row, rc->rc_col,
    681 	    n, rc->rc_attr);
    682 }
    683 
    684 /* Insert some lines */
    685 void
    686 rcons_insertline(rc, n)
    687 	struct rconsole *rc;
    688 	int n;
    689 {
    690 	/* Can't insert more lines than can fit */
    691 	if (n > rc->rc_maxrow - rc->rc_row)
    692 		n = rc->rc_maxrow - rc->rc_row;
    693 
    694 	rc->rc_ops->copyrows(rc->rc_cookie, rc->rc_row, rc->rc_row + n,
    695 	    rc->rc_maxrow - rc->rc_row - n);
    696 
    697 	rc->rc_ops->eraserows(rc->rc_cookie, rc->rc_row, n,
    698 	    rc->rc_attr);
    699 }
    700 
    701 /* end of rcons_subr.c */
    702