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