date and time created 94/04/13 10:27:13 by eric
[unix-history] / usr / src / usr.bin / ex / ex_vops3.c
CommitLineData
2791ff57 1/*-
eb035710
KB
2 * Copyright (c) 1980, 1993
3 * The Regents of the University of California. All rights reserved.
2791ff57
KB
4 *
5 * %sccs.include.proprietary.c%
f9679f70
DF
6 */
7
8#ifndef lint
eb035710 9static char sccsid[] = "@(#)ex_vops3.c 8.1 (Berkeley) %G%";
2791ff57 10#endif /* not lint */
f9679f70 11
1c1e118c
MH
12#include "ex.h"
13#include "ex_tty.h"
14#include "ex_vis.h"
15
16/*
17 * Routines to handle structure.
18 * Operations supported are:
19 * ( ) { } [ ]
20 *
21 * These cover: LISP TEXT
22 * ( ) s-exprs sentences
23 * { } list at same paragraphs
24 * [ ] defuns sections
25 *
26 * { and } for C used to attempt to do something with matching {}'s, but
27 * I couldn't find definitions which worked intuitively very well, so I
28 * scrapped this.
29 *
30 * The code here is very hard to understand.
31 */
32line *llimit;
33int (*lf)();
34
35#ifdef LISPCODE
36int lindent();
37#endif
38
39bool wasend;
40
41/*
42 * Find over structure, repeated count times.
43 * Don't go past line limit. F is the operation to
44 * be performed eventually. If pastatom then the user said {}
45 * rather than (), implying past atoms in a list (or a paragraph
46 * rather than a sentence.
47 */
48lfind(pastatom, cnt, f, limit)
49 bool pastatom;
50 int cnt, (*f)();
51 line *limit;
52{
53 register int c;
54 register int rc = 0;
55 char save[LBSIZE];
56
57 /*
58 * Initialize, saving the current line buffer state
59 * and computing the limit; a 0 argument means
60 * directional end of file.
61 */
62 wasend = 0;
63 lf = f;
64 strcpy(save, linebuf);
65 if (limit == 0)
66 limit = dir < 0 ? one : dol;
67 llimit = limit;
68 wdot = dot;
69 wcursor = cursor;
70
71 if (pastatom >= 2) {
72 while (cnt > 0 && word(f, cnt))
73 cnt--;
74 if (pastatom == 3)
75 eend(f);
76 if (dot == wdot) {
77 wdot = 0;
78 if (cursor == wcursor)
79 rc = -1;
80 }
81 }
82#ifdef LISPCODE
83 else if (!value(LISP)) {
84#else
85 else {
86#endif
87 char *icurs;
88 line *idot;
89
90 if (linebuf[0] == 0) {
91 do
92 if (!lnext())
93 goto ret;
94 while (linebuf[0] == 0);
95 if (dir > 0) {
96 wdot--;
97 linebuf[0] = 0;
98 wcursor = linebuf;
99 /*
100 * If looking for sentence, next line
101 * starts one.
102 */
103 if (!pastatom) {
104 icurs = wcursor;
105 idot = wdot;
106 goto begin;
107 }
108 }
109 }
110 icurs = wcursor;
111 idot = wdot;
112
113 /*
114 * Advance so as to not find same thing again.
115 */
116 if (dir > 0) {
117 if (!lnext()) {
118 rc = -1;
119 goto ret;
120 }
121 } else
122 ignore(lskipa1(""));
123
124 /*
125 * Count times find end of sentence/paragraph.
126 */
127begin:
128 for (;;) {
129 while (!endsent(pastatom))
130 if (!lnext())
131 goto ret;
132 if (!pastatom || wcursor == linebuf && endPS())
133 if (--cnt <= 0)
134 break;
135 if (linebuf[0] == 0) {
136 do
137 if (!lnext())
138 goto ret;
139 while (linebuf[0] == 0);
140 } else
141 if (!lnext())
142 goto ret;
143 }
144
145 /*
146 * If going backwards, and didn't hit the end of the buffer,
147 * then reverse direction.
148 */
149 if (dir < 0 && (wdot != llimit || wcursor != linebuf)) {
150 dir = 1;
151 llimit = dot;
152 /*
153 * Empty line needs special treatement.
154 * If moved to it from other than begining of next line,
155 * then a sentence starts on next line.
156 */
157 if (linebuf[0] == 0 && !pastatom &&
158 (wdot != dot - 1 || cursor != linebuf)) {
5a6c967e 159 ignore(lnext());
1c1e118c
MH
160 goto ret;
161 }
162 }
163
164 /*
165 * If we are not at a section/paragraph division,
166 * advance to next.
167 */
168 if (wcursor == icurs && wdot == idot || wcursor != linebuf || !endPS())
169 ignore(lskipa1(""));
170 }
171#ifdef LISPCODE
172 else {
173 c = *wcursor;
174 /*
175 * Startup by skipping if at a ( going left or a ) going
176 * right to keep from getting stuck immediately.
177 */
178 if (dir < 0 && c == '(' || dir > 0 && c == ')') {
179 if (!lnext()) {
180 rc = -1;
181 goto ret;
182 }
183 }
184 /*
185 * Now chew up repitition count. Each time around
186 * if at the beginning of an s-exp (going forwards)
187 * or the end of an s-exp (going backwards)
188 * skip the s-exp. If not at beg/end resp, then stop
189 * if we hit a higher level paren, else skip an atom,
190 * counting it unless pastatom.
191 */
192 while (cnt > 0) {
193 c = *wcursor;
194 if (dir < 0 && c == ')' || dir > 0 && c == '(') {
195 if (!lskipbal("()"))
196 goto ret;
197 /*
198 * Unless this is the last time going
199 * backwards, skip past the matching paren
200 * so we don't think it is a higher level paren.
201 */
202 if (dir < 0 && cnt == 1)
203 goto ret;
204 if (!lnext() || !ltosolid())
205 goto ret;
206 --cnt;
207 } else if (dir < 0 && c == '(' || dir > 0 && c == ')')
208 /* Found a higher level paren */
209 goto ret;
210 else {
211 if (!lskipatom())
212 goto ret;
213 if (!pastatom)
214 --cnt;
215 }
216 }
217 }
218#endif
219ret:
220 strcLIN(save);
221 return (rc);
222}
223
224/*
225 * Is this the end of a sentence?
226 */
5a6c967e 227/* ARGSUSED */
1c1e118c
MH
228endsent(pastatom)
229 bool pastatom;
230{
231 register char *cp = wcursor;
5a6c967e 232 register int d;
1c1e118c
MH
233
234 /*
235 * If this is the beginning of a line, then
236 * check for the end of a paragraph or section.
237 */
238 if (cp == linebuf)
239 return (endPS());
240
241 /*
242 * Sentences end with . ! ? not at the beginning
243 * of the line, and must be either at the end of the line,
244 * or followed by 2 spaces. Any number of intervening ) ] ' "
245 * characters are allowed.
246 */
5a6c967e 247 if (!any(*cp, ".!?"))
1c1e118c
MH
248 goto tryps;
249 do
250 if ((d = *++cp) == 0)
251 return (1);
252 while (any(d, ")]'"));
253 if (*cp == 0 || *cp++ == ' ' && *cp == ' ')
254 return (1);
255tryps:
256 if (cp[1] == 0)
257 return (endPS());
258 return (0);
259}
260
261/*
262 * End of paragraphs/sections are respective
263 * macros as well as blank lines and form feeds.
264 */
265endPS()
266{
267
268 return (linebuf[0] == 0 ||
269 isa(svalue(PARAGRAPHS)) || isa(svalue(SECTIONS)));
270
271}
272
273#ifdef LISPCODE
274lindent(addr)
275 line *addr;
276{
277 register int i;
278 char *swcurs = wcursor;
279 line *swdot = wdot;
280
281again:
282 if (addr > one) {
283 register char *cp;
284 register int cnt = 0;
285
286 addr--;
287 getline(*addr);
288 for (cp = linebuf; *cp; cp++)
289 if (*cp == '(')
290 cnt++;
291 else if (*cp == ')')
292 cnt--;
293 cp = vpastwh(linebuf);
294 if (*cp == 0)
295 goto again;
296 if (cnt == 0)
297 return (whitecnt(linebuf));
298 addr++;
299 }
300 wcursor = linebuf;
301 linebuf[0] = 0;
302 wdot = addr;
303 dir = -1;
304 llimit = one;
305 lf = lindent;
306 if (!lskipbal("()"))
307 i = 0;
308 else if (wcursor == linebuf)
309 i = 2;
310 else {
311 register char *wp = wcursor;
312
313 dir = 1;
314 llimit = wdot;
315 if (!lnext() || !ltosolid() || !lskipatom()) {
316 wcursor = wp;
317 i = 1;
318 } else
319 i = 0;
320 i += column(wcursor) - 1;
321 if (!inopen)
322 i--;
323 }
324 wdot = swdot;
325 wcursor = swcurs;
326 return (i);
327}
328#endif
329
330lmatchp(addr)
331 line *addr;
332{
333 register int i;
334 register char *parens, *cp;
335
d266c416 336 for (cp = cursor; !any(*cp, "({[)}]");)
1c1e118c
MH
337 if (*cp++ == 0)
338 return (0);
339 lf = 0;
d266c416 340 parens = any(*cp, "()") ? "()" : any(*cp, "[]") ? "[]" : "{}";
1c1e118c
MH
341 if (*cp == parens[1]) {
342 dir = -1;
343 llimit = one;
344 } else {
345 dir = 1;
346 llimit = dol;
347 }
348 if (addr)
349 llimit = addr;
350 if (splitw)
351 llimit = dot;
352 wcursor = cp;
353 wdot = dot;
354 i = lskipbal(parens);
355 return (i);
356}
357
358lsmatch(cp)
359 char *cp;
360{
361 char save[LBSIZE];
362 register char *sp = save;
363 register char *scurs = cursor;
364
365 wcursor = cp;
366 strcpy(sp, linebuf);
367 *wcursor = 0;
368 strcpy(cursor, genbuf);
369 cursor = strend(linebuf) - 1;
370 if (lmatchp(dot - vcline)) {
371 register int i = insmode;
372 register int c = outcol;
373 register int l = outline;
374
375 if (!MI)
376 endim();
377 vgoto(splitw ? WECHO : LINE(wdot - llimit), column(wcursor) - 1);
378 flush();
379 sleep(1);
380 vgoto(l, c);
381 if (i)
382 goim();
383 }
d266c416
MH
384 else {
385 strcLIN(sp);
386 strcpy(scurs, genbuf);
387 if (!lmatchp((line *) 0))
388 beep();
389 }
1c1e118c
MH
390 strcLIN(sp);
391 wdot = 0;
392 wcursor = 0;
393 cursor = scurs;
394}
395
396ltosolid()
397{
398
399 return (ltosol1("()"));
400}
401
402ltosol1(parens)
403 register char *parens;
404{
405 register char *cp;
406
407 if (*parens && !*wcursor && !lnext())
408 return (0);
409 while (isspace(*wcursor) || (*wcursor == 0 && *parens))
410 if (!lnext())
411 return (0);
412 if (any(*wcursor, parens) || dir > 0)
413 return (1);
414 for (cp = wcursor; cp > linebuf; cp--)
415 if (isspace(cp[-1]) || any(cp[-1], parens))
416 break;
417 wcursor = cp;
418 return (1);
419}
420
421lskipbal(parens)
422 register char *parens;
423{
424 register int level = dir;
425 register int c;
426
427 do {
f0f2d980
MH
428 if (!lnext()) {
429 wdot = NOLINE;
1c1e118c 430 return (0);
f0f2d980 431 }
1c1e118c
MH
432 c = *wcursor;
433 if (c == parens[1])
434 level--;
435 else if (c == parens[0])
436 level++;
437 } while (level);
438 return (1);
439}
440
441lskipatom()
442{
443
444 return (lskipa1("()"));
445}
446
447lskipa1(parens)
448 register char *parens;
449{
450 register int c;
451
452 for (;;) {
453 if (dir < 0 && wcursor == linebuf) {
454 if (!lnext())
455 return (0);
456 break;
457 }
458 c = *wcursor;
459 if (c && (isspace(c) || any(c, parens)))
460 break;
461 if (!lnext())
462 return (0);
463 if (dir > 0 && wcursor == linebuf)
464 break;
465 }
466 return (ltosol1(parens));
467}
468
469lnext()
470{
471
472 if (dir > 0) {
473 if (*wcursor)
474 wcursor++;
475 if (*wcursor)
476 return (1);
477 if (wdot >= llimit) {
d266c416 478 if (lf == vmove && wcursor > linebuf)
1c1e118c
MH
479 wcursor--;
480 return (0);
481 }
482 wdot++;
483 getline(*wdot);
484 wcursor = linebuf;
485 return (1);
486 } else {
487 --wcursor;
488 if (wcursor >= linebuf)
489 return (1);
490#ifdef LISPCODE
491 if (lf == lindent && linebuf[0] == '(')
492 llimit = wdot;
493#endif
494 if (wdot <= llimit) {
495 wcursor = linebuf;
496 return (0);
497 }
498 wdot--;
499 getline(*wdot);
500 wcursor = linebuf[0] == 0 ? linebuf : strend(linebuf) - 1;
501 return (1);
502 }
503}
504
505lbrack(c, f)
506 register int c;
507 int (*f)();
508{
509 register line *addr;
510
511 addr = dot;
512 for (;;) {
513 addr += dir;
514 if (addr < one || addr > dol) {
515 addr -= dir;
516 break;
517 }
518 getline(*addr);
519 if (linebuf[0] == '{' ||
520#ifdef LISPCODE
521 value(LISP) && linebuf[0] == '(' ||
522#endif
523 isa(svalue(SECTIONS))) {
524 if (c == ']' && f != vmove) {
525 addr--;
526 getline(*addr);
527 }
528 break;
529 }
530 if (c == ']' && f != vmove && linebuf[0] == '}')
531 break;
532 }
533 if (addr == dot)
534 return (0);
535 if (f != vmove)
536 wcursor = c == ']' ? strend(linebuf) : linebuf;
537 else
538 wcursor = 0;
539 wdot = addr;
540 vmoving = 0;
541 return (1);
542}
543
544isa(cp)
545 register char *cp;
546{
547
548 if (linebuf[0] != '.')
549 return (0);
550 for (; cp[0] && cp[1]; cp += 2)
551 if (linebuf[1] == cp[0]) {
552 if (linebuf[2] == cp[1])
553 return (1);
554 if (linebuf[2] == 0 && cp[1] == ' ')
555 return (1);
556 }
557 return (0);
558}