|
|
1.1 root 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: */
22: line *llimit;
23: int (*lf)();
24:
25: #ifdef LISPCODE
26: int lindent();
27: #endif
28:
29: bool 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: */
38: lfind(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: */
117: begin:
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
209: ret:
210: strcLIN(save);
211: return (rc);
212: }
213:
214: /*
215: * Is this the end of a sentence?
216: */
217: endsent(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);
244: tryps:
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: */
254: endPS()
255: {
256:
257: return (linebuf[0] == 0 ||
258: isa(svalue(PARAGRAPHS)) || isa(svalue(SECTIONS)));
259:
260: }
261:
262: #ifdef LISPCODE
263: lindent(addr)
264: line *addr;
265: {
266: register int i;
267: char *swcurs = wcursor;
268: line *swdot = wdot;
269:
270: again:
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:
319: lmatchp(addr)
320: line *addr;
321: {
322: register int i;
323: register char *parens, *cp;
324:
325: for (cp = cursor; !any(*cp, "({)}");)
326: if (*cp++ == 0)
327: return (0);
328: lf = 0;
329: parens = any(*cp, "()") ? "()" : "{}";
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:
347: lsmatch(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: }
373: strcLIN(sp);
374: wdot = 0;
375: wcursor = 0;
376: cursor = scurs;
377: }
378:
379: ltosolid()
380: {
381:
382: return (ltosol1("()"));
383: }
384:
385: ltosol1(parens)
386: register char *parens;
387: {
388: register char *cp;
389:
390: if (*parens && !*wcursor && !lnext())
391: return (0);
392: while (isspace(*wcursor) || (*wcursor == 0 && *parens))
393: if (!lnext())
394: return (0);
395: if (any(*wcursor, parens) || dir > 0)
396: return (1);
397: for (cp = wcursor; cp > linebuf; cp--)
398: if (isspace(cp[-1]) || any(cp[-1], parens))
399: break;
400: wcursor = cp;
401: return (1);
402: }
403:
404: lskipbal(parens)
405: register char *parens;
406: {
407: register int level = dir;
408: register int c;
409:
410: do {
411: if (!lnext())
412: return (0);
413: c = *wcursor;
414: if (c == parens[1])
415: level--;
416: else if (c == parens[0])
417: level++;
418: } while (level);
419: return (1);
420: }
421:
422: lskipatom()
423: {
424:
425: return (lskipa1("()"));
426: }
427:
428: lskipa1(parens)
429: register char *parens;
430: {
431: register int c;
432:
433: for (;;) {
434: if (dir < 0 && wcursor == linebuf) {
435: if (!lnext())
436: return (0);
437: break;
438: }
439: c = *wcursor;
440: if (c && (isspace(c) || any(c, parens)))
441: break;
442: if (!lnext())
443: return (0);
444: if (dir > 0 && wcursor == linebuf)
445: break;
446: }
447: return (ltosol1(parens));
448: }
449:
450: lnext()
451: {
452:
453: if (dir > 0) {
454: if (*wcursor)
455: wcursor++;
456: if (*wcursor)
457: return (1);
458: if (wdot >= llimit) {
459: if (wcursor > linebuf)
460: wcursor--;
461: return (0);
462: }
463: wdot++;
464: getline(*wdot);
465: wcursor = linebuf;
466: return (1);
467: } else {
468: --wcursor;
469: if (wcursor >= linebuf)
470: return (1);
471: #ifdef LISPCODE
472: if (lf == lindent && linebuf[0] == '(')
473: llimit = wdot;
474: #endif
475: if (wdot <= llimit) {
476: wcursor = linebuf;
477: return (0);
478: }
479: wdot--;
480: getline(*wdot);
481: wcursor = linebuf[0] == 0 ? linebuf : strend(linebuf) - 1;
482: return (1);
483: }
484: }
485:
486: lbrack(c, f)
487: register int c;
488: int (*f)();
489: {
490: register line *addr;
491:
492: addr = dot;
493: for (;;) {
494: addr += dir;
495: if (addr < one || addr > dol) {
496: addr -= dir;
497: break;
498: }
499: getline(*addr);
500: if (linebuf[0] == '{' ||
501: #ifdef LISPCODE
502: value(LISP) && linebuf[0] == '(' ||
503: #endif
504: isa(svalue(SECTIONS))) {
505: if (c == ']' && f != vmove) {
506: addr--;
507: getline(*addr);
508: }
509: break;
510: }
511: if (c == ']' && f != vmove && linebuf[0] == '}')
512: break;
513: }
514: if (addr == dot)
515: return (0);
516: if (f != vmove)
517: wcursor = c == ']' ? strend(linebuf) : linebuf;
518: else
519: wcursor = 0;
520: wdot = addr;
521: vmoving = 0;
522: return (1);
523: }
524:
525: isa(cp)
526: register char *cp;
527: {
528:
529: if (linebuf[0] != '.')
530: return (0);
531: for (; cp[0] && cp[1]; cp += 2)
532: if (linebuf[1] == cp[0]) {
533: if (linebuf[2] == cp[1])
534: return (1);
535: if (linebuf[2] == 0 && cp[1] == ' ')
536: return (1);
537: }
538: return (0);
539: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.