|
|
1.1 root 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
8: static char *sccsid = "@(#)ex_vops3.c 7.4 (Berkeley) 3/9/87";
9: #endif not lint
10:
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: */
31: line *llimit;
32: int (*lf)();
33:
34: #ifdef LISPCODE
35: int lindent();
36: #endif
37:
38: bool 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: */
47: lfind(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: */
126: begin:
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)) {
158: ignore(lnext());
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
218: ret:
219: strcLIN(save);
220: return (rc);
221: }
222:
223: /*
224: * Is this the end of a sentence?
225: */
226: /* ARGSUSED */
227: endsent(pastatom)
228: bool pastatom;
229: {
230: register char *cp = wcursor;
231: register int d;
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: */
246: if (!any(*cp, ".!?"))
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);
254: tryps:
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: */
264: endPS()
265: {
266:
267: return (linebuf[0] == 0 ||
268: isa(svalue(PARAGRAPHS)) || isa(svalue(SECTIONS)));
269:
270: }
271:
272: #ifdef LISPCODE
273: lindent(addr)
274: line *addr;
275: {
276: register int i;
277: char *swcurs = wcursor;
278: line *swdot = wdot;
279:
280: again:
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:
329: lmatchp(addr)
330: line *addr;
331: {
332: register int i;
333: register char *parens, *cp;
334:
335: for (cp = cursor; !any(*cp, "({[)}]");)
336: if (*cp++ == 0)
337: return (0);
338: lf = 0;
339: parens = any(*cp, "()") ? "()" : any(*cp, "[]") ? "[]" : "{}";
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:
357: lsmatch(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: }
383: else {
384: strcLIN(sp);
385: strcpy(scurs, genbuf);
386: if (!lmatchp((line *) 0))
387: beep();
388: }
389: strcLIN(sp);
390: wdot = 0;
391: wcursor = 0;
392: cursor = scurs;
393: }
394:
395: ltosolid()
396: {
397:
398: return (ltosol1("()"));
399: }
400:
401: ltosol1(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:
420: lskipbal(parens)
421: register char *parens;
422: {
423: register int level = dir;
424: register int c;
425:
426: do {
427: if (!lnext()) {
428: wdot = NOLINE;
429: return (0);
430: }
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:
440: lskipatom()
441: {
442:
443: return (lskipa1("()"));
444: }
445:
446: lskipa1(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:
468: lnext()
469: {
470:
471: if (dir > 0) {
472: if (*wcursor)
473: wcursor++;
474: if (*wcursor)
475: return (1);
476: if (wdot >= llimit) {
477: if (lf == vmove && wcursor > linebuf)
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:
504: lbrack(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:
543: isa(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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.