1/*-
2 * Copyright (c) 1992, 1993, 1994
3 *	The Regents of the University of California.  All rights reserved.
4 * Copyright (c) 1992, 1993, 1994, 1995, 1996
5 *	Keith Bostic.  All rights reserved.
6 *
7 * See the LICENSE file for redistribution information.
8 */
9
10#include "config.h"
11
12#include <sys/types.h>
13#include <sys/queue.h>
14#include <sys/time.h>
15
16#include <bitstring.h>
17#include <limits.h>
18#include <stdio.h>
19
20#include "../common/common.h"
21#include "vi.h"
22
23/*
24 * v_z -- [count]z[count][-.+^<CR>]
25 *	Move the screen.
26 *
27 * PUBLIC: int v_z(SCR *, VICMD *);
28 */
29int
30v_z(SCR *sp, VICMD *vp)
31{
32	recno_t lno;
33	e_key_t value;
34
35	/*
36	 * The first count is the line to use.  If the value doesn't
37	 * exist, use the last line.
38	 */
39	if (F_ISSET(vp, VC_C1SET)) {
40		lno = vp->count;
41		if (!db_exist(sp, lno) && db_last(sp, &lno))
42			return (1);
43	} else
44		lno = vp->m_start.lno;
45
46	/* Set default return cursor line. */
47	vp->m_final.lno = lno;
48	vp->m_final.cno = vp->m_start.cno;
49
50	/*
51	 * The second count is the displayed window size, i.e. the 'z' command
52	 * is another way to get artificially small windows.  Note, you can't
53	 * grow beyond the size of the window.
54	 *
55	 * !!!
56	 * A window size of 0 was historically allowed, and simply ignored.
57	 * This could be much more simply done by modifying the value of the
58	 * O_WINDOW option, but that's not how it worked historically.
59	 */
60	if (F_ISSET(vp, VC_C2SET) && vp->count2 != 0) {
61		if (vp->count2 > O_VAL(sp, O_WINDOW))
62			vp->count2 = O_VAL(sp, O_WINDOW);
63		if (vs_crel(sp, vp->count2))
64			return (1);
65	}
66
67	switch (vp->character) {
68	case '-':		/* Put the line at the bottom. */
69		if (vs_sm_fill(sp, lno, P_BOTTOM))
70			return (1);
71		break;
72	case '.':		/* Put the line in the middle. */
73		if (vs_sm_fill(sp, lno, P_MIDDLE))
74			return (1);
75		break;
76	case '+':
77		/*
78		 * If the user specified a line number, put that line at the
79		 * top and move the cursor to it.  Otherwise, scroll forward
80		 * a screen from the current screen.
81		 */
82		if (F_ISSET(vp, VC_C1SET)) {
83			if (vs_sm_fill(sp, lno, P_TOP))
84				return (1);
85			if (vs_sm_position(sp, &vp->m_final, 0, P_TOP))
86				return (1);
87		} else
88			if (vs_sm_scroll(sp, &vp->m_final, sp->t_rows, Z_PLUS))
89				return (1);
90		break;
91	case '^':
92		/*
93		 * If the user specified a line number, put that line at the
94		 * bottom, move the cursor to it, and then display the screen
95		 * before that one.  Otherwise, scroll backward a screen from
96		 * the current screen.
97		 *
98		 * !!!
99		 * Note, we match the off-by-one characteristics of historic
100		 * vi, here.
101		 */
102		if (F_ISSET(vp, VC_C1SET)) {
103			if (vs_sm_fill(sp, lno, P_BOTTOM))
104				return (1);
105			if (vs_sm_position(sp, &vp->m_final, 0, P_TOP))
106				return (1);
107			if (vs_sm_fill(sp, vp->m_final.lno, P_BOTTOM))
108				return (1);
109		} else
110			if (vs_sm_scroll(sp, &vp->m_final, sp->t_rows, Z_CARAT))
111				return (1);
112		break;
113	default:		/* Put the line at the top for <cr>. */
114		value = KEY_VAL(sp, vp->character);
115		if (value != K_CR && value != K_NL) {
116			v_emsg(sp, vp->kp->usage, VIM_USAGE);
117			return (1);
118		}
119		if (vs_sm_fill(sp, lno, P_TOP))
120			return (1);
121		break;
122	}
123	return (0);
124}
125
126/*
127 * vs_crel --
128 *	Change the relative size of the current screen.
129 *
130 * PUBLIC: int vs_crel(SCR *, long);
131 */
132int
133vs_crel(SCR *sp, long int count)
134{
135	sp->t_minrows = sp->t_rows = count;
136	if (sp->t_rows > sp->rows - 1)
137		sp->t_minrows = sp->t_rows = sp->rows - 1;
138	TMAP = HMAP + (sp->t_rows - 1);
139	F_SET(sp, SC_SCR_REDRAW);
140	return (0);
141}
142