xref: /netbsd-src/sys/dev/rcons/rcons_subr.c (revision 3b01aba77a7a698587faaae455bbfe740923c1f5)
1 /*	$NetBSD: rcons_subr.c,v 1.7 2000/04/16 21:49:49 pk 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 	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