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