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