tools/llvm: Do not build with symbols
[minix3.git] / external / bsd / nvi / dist / vi / v_sentence.c
blob88d660681c45936f7ad59b36cd0316bf76c79aad
1 /* $NetBSD: v_sentence.c,v 1.2 2013/11/22 15:52:06 christos Exp $ */
2 /*-
3 * Copyright (c) 1992, 1993, 1994
4 * The Regents of the University of California. All rights reserved.
5 * Copyright (c) 1992, 1993, 1994, 1995, 1996
6 * Keith Bostic. All rights reserved.
8 * See the LICENSE file for redistribution information.
9 */
11 #include "config.h"
13 #ifndef lint
14 static const char sccsid[] = "Id: v_sentence.c,v 10.9 2001/06/25 15:19:35 skimo Exp (Berkeley) Date: 2001/06/25 15:19:35 ";
15 #endif /* not lint */
17 #include <sys/types.h>
18 #include <sys/queue.h>
19 #include <sys/time.h>
21 #include <bitstring.h>
22 #include <ctype.h>
23 #include <limits.h>
24 #include <stdio.h>
26 #include "../common/common.h"
27 #include "vi.h"
30 * !!!
31 * In historic vi, a sentence was delimited by a '.', '?' or '!' character
32 * followed by TWO spaces or a newline. One or more empty lines was also
33 * treated as a separate sentence. The Berkeley documentation for historical
34 * vi states that any number of ')', ']', '"' and '\'' characters can be
35 * between the delimiter character and the spaces or end of line, however,
36 * the historical implementation did not handle additional '"' characters.
37 * We follow the documentation here, not the implementation.
39 * Once again, historical vi didn't do sentence movements associated with
40 * counts consistently, mostly in the presence of lines containing only
41 * white-space characters.
43 * This implementation also permits a single tab to delimit sentences, and
44 * treats lines containing only white-space characters as empty lines.
45 * Finally, tabs are eaten (along with spaces) when skipping to the start
46 * of the text following a "sentence".
50 * v_sentencef -- [count])
51 * Move forward count sentences.
53 * PUBLIC: int v_sentencef __P((SCR *, VICMD *));
55 int
56 v_sentencef(SCR *sp, VICMD *vp)
58 enum { BLANK, NONE, PERIOD } state;
59 VCS cs;
60 size_t len;
61 u_long cnt;
63 cs.cs_lno = vp->m_start.lno;
64 cs.cs_cno = vp->m_start.cno;
65 if (cs_init(sp, &cs))
66 return (1);
68 cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
71 * !!!
72 * If in white-space, the next start of sentence counts as one.
73 * This may not handle " . " correctly, but it's real unclear
74 * what correctly means in that case.
76 if (cs.cs_flags == CS_EMP || (cs.cs_flags == 0 && ISBLANK2(cs.cs_ch))) {
77 if (cs_fblank(sp, &cs))
78 return (1);
79 if (--cnt == 0) {
80 if (vp->m_start.lno != cs.cs_lno ||
81 vp->m_start.cno != cs.cs_cno)
82 goto okret;
83 return (1);
87 for (state = NONE;;) {
88 if (cs_next(sp, &cs))
89 return (1);
90 if (cs.cs_flags == CS_EOF)
91 break;
92 if (cs.cs_flags == CS_EOL) {
93 if ((state == PERIOD || state == BLANK) && --cnt == 0) {
94 if (cs_next(sp, &cs))
95 return (1);
96 if (cs.cs_flags == 0 &&
97 ISBLANK2(cs.cs_ch) && cs_fblank(sp, &cs))
98 return (1);
99 goto okret;
101 state = NONE;
102 continue;
104 if (cs.cs_flags == CS_EMP) { /* An EMP is two sentences. */
105 if (--cnt == 0)
106 goto okret;
107 if (cs_fblank(sp, &cs))
108 return (1);
109 if (--cnt == 0)
110 goto okret;
111 state = NONE;
112 continue;
114 switch (cs.cs_ch) {
115 case '.':
116 case '?':
117 case '!':
118 state = PERIOD;
119 break;
120 case ')':
121 case ']':
122 case '"':
123 case '\'':
124 if (state != PERIOD)
125 state = NONE;
126 break;
127 case '\t':
128 if (state == PERIOD)
129 state = BLANK;
130 /* FALLTHROUGH */
131 case ' ':
132 if (state == PERIOD) {
133 state = BLANK;
134 break;
136 if (state == BLANK && --cnt == 0) {
137 if (cs_fblank(sp, &cs))
138 return (1);
139 goto okret;
141 /* FALLTHROUGH */
142 default:
143 state = NONE;
144 break;
148 /* EOF is a movement sink, but it's an error not to have moved. */
149 if (vp->m_start.lno == cs.cs_lno && vp->m_start.cno == cs.cs_cno) {
150 v_eof(sp, NULL);
151 return (1);
154 okret: vp->m_stop.lno = cs.cs_lno;
155 vp->m_stop.cno = cs.cs_cno;
158 * !!!
159 * Historic, uh, features, yeah, that's right, call 'em features.
160 * If the starting and ending cursor positions are at the first
161 * column in their lines, i.e. the movement is cutting entire lines,
162 * the buffer is in line mode, and the ending position is the last
163 * character of the previous line. Note check to make sure that
164 * it's not within a single line.
166 * Non-motion commands move to the end of the range. Delete and
167 * yank stay at the start. Ignore others. Adjust the end of the
168 * range for motion commands.
170 if (ISMOTION(vp)) {
171 if (vp->m_start.cno == 0 &&
172 (cs.cs_flags != 0 || vp->m_stop.cno == 0)) {
173 if (vp->m_start.lno < vp->m_stop.lno) {
174 if (db_get(sp,
175 --vp->m_stop.lno, DBG_FATAL, NULL, &len))
176 return (1);
177 vp->m_stop.cno = len ? len - 1 : 0;
179 F_SET(vp, VM_LMODE);
180 } else
181 --vp->m_stop.cno;
182 vp->m_final = vp->m_start;
183 } else
184 vp->m_final = vp->m_stop;
185 return (0);
189 * v_sentenceb -- [count](
190 * Move backward count sentences.
192 * PUBLIC: int v_sentenceb __P((SCR *, VICMD *));
195 v_sentenceb(SCR *sp, VICMD *vp)
197 VCS cs;
198 db_recno_t slno;
199 size_t len, scno;
200 u_long cnt;
201 int last;
204 * !!!
205 * Historic vi permitted the user to hit SOF repeatedly.
207 if (vp->m_start.lno == 1 && vp->m_start.cno == 0)
208 return (0);
210 cs.cs_lno = vp->m_start.lno;
211 cs.cs_cno = vp->m_start.cno;
212 if (cs_init(sp, &cs))
213 return (1);
215 cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
218 * !!!
219 * In empty lines, skip to the previous non-white-space character.
220 * If in text, skip to the prevous white-space character. Believe
221 * it or not, in the paragraph:
222 * ab cd.
223 * AB CD.
224 * if the cursor is on the 'A' or 'B', ( moves to the 'a'. If it
225 * is on the ' ', 'C' or 'D', it moves to the 'A'. Yes, Virginia,
226 * Berkeley was once a major center of drug activity.
228 if (cs.cs_flags == CS_EMP) {
229 if (cs_bblank(sp, &cs))
230 return (1);
231 for (;;) {
232 if (cs_prev(sp, &cs))
233 return (1);
234 if (cs.cs_flags != CS_EOL)
235 break;
237 } else if (cs.cs_flags == 0 && !ISBLANK2(cs.cs_ch))
238 for (;;) {
239 if (cs_prev(sp, &cs))
240 return (1);
241 if (cs.cs_flags != 0 || ISBLANK2(cs.cs_ch))
242 break;
245 for (last = 0;;) {
246 if (cs_prev(sp, &cs))
247 return (1);
248 if (cs.cs_flags == CS_SOF) /* SOF is a movement sink. */
249 break;
250 if (cs.cs_flags == CS_EOL) {
251 last = 1;
252 continue;
254 if (cs.cs_flags == CS_EMP) {
255 if (--cnt == 0)
256 goto ret;
257 if (cs_bblank(sp, &cs))
258 return (1);
259 last = 0;
260 continue;
262 switch (cs.cs_ch) {
263 case '.':
264 case '?':
265 case '!':
266 if (!last || --cnt != 0) {
267 last = 0;
268 continue;
271 ret: slno = cs.cs_lno;
272 scno = cs.cs_cno;
275 * Move to the start of the sentence, skipping blanks
276 * and special characters.
278 do {
279 if (cs_next(sp, &cs))
280 return (1);
281 } while (!cs.cs_flags &&
282 (cs.cs_ch == ')' || cs.cs_ch == ']' ||
283 cs.cs_ch == '"' || cs.cs_ch == '\''));
284 if ((cs.cs_flags || ISBLANK2(cs.cs_ch)) &&
285 cs_fblank(sp, &cs))
286 return (1);
289 * If it was ". xyz", with the cursor on the 'x', or
290 * "end. ", with the cursor in the spaces, or the
291 * beginning of a sentence preceded by an empty line,
292 * we can end up where we started. Fix it.
294 if (vp->m_start.lno != cs.cs_lno ||
295 vp->m_start.cno != cs.cs_cno)
296 goto okret;
299 * Well, if an empty line preceded possible blanks
300 * and the sentence, it could be a real sentence.
302 for (;;) {
303 if (cs_prev(sp, &cs))
304 return (1);
305 if (cs.cs_flags == CS_EOL)
306 continue;
307 if (cs.cs_flags == 0 && ISBLANK2(cs.cs_ch))
308 continue;
309 break;
311 if (cs.cs_flags == CS_EMP)
312 goto okret;
314 /* But it wasn't; try again. */
315 ++cnt;
316 cs.cs_lno = slno;
317 cs.cs_cno = scno;
318 last = 0;
319 break;
320 case '\t':
321 last = 1;
322 break;
323 default:
324 last =
325 cs.cs_flags == CS_EOL || ISBLANK2(cs.cs_ch) ||
326 cs.cs_ch == ')' || cs.cs_ch == ']' ||
327 cs.cs_ch == '"' || cs.cs_ch == '\'' ? 1 : 0;
331 okret: vp->m_stop.lno = cs.cs_lno;
332 vp->m_stop.cno = cs.cs_cno;
335 * !!!
336 * If the starting and stopping cursor positions are at the first
337 * columns in the line, i.e. the movement is cutting an entire line,
338 * the buffer is in line mode, and the starting position is the last
339 * character of the previous line.
341 * All commands move to the end of the range. Adjust the start of
342 * the range for motion commands.
344 if (ISMOTION(vp)) {
345 if (vp->m_start.cno == 0 &&
346 (cs.cs_flags != 0 || vp->m_stop.cno == 0)) {
347 if (db_get(sp,
348 --vp->m_start.lno, DBG_FATAL, NULL, &len))
349 return (1);
350 vp->m_start.cno = len ? len - 1 : 0;
351 F_SET(vp, VM_LMODE);
352 } else
353 --vp->m_start.cno;
355 vp->m_final = vp->m_stop;
356 return (0);