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