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