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