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