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