source: trunk/third/nvi/vi/v_section.c @ 14302

Revision 14302, 6.3 KB checked in by ghudson, 25 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r14301, which included commits to RCS files with non-trunk default branches.
Line 
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
13static const char sccsid[] = "@(#)v_section.c   10.7 (Berkeley) 3/6/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#include <string.h>
24
25#include "../common/common.h"
26#include "vi.h"
27
28/*
29 * !!!
30 * In historic vi, the section commands ignored empty lines, unlike the
31 * paragraph commands, which was probably okay.  However, they also moved
32 * to the start of the last line when there where no more sections instead
33 * of the end of the last line like the paragraph commands.  I've changed
34 * the latter behavior to match the paragraph commands.
35 *
36 * In historic vi, a section was defined as the first character(s) of the
37 * line matching, which could be followed by anything.  This implementation
38 * follows that historic practice.
39 *
40 * !!!
41 * The historic vi documentation (USD:15-10) claimed:
42 *      The section commands interpret a preceding count as a different
43 *      window size in which to redraw the screen at the new location,
44 *      and this window size is the base size for newly drawn windows
45 *      until another size is specified.  This is very useful if you are
46 *      on a slow terminal ...
47 *
48 * I can't get the 4BSD vi to do this, it just beeps at me.  For now, a
49 * count to the section commands simply repeats the command.
50 */
51
52/*
53 * v_sectionf -- [count]]]
54 *      Move forward count sections/functions.
55 *
56 * !!!
57 * Using ]] as a motion command was a bit special, historically.  It could
58 * match } as well as the usual { and section values.  If it matched a { or
59 * a section, it did NOT include the matched line.  If it matched a }, it
60 * did include the line.  No clue why.
61 *
62 * PUBLIC: int v_sectionf __P((SCR *, VICMD *));
63 */
64int
65v_sectionf(sp, vp)
66        SCR *sp;
67        VICMD *vp;
68{
69        recno_t cnt, lno;
70        size_t len;
71        char *p, *list, *lp;
72
73        /* Get the macro list. */
74        if ((list = O_STR(sp, O_SECTIONS)) == NULL)
75                return (1);
76
77        /*
78         * !!!
79         * If the starting cursor position is at or before any non-blank
80         * characters in the line, i.e. the movement is cutting all of the
81         * line's text, the buffer is in line mode.  It's a lot easier to
82         * check here, because we know that the end is going to be the start
83         * or end of a line.
84         */
85        if (ISMOTION(vp))
86                if (vp->m_start.cno == 0)
87                        F_SET(vp, VM_LMODE);
88                else {
89                        vp->m_stop = vp->m_start;
90                        vp->m_stop.cno = 0;
91                        if (nonblank(sp, vp->m_stop.lno, &vp->m_stop.cno))
92                                return (1);
93                        if (vp->m_start.cno <= vp->m_stop.cno)
94                                F_SET(vp, VM_LMODE);
95                }
96
97        cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
98        for (lno = vp->m_start.lno; !db_get(sp, ++lno, 0, &p, &len);) {
99                if (len == 0)
100                        continue;
101                if (p[0] == '{' || ISMOTION(vp) && p[0] == '}') {
102                        if (!--cnt) {
103                                if (p[0] == '{')
104                                        goto adjust1;
105                                goto adjust2;
106                        }
107                        continue;
108                }
109                /*
110                 * !!!
111                 * Historic documentation (USD:15-11, 4.2) said that formfeed
112                 * characters (^L) in the first column delimited sections.
113                 * The historic code mentions formfeed characters, but never
114                 * implements them.  Seems reasonable, do it.
115                 */
116                if (p[0] == '\014') {
117                        if (!--cnt)
118                                goto adjust1;
119                        continue;
120                }
121                if (p[0] != '.' || len < 2)
122                        continue;
123                for (lp = list; *lp != '\0'; lp += 2 * sizeof(*lp))
124                        if (lp[0] == p[1] &&
125                            (lp[1] == ' ' && len == 2 || lp[1] == p[2]) &&
126                            !--cnt) {
127                                /*
128                                 * !!!
129                                 * If not cutting this line, adjust to the end
130                                 * of the previous one.  Otherwise, position to
131                                 * column 0.
132                                 */
133adjust1:                        if (ISMOTION(vp))
134                                        goto ret1;
135
136adjust2:                        vp->m_stop.lno = lno;
137                                vp->m_stop.cno = 0;
138                                goto ret2;
139                        }
140        }
141
142        /* If moving forward, reached EOF, check to see if we started there. */
143        if (vp->m_start.lno == lno - 1) {
144                v_eof(sp, NULL);
145                return (1);
146        }
147
148ret1:   if (db_get(sp, --lno, DBG_FATAL, NULL, &len))
149                return (1);
150        vp->m_stop.lno = lno;
151        vp->m_stop.cno = len ? len - 1 : 0;
152
153        /*
154         * Non-motion commands go to the end of the range.  Delete and
155         * yank stay at the start of the range.  Ignore others.
156         */
157ret2:   if (ISMOTION(vp)) {
158                vp->m_final = vp->m_start;
159                if (F_ISSET(vp, VM_LMODE))
160                        vp->m_final.cno = 0;
161        } else
162                vp->m_final = vp->m_stop;
163        return (0);
164}
165
166/*
167 * v_sectionb -- [count][[
168 *      Move backward count sections/functions.
169 *
170 * PUBLIC: int v_sectionb __P((SCR *, VICMD *));
171 */
172int
173v_sectionb(sp, vp)
174        SCR *sp;
175        VICMD *vp;
176{
177        size_t len;
178        recno_t cnt, lno;
179        char *p, *list, *lp;
180
181        /* An empty file or starting from line 1 is always illegal. */
182        if (vp->m_start.lno <= 1) {
183                v_sof(sp, NULL);
184                return (1);
185        }
186
187        /* Get the macro list. */
188        if ((list = O_STR(sp, O_SECTIONS)) == NULL)
189                return (1);
190
191        cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
192        for (lno = vp->m_start.lno; !db_get(sp, --lno, 0, &p, &len);) {
193                if (len == 0)
194                        continue;
195                if (p[0] == '{') {
196                        if (!--cnt)
197                                goto adjust1;
198                        continue;
199                }
200                /*
201                 * !!!
202                 * Historic documentation (USD:15-11, 4.2) said that formfeed
203                 * characters (^L) in the first column delimited sections.
204                 * The historic code mentions formfeed characters, but never
205                 * implements them.  Seems reasonable, do it.
206                 */
207                if (p[0] == '\014') {
208                        if (!--cnt)
209                                goto adjust1;
210                        continue;
211                }
212                if (p[0] != '.' || len < 2)
213                        continue;
214                for (lp = list; *lp != '\0'; lp += 2 * sizeof(*lp))
215                        if (lp[0] == p[1] &&
216                            (lp[1] == ' ' && len == 2 || lp[1] == p[2]) &&
217                            !--cnt) {
218adjust1:                        vp->m_stop.lno = lno;
219                                vp->m_stop.cno = 0;
220                                goto ret1;
221                        }
222        }
223
224        /*
225         * If moving backward, reached SOF, which is a movement sink.
226         * We already checked for starting there.
227         */
228        vp->m_stop.lno = 1;
229        vp->m_stop.cno = 0;
230
231        /*
232         * All commands move to the end of the range.
233         *
234         * !!!
235         * Historic practice is the section cut was in line mode if it started
236         * from column 0 and was in the backward direction.  Otherwise, left
237         * motion commands adjust the starting point to the character before
238         * the current one.  What makes this worse is that if it cut to line
239         * mode it also went to the first non-<blank>.
240         */
241ret1:   if (vp->m_start.cno == 0) {
242                F_CLR(vp, VM_RCM_MASK);
243                F_SET(vp, VM_RCM_SETFNB);
244
245                --vp->m_start.lno;
246                F_SET(vp, VM_LMODE);
247        } else
248                --vp->m_start.cno;
249
250        vp->m_final = vp->m_stop;
251        return (0);
252}
Note: See TracBrowser for help on using the repository browser.