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