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