schistory.c revision 48667
148104Syokota/*-
248104Syokota * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
348104Syokota * Copyright (c) 1992-1998 S�ren Schmidt
448104Syokota * All rights reserved.
548104Syokota *
648104Syokota * Redistribution and use in source and binary forms, with or without
748104Syokota * modification, are permitted provided that the following conditions
848104Syokota * are met:
948104Syokota * 1. Redistributions of source code must retain the above copyright
1048104Syokota *    notice, this list of conditions and the following disclaimer,
1148104Syokota *    without modification, immediately at the beginning of the file.
1248104Syokota * 2. Redistributions in binary form must reproduce the above copyright
1348104Syokota *    notice, this list of conditions and the following disclaimer in the
1448104Syokota *    documentation and/or other materials provided with the distribution.
1548104Syokota * 3. The name of the author may not be used to endorse or promote products
1648104Syokota *    derived from this software without specific prior written permission.
1748104Syokota *
1848104Syokota * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
1948104Syokota * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2048104Syokota * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2148104Syokota * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2248104Syokota * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2348104Syokota * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2448104Syokota * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2548104Syokota * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2648104Syokota * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2748104Syokota * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2848104Syokota *
2948667Syokota * $Id: schistory.c,v 1.1 1999/06/22 14:13:26 yokota Exp $
3048104Syokota */
3148104Syokota
3248104Syokota#include "sc.h"
3348104Syokota#include "opt_syscons.h"
3448104Syokota
3548104Syokota#if NSC > 0
3648104Syokota
3748104Syokota#ifndef SC_NO_HISTORY
3848104Syokota
3948104Syokota#include <sys/param.h>
4048104Syokota#include <sys/systm.h>
4148104Syokota#include <sys/tty.h>
4248104Syokota#include <sys/kernel.h>
4348104Syokota#include <sys/malloc.h>
4448104Syokota
4548104Syokota#include <machine/console.h>
4648104Syokota
4748104Syokota#include <dev/syscons/syscons.h>
4848104Syokota
4948104Syokota#if !defined(SC_MAX_HISTORY_SIZE)
5048104Syokota#define SC_MAX_HISTORY_SIZE	(1000 * MAXCONS * NSC)
5148104Syokota#endif
5248104Syokota
5348104Syokota#if !defined(SC_HISTORY_SIZE)
5448104Syokota#define SC_HISTORY_SIZE		(ROW * 4)
5548104Syokota#endif
5648104Syokota
5748104Syokota#if (SC_HISTORY_SIZE * MAXCONS * NSC) > SC_MAX_HISTORY_SIZE
5848104Syokota#undef SC_MAX_HISTORY_SIZE
5948104Syokota#define SC_MAX_HISTORY_SIZE	(SC_HISTORY_SIZE * MAXCONS * NSC)
6048104Syokota#endif
6148104Syokota
6248104Syokota/* local variables */
6348104Syokotastatic int		extra_history_size
6448104Syokota				= SC_MAX_HISTORY_SIZE - SC_HISTORY_SIZE*MAXCONS;
6548104Syokota
6648104Syokota/* local functions */
6748104Syokotastatic void history_to_screen(scr_stat *scp);
6848104Syokota
6948104Syokota/* allocate a history buffer */
7048104Syokotaint
7148667Syokotasc_alloc_history_buffer(scr_stat *scp, int lines, int prev_ysize, int wait)
7248104Syokota{
7348104Syokota	/*
7448104Syokota	 * syscons unconditionally allocates buffers upto
7548104Syokota	 * SC_HISTORY_SIZE lines or scp->ysize lines, whichever
7648104Syokota	 * is larger. A value greater than that is allowed,
7748104Syokota	 * subject to extra_history_size.
7848104Syokota	 */
7948104Syokota	sc_vtb_t *history;
8048667Syokota	sc_vtb_t *prev_history;
8148104Syokota	int cur_lines;				/* current buffer size */
8248104Syokota	int min_lines;				/* guaranteed buffer size */
8348667Syokota	int delta;				/* lines to put back */
8448104Syokota
8548104Syokota	if (lines <= 0)
8648104Syokota		lines = SC_HISTORY_SIZE;	/* use the default value */
8748667Syokota
8848667Syokota	/* make it at least as large as the screen size */
8948104Syokota	lines = imax(lines, scp->ysize);
9048104Syokota
9148667Syokota	/* remove the history buffer while we update it */
9248667Syokota	history = prev_history = scp->history;
9348104Syokota	scp->history = NULL;
9448667Syokota
9548667Syokota	/* calculate the amount of lines to put back to extra_history_size */
9648667Syokota	delta = 0;
9748667Syokota	if (prev_history) {
9848104Syokota		cur_lines = sc_vtb_rows(history);
9948667Syokota		min_lines = imax(SC_HISTORY_SIZE, prev_ysize);
10048104Syokota		if (cur_lines > min_lines)
10148667Syokota			delta = cur_lines - min_lines;
10248104Syokota	}
10348104Syokota
10448667Syokota	/* lines upto min_lines are always allowed. */
10548667Syokota	min_lines = imax(SC_HISTORY_SIZE, scp->ysize);
10648667Syokota	if (lines > min_lines) {
10748667Syokota		if (lines - min_lines > extra_history_size + delta) {
10848667Syokota			/* too many lines are requested */
10948667Syokota			scp->history = prev_history;
11048667Syokota			return EINVAL;
11148667Syokota		}
11248667Syokota	}
11348667Syokota
11448667Syokota	/* destroy the previous buffer and allocate a new one */
11548667Syokota	if (prev_history == NULL) {
11648667Syokota		history = (sc_vtb_t *)malloc(sizeof(*history),
11748667Syokota					     M_DEVBUF,
11848667Syokota					     (wait) ? M_WAITOK : M_NOWAIT);
11948667Syokota	} else {
12048667Syokota		extra_history_size += delta;
12148667Syokota		sc_vtb_destroy(prev_history);
12248667Syokota	}
12348667Syokota	if (history != NULL) {
12448667Syokota		if (lines > min_lines)
12548667Syokota			extra_history_size -= lines - min_lines;
12648104Syokota		sc_vtb_init(history, VTB_RINGBUFFER, scp->xsize, lines,
12748104Syokota			    NULL, wait);
12848667Syokota	}
12948667Syokota
13048104Syokota	scp->history_pos = 0;
13148104Syokota	scp->history = history;
13248104Syokota
13348104Syokota	return 0;
13448104Syokota}
13548104Syokota
13648667Syokotavoid
13748667Syokotasc_free_history_buffer(scr_stat *scp, int prev_ysize)
13848667Syokota{
13948667Syokota	sc_vtb_t *history;
14048667Syokota	int cur_lines;				/* current buffer size */
14148667Syokota	int min_lines;				/* guaranteed buffer size */
14248667Syokota
14348667Syokota	history = scp->history;
14448667Syokota	scp->history = NULL;
14548667Syokota	if (history == NULL)
14648667Syokota		return;
14748667Syokota
14848667Syokota	cur_lines = sc_vtb_rows(history);
14948667Syokota	min_lines = imax(SC_HISTORY_SIZE, prev_ysize);
15048667Syokota	extra_history_size += (cur_lines > min_lines) ? cur_lines - min_lines : 0;
15148667Syokota
15248667Syokota	sc_vtb_destroy(history);
15348667Syokota	free(history, M_DEVBUF);
15448667Syokota}
15548667Syokota
15648104Syokota/* copy entire screen into the top of the history buffer */
15748104Syokotavoid
15848104Syokotasc_hist_save(scr_stat *scp)
15948104Syokota{
16048104Syokota	sc_vtb_append(&scp->vtb, 0, scp->history, scp->xsize*scp->ysize);
16148104Syokota	scp->history_pos = sc_vtb_tail(scp->history);
16248104Syokota}
16348104Syokota
16448104Syokota/* restore the screen by copying from the history buffer */
16548104Syokotaint
16648104Syokotasc_hist_restore(scr_stat *scp)
16748104Syokota{
16848104Syokota	int ret;
16948104Syokota
17048104Syokota	if (scp->history_pos != sc_vtb_tail(scp->history)) {
17148104Syokota		scp->history_pos = sc_vtb_tail(scp->history);
17248104Syokota		history_to_screen(scp);
17348104Syokota		ret =  0;
17448104Syokota	} else {
17548104Syokota		ret = 1;
17648104Syokota	}
17748104Syokota	sc_vtb_seek(scp->history, sc_vtb_pos(scp->history,
17848104Syokota					     sc_vtb_tail(scp->history),
17948104Syokota					     -scp->xsize*scp->ysize));
18048104Syokota	return ret;
18148104Syokota}
18248104Syokota
18348104Syokota/* copy screen-full of saved lines */
18448104Syokotastatic void
18548104Syokotahistory_to_screen(scr_stat *scp)
18648104Syokota{
18748104Syokota	int pos;
18848104Syokota	int i;
18948104Syokota
19048104Syokota	pos = scp->history_pos;
19148104Syokota	for (i = 1; i <= scp->ysize; ++i) {
19248104Syokota		pos = sc_vtb_pos(scp->history, pos, -scp->xsize);
19348104Syokota		sc_vtb_copy(scp->history, pos,
19448104Syokota			    &scp->vtb, scp->xsize*(scp->ysize - i),
19548104Syokota			    scp->xsize);
19648104Syokota	}
19748104Syokota	mark_all(scp);
19848104Syokota}
19948104Syokota
20048104Syokota/* go to the tail of the history buffer */
20148104Syokotavoid
20248104Syokotasc_hist_home(scr_stat *scp)
20348104Syokota{
20448104Syokota	scp->history_pos = sc_vtb_tail(scp->history);
20548104Syokota	history_to_screen(scp);
20648104Syokota}
20748104Syokota
20848104Syokota/* go to the top of the history buffer */
20948104Syokotavoid
21048104Syokotasc_hist_end(scr_stat *scp)
21148104Syokota{
21248104Syokota	scp->history_pos = sc_vtb_pos(scp->history, sc_vtb_tail(scp->history),
21348104Syokota				      scp->xsize*scp->ysize);
21448104Syokota	history_to_screen(scp);
21548104Syokota}
21648104Syokota
21748104Syokota/* move one line up */
21848104Syokotaint
21948104Syokotasc_hist_up_line(scr_stat *scp)
22048104Syokota{
22148104Syokota	if (sc_vtb_pos(scp->history, scp->history_pos, -(scp->xsize*scp->ysize))
22248104Syokota	    == sc_vtb_tail(scp->history))
22348104Syokota		return -1;
22448104Syokota	scp->history_pos = sc_vtb_pos(scp->history, scp->history_pos,
22548104Syokota				      -scp->xsize);
22648104Syokota	history_to_screen(scp);
22748104Syokota	return 0;
22848104Syokota}
22948104Syokota
23048104Syokota/* move one line down */
23148104Syokotaint
23248104Syokotasc_hist_down_line(scr_stat *scp)
23348104Syokota{
23448104Syokota	if (scp->history_pos == sc_vtb_tail(scp->history))
23548104Syokota		return -1;
23648104Syokota	scp->history_pos = sc_vtb_pos(scp->history, scp->history_pos,
23748104Syokota				      scp->xsize);
23848104Syokota	history_to_screen(scp);
23948104Syokota	return 0;
24048104Syokota}
24148104Syokota
24248104Syokotaint
24348104Syokotasc_hist_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
24448104Syokota	      struct proc *p)
24548104Syokota{
24648104Syokota	scr_stat *scp;
24748667Syokota	int error;
24848104Syokota
24948104Syokota	switch (cmd) {
25048104Syokota
25148104Syokota	case CONS_HISTORY:  	/* set history size */
25248104Syokota		scp = sc_get_scr_stat(tp->t_dev);
25348104Syokota		if (*(int *)data <= 0)
25448104Syokota			return EINVAL;
25548104Syokota		if (scp->status & BUFFER_SAVED)
25648104Syokota			return EBUSY;
25748667Syokota		DPRINTF(5, ("lines:%d, ysize:%d, pool:%d\n",
25848667Syokota			    *(int *)data, scp->ysize, extra_history_size));
25948667Syokota		error = sc_alloc_history_buffer(scp,
26048104Syokota					       imax(*(int *)data, scp->ysize),
26148667Syokota					       scp->ysize, TRUE);
26248667Syokota		DPRINTF(5, ("error:%d, rows:%d, pool:%d\n", error,
26348667Syokota			    sc_vtb_rows(scp->history), extra_history_size));
26448667Syokota		return error;
26548104Syokota	}
26648104Syokota
26748104Syokota	return ENOIOCTL;
26848104Syokota}
26948104Syokota
27048104Syokota#endif /* SC_NO_HISTORY */
27148104Syokota
27248104Syokota#endif /* NSC */
273