Remove building with NOCRYPTO option
[minix3.git] / external / bsd / nvi / dist / vi / v_sentence.c
blob53cc221c5dcb10fb04da1a97daf092ee4b68b41c
1 /* $NetBSD: v_sentence.c,v 1.3 2014/01/26 21:43:45 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 #include <sys/cdefs.h>
14 #if 0
15 #ifndef lint
16 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 ";
17 #endif /* not lint */
18 #else
19 __RCSID("$NetBSD: v_sentence.c,v 1.3 2014/01/26 21:43:45 christos Exp $");
20 #endif
22 #include <sys/types.h>
23 #include <sys/queue.h>
24 #include <sys/time.h>
26 #include <bitstring.h>
27 #include <ctype.h>
28 #include <limits.h>
29 #include <stdio.h>
31 #include "../common/common.h"
32 #include "vi.h"
35 * !!!
36 * In historic vi, a sentence was delimited by a '.', '?' or '!' character
37 * followed by TWO spaces or a newline. One or more empty lines was also
38 * treated as a separate sentence. The Berkeley documentation for historical
39 * vi states that any number of ')', ']', '"' and '\'' characters can be
40 * between the delimiter character and the spaces or end of line, however,
41 * the historical implementation did not handle additional '"' characters.
42 * We follow the documentation here, not the implementation.
44 * Once again, historical vi didn't do sentence movements associated with
45 * counts consistently, mostly in the presence of lines containing only
46 * white-space characters.
48 * This implementation also permits a single tab to delimit sentences, and
49 * treats lines containing only white-space characters as empty lines.
50 * Finally, tabs are eaten (along with spaces) when skipping to the start
51 * of the text following a "sentence".
55 * v_sentencef -- [count])
56 * Move forward count sentences.
58 * PUBLIC: int v_sentencef __P((SCR *, VICMD *));
60 int
61 v_sentencef(SCR *sp, VICMD *vp)
63 enum { BLANK, NONE, PERIOD } state;
64 VCS cs;
65 size_t len;
66 u_long cnt;
68 cs.cs_lno = vp->m_start.lno;
69 cs.cs_cno = vp->m_start.cno;
70 if (cs_init(sp, &cs))
71 return (1);
73 cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
76 * !!!
77 * If in white-space, the next start of sentence counts as one.
78 * This may not handle " . " correctly, but it's real unclear
79 * what correctly means in that case.
81 if (cs.cs_flags == CS_EMP || (cs.cs_flags == 0 && ISBLANK2(cs.cs_ch))) {
82 if (cs_fblank(sp, &cs))
83 return (1);
84 if (--cnt == 0) {
85 if (vp->m_start.lno != cs.cs_lno ||
86 vp->m_start.cno != cs.cs_cno)
87 goto okret;
88 return (1);
92 for (state = NONE;;) {
93 if (cs_next(sp, &cs))
94 return (1);
95 if (cs.cs_flags == CS_EOF)
96 break;
97 if (cs.cs_flags == CS_EOL) {
98 if ((state == PERIOD || state == BLANK) && --cnt == 0) {
99 if (cs_next(sp, &cs))
100 return (1);
101 if (cs.cs_flags == 0 &&
102 ISBLANK2(cs.cs_ch) && cs_fblank(sp, &cs))
103 return (1);
104 goto okret;
106 state = NONE;
107 continue;
109 if (cs.cs_flags == CS_EMP) { /* An EMP is two sentences. */
110 if (--cnt == 0)
111 goto okret;
112 if (cs_fblank(sp, &cs))
113 return (1);
114 if (--cnt == 0)
115 goto okret;
116 state = NONE;
117 continue;
119 switch (cs.cs_ch) {
120 case '.':
121 case '?':
122 case '!':
123 state = PERIOD;
124 break;
125 case ')':
126 case ']':
127 case '"':
128 case '\'':
129 if (state != PERIOD)
130 state = NONE;
131 break;
132 case '\t':
133 if (state == PERIOD)
134 state = BLANK;
135 /* FALLTHROUGH */
136 case ' ':
137 if (state == PERIOD) {
138 state = BLANK;
139 break;
141 if (state == BLANK && --cnt == 0) {
142 if (cs_fblank(sp, &cs))
143 return (1);
144 goto okret;
146 /* FALLTHROUGH */
147 default:
148 state = NONE;
149 break;
153 /* EOF is a movement sink, but it's an error not to have moved. */
154 if (vp->m_start.lno == cs.cs_lno && vp->m_start.cno == cs.cs_cno) {
155 v_eof(sp, NULL);
156 return (1);
159 okret: vp->m_stop.lno = cs.cs_lno;
160 vp->m_stop.cno = cs.cs_cno;
163 * !!!
164 * Historic, uh, features, yeah, that's right, call 'em features.
165 * If the starting and ending cursor positions are at the first
166 * column in their lines, i.e. the movement is cutting entire lines,
167 * the buffer is in line mode, and the ending position is the last
168 * character of the previous line. Note check to make sure that
169 * it's not within a single line.
171 * Non-motion commands move to the end of the range. Delete and
172 * yank stay at the start. Ignore others. Adjust the end of the
173 * range for motion commands.
175 if (ISMOTION(vp)) {
176 if (vp->m_start.cno == 0 &&
177 (cs.cs_flags != 0 || vp->m_stop.cno == 0)) {
178 if (vp->m_start.lno < vp->m_stop.lno) {
179 if (db_get(sp,
180 --vp->m_stop.lno, DBG_FATAL, NULL, &len))
181 return (1);
182 vp->m_stop.cno = len ? len - 1 : 0;
184 F_SET(vp, VM_LMODE);
185 } else
186 --vp->m_stop.cno;
187 vp->m_final = vp->m_start;
188 } else
189 vp->m_final = vp->m_stop;
190 return (0);
194 * v_sentenceb -- [count](
195 * Move backward count sentences.
197 * PUBLIC: int v_sentenceb __P((SCR *, VICMD *));
200 v_sentenceb(SCR *sp, VICMD *vp)
202 VCS cs;
203 db_recno_t slno;
204 size_t len, scno;
205 u_long cnt;
206 int last;
209 * !!!
210 * Historic vi permitted the user to hit SOF repeatedly.
212 if (vp->m_start.lno == 1 && vp->m_start.cno == 0)
213 return (0);
215 cs.cs_lno = vp->m_start.lno;
216 cs.cs_cno = vp->m_start.cno;
217 if (cs_init(sp, &cs))
218 return (1);
220 cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
223 * !!!
224 * In empty lines, skip to the previous non-white-space character.
225 * If in text, skip to the prevous white-space character. Believe
226 * it or not, in the paragraph:
227 * ab cd.
228 * AB CD.
229 * if the cursor is on the 'A' or 'B', ( moves to the 'a'. If it
230 * is on the ' ', 'C' or 'D', it moves to the 'A'. Yes, Virginia,
231 * Berkeley was once a major center of drug activity.
233 if (cs.cs_flags == CS_EMP) {
234 if (cs_bblank(sp, &cs))
235 return (1);
236 for (;;) {
237 if (cs_prev(sp, &cs))
238 return (1);
239 if (cs.cs_flags != CS_EOL)
240 break;
242 } else if (cs.cs_flags == 0 && !ISBLANK2(cs.cs_ch))
243 for (;;) {
244 if (cs_prev(sp, &cs))
245 return (1);
246 if (cs.cs_flags != 0 || ISBLANK2(cs.cs_ch))
247 break;
250 for (last = 0;;) {
251 if (cs_prev(sp, &cs))
252 return (1);
253 if (cs.cs_flags == CS_SOF) /* SOF is a movement sink. */
254 break;
255 if (cs.cs_flags == CS_EOL) {
256 last = 1;
257 continue;
259 if (cs.cs_flags == CS_EMP) {
260 if (--cnt == 0)
261 goto ret;
262 if (cs_bblank(sp, &cs))
263 return (1);
264 last = 0;
265 continue;
267 switch (cs.cs_ch) {
268 case '.':
269 case '?':
270 case '!':
271 if (!last || --cnt != 0) {
272 last = 0;
273 continue;
276 ret: slno = cs.cs_lno;
277 scno = cs.cs_cno;
280 * Move to the start of the sentence, skipping blanks
281 * and special characters.
283 do {
284 if (cs_next(sp, &cs))
285 return (1);
286 } while (!cs.cs_flags &&
287 (cs.cs_ch == ')' || cs.cs_ch == ']' ||
288 cs.cs_ch == '"' || cs.cs_ch == '\''));
289 if ((cs.cs_flags || ISBLANK2(cs.cs_ch)) &&
290 cs_fblank(sp, &cs))
291 return (1);
294 * If it was ". xyz", with the cursor on the 'x', or
295 * "end. ", with the cursor in the spaces, or the
296 * beginning of a sentence preceded by an empty line,
297 * we can end up where we started. Fix it.
299 if (vp->m_start.lno != cs.cs_lno ||
300 vp->m_start.cno != cs.cs_cno)
301 goto okret;
304 * Well, if an empty line preceded possible blanks
305 * and the sentence, it could be a real sentence.
307 for (;;) {
308 if (cs_prev(sp, &cs))
309 return (1);
310 if (cs.cs_flags == CS_EOL)
311 continue;
312 if (cs.cs_flags == 0 && ISBLANK2(cs.cs_ch))
313 continue;
314 break;
316 if (cs.cs_flags == CS_EMP)
317 goto okret;
319 /* But it wasn't; try again. */
320 ++cnt;
321 cs.cs_lno = slno;
322 cs.cs_cno = scno;
323 last = 0;
324 break;
325 case '\t':
326 last = 1;
327 break;
328 default:
329 last =
330 cs.cs_flags == CS_EOL || ISBLANK2(cs.cs_ch) ||
331 cs.cs_ch == ')' || cs.cs_ch == ']' ||
332 cs.cs_ch == '"' || cs.cs_ch == '\'' ? 1 : 0;
336 okret: vp->m_stop.lno = cs.cs_lno;
337 vp->m_stop.cno = cs.cs_cno;
340 * !!!
341 * If the starting and stopping cursor positions are at the first
342 * columns in the line, i.e. the movement is cutting an entire line,
343 * the buffer is in line mode, and the starting position is the last
344 * character of the previous line.
346 * All commands move to the end of the range. Adjust the start of
347 * the range for motion commands.
349 if (ISMOTION(vp)) {
350 if (vp->m_start.cno == 0 &&
351 (cs.cs_flags != 0 || vp->m_stop.cno == 0)) {
352 if (db_get(sp,
353 --vp->m_start.lno, DBG_FATAL, NULL, &len))
354 return (1);
355 vp->m_start.cno = len ? len - 1 : 0;
356 F_SET(vp, VM_LMODE);
357 } else
358 --vp->m_start.cno;
360 vp->m_final = vp->m_stop;
361 return (0);