update to 1.01
[nvi.git] / vi / v_paragraph.c
blob405509784777c5c991d4d894dc694ef224d35909
1 /*-
2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
5 * %sccs.include.redist.c%
6 */
8 #ifndef lint
9 static char sccsid[] = "$Id: v_paragraph.c,v 8.4 1993/12/09 19:43:16 bostic Exp $ (Berkeley) $Date: 1993/12/09 19:43:16 $";
10 #endif /* not lint */
12 #include <sys/types.h>
14 #include <errno.h>
15 #include <stdlib.h>
16 #include <string.h>
18 #include "vi.h"
19 #include "vcmd.h"
22 * Paragraphs are empty lines after text or values from the paragraph or
23 * section options.
27 * v_paragraphf -- [count]}
28 * Move forward count paragraphs.
30 int
31 v_paragraphf(sp, ep, vp, fm, tm, rp)
32 SCR *sp;
33 EXF *ep;
34 VICMDARG *vp;
35 MARK *fm, *tm, *rp;
37 enum { P_INTEXT, P_INBLANK } pstate;
38 size_t lastlen, len;
39 recno_t cnt, lastlno, lno;
40 char *p, *lp;
42 /* Figure out what state we're currently in. */
43 lno = fm->lno;
44 if ((p = file_gline(sp, ep, lno, &len)) == NULL)
45 goto eof;
48 * If we start in text, we want to switch states 2 * N - 1
49 * times, in non-text, 2 * N times.
51 cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
52 cnt *= 2;
53 if (len == 0 || v_isempty(p, len))
54 pstate = P_INBLANK;
55 else {
56 --cnt;
57 pstate = P_INTEXT;
60 for (;;) {
61 lastlno = lno;
62 lastlen = len;
63 if ((p = file_gline(sp, ep, ++lno, &len)) == NULL)
64 goto eof;
65 switch (pstate) {
66 case P_INTEXT:
67 if (p[0] == '.' && len >= 2)
68 for (lp = VIP(sp)->paragraph; *lp; lp += 2)
69 if (lp[0] == p[1] &&
70 (lp[1] == ' ' || lp[1] == p[2]) &&
71 !--cnt)
72 goto found;
73 if (len == 0 || v_isempty(p, len)) {
74 if (!--cnt)
75 goto found;
76 pstate = P_INBLANK;
78 break;
79 case P_INBLANK:
80 if (len == 0 || v_isempty(p, len))
81 break;
82 if (--cnt) {
83 pstate = P_INTEXT;
84 break;
87 * Historically, a motion command was up to the end
88 * of the previous line, whereas the movement command
89 * was to the start of the new "paragraph".
91 found: if (F_ISSET(vp, VC_C | VC_D | VC_Y)) {
92 rp->lno = lastlno;
93 rp->cno = lastlen ? lastlen + 1 : 0;
94 } else {
95 rp->lno = lno;
96 rp->cno = 0;
98 return (0);
99 default:
100 abort();
105 * EOF is a movement sink, however, the } command historically
106 * moved to the end of the last line if repeatedly invoked.
108 eof: if (fm->lno != lno - 1) {
109 rp->lno = lno - 1;
110 rp->cno = len ? len - 1 : 0;
111 return (0);
113 if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL)
114 GETLINE_ERR(sp, fm->lno);
115 if (fm->cno != (len ? len - 1 : 0)) {
116 rp->lno = lno - 1;
117 rp->cno = len ? len - 1 : 0;
118 return (0);
120 v_eof(sp, ep, NULL);
121 return (1);
125 * v_paragraphb -- [count]{
126 * Move forward count paragraph.
129 v_paragraphb(sp, ep, vp, fm, tm, rp)
130 SCR *sp;
131 EXF *ep;
132 VICMDARG *vp;
133 MARK *fm, *tm, *rp;
135 enum { P_INTEXT, P_INBLANK } pstate;
136 size_t len;
137 recno_t cnt, lno;
138 char *p, *lp;
141 * The { command historically moved to the beginning of the first
142 * line if invoked on the first line.
144 * Check for SOF.
146 if (fm->lno <= 1) {
147 if (fm->cno == 0) {
148 v_sof(sp, NULL);
149 return (1);
151 rp->lno = 1;
152 rp->cno = 0;
153 return (0);
156 /* Figure out what state we're currently in. */
157 lno = fm->lno;
158 if ((p = file_gline(sp, ep, lno, &len)) == NULL)
159 goto sof;
162 * If we start in text, we want to switch states 2 * N - 1
163 * times, in non-text, 2 * N times.
165 cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
166 cnt *= 2;
167 if (len == 0 || v_isempty(p, len))
168 pstate = P_INBLANK;
169 else {
170 --cnt;
171 pstate = P_INTEXT;
174 for (;;) {
175 if ((p = file_gline(sp, ep, --lno, &len)) == NULL)
176 goto sof;
177 switch (pstate) {
178 case P_INTEXT:
179 if (p[0] == '.' && len >= 2)
180 for (lp = VIP(sp)->paragraph; *lp; lp += 2)
181 if (lp[0] == p[1] &&
182 (lp[1] == ' ' || lp[1] == p[2]) &&
183 !--cnt)
184 goto found;
185 if (len == 0 || v_isempty(p, len)) {
186 if (!--cnt)
187 goto found;
188 pstate = P_INBLANK;
190 break;
191 case P_INBLANK:
192 if (len != 0 && !v_isempty(p, len)) {
193 if (!--cnt) {
194 found: rp->lno = lno;
195 rp->cno = 0;
196 return (0);
198 pstate = P_INTEXT;
200 break;
201 default:
202 abort();
206 /* SOF is a movement sink. */
207 sof: rp->lno = 1;
208 rp->cno = 0;
209 return (0);
213 * v_buildparagraph --
214 * Build the paragraph command search pattern.
217 v_buildparagraph(sp)
218 SCR *sp;
220 VI_PRIVATE *vip;
221 size_t p_len, s_len;
222 char *p, *p_p, *s_p;
225 * The vi paragraph command searches for either a paragraph or
226 * section option macro.
228 p_len = (p_p = O_STR(sp, O_PARAGRAPHS)) == NULL ? 0 : strlen(p_p);
229 s_len = (s_p = O_STR(sp, O_SECTIONS)) == NULL ? 0 : strlen(s_p);
231 if (p_len == 0 && s_len == 0)
232 return (0);
234 MALLOC_RET(sp, p, char *, p_len + s_len + 1);
236 vip = VIP(sp);
237 if (vip->paragraph != NULL)
238 FREE(vip->paragraph, vip->paragraph_len);
240 if (p_p != NULL)
241 memmove(p, p_p, p_len + 1);
242 if (s_p != NULL)
243 memmove(p + p_len, s_p, s_len + 1);
244 vip->paragraph = p;
245 vip->paragraph_len = p_len + s_len + 1;
246 return (0);