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