|
|
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_subr.c 7.13 (Berkeley) 5/28/90";
9: #endif not lint
10:
11: #include "ex.h"
12: #include "ex_re.h"
13: #include "ex_tty.h"
14: #include "ex_vis.h"
15: #include "pathnames.h"
16:
17: /*
18: * Random routines, in alphabetical order.
19: */
20:
21: any(c, s)
22: int c;
23: register char *s;
24: {
25: register int x;
26:
27: while (x = *s++)
28: if (x == c)
29: return (1);
30: return (0);
31: }
32:
33: backtab(i)
34: register int i;
35: {
36: register int j;
37:
38: j = i % value(SHIFTWIDTH);
39: if (j == 0)
40: j = value(SHIFTWIDTH);
41: i -= j;
42: if (i < 0)
43: i = 0;
44: return (i);
45: }
46:
47: change()
48: {
49:
50: tchng++;
51: chng = tchng;
52: }
53:
54: /*
55: * Column returns the number of
56: * columns occupied by printing the
57: * characters through position cp of the
58: * current line.
59: */
60: column(cp)
61: register char *cp;
62: {
63:
64: if (cp == 0)
65: cp = &linebuf[LBSIZE - 2];
66: return (qcolumn(cp, (char *) 0));
67: }
68:
69: /*
70: * Ignore a comment to the end of the line.
71: * This routine eats the trailing newline so don't call newline().
72: */
73: comment()
74: {
75: register int c;
76:
77: do {
78: c = ex_getchar();
79: } while (c != '\n' && c != EOF);
80: if (c == EOF)
81: ungetchar(c);
82: }
83:
84: Copy(to, from, size)
85: register char *from, *to;
86: register int size;
87: {
88:
89: if (size > 0)
90: do
91: *to++ = *from++;
92: while (--size > 0);
93: }
94:
95: copyw(to, from, size)
96: register line *from, *to;
97: register int size;
98: {
99: if (size > 0)
100: do
101: *to++ = *from++;
102: while (--size > 0);
103: }
104:
105: copywR(to, from, size)
106: register line *from, *to;
107: register int size;
108: {
109:
110: while (--size >= 0)
111: to[size] = from[size];
112: }
113:
114: ctlof(c)
115: int c;
116: {
117:
118: return (c == TRIM ? '?' : c | ('A' - 1));
119: }
120:
121: dingdong()
122: {
123:
124: if (VB)
125: putpad(VB);
126: else if (value(ERRORBELLS))
127: putch('\207');
128: }
129:
130: fixindent(indent)
131: int indent;
132: {
133: register int i;
134: register char *cp;
135:
136: i = whitecnt(genbuf);
137: cp = vpastwh(genbuf);
138: if (*cp == 0 && i == indent && linebuf[0] == 0) {
139: genbuf[0] = 0;
140: return (i);
141: }
142: CP(genindent(i), cp);
143: return (i);
144: }
145:
146: filioerr(cp)
147: char *cp;
148: {
149: register int oerrno = errno;
150:
151: lprintf("\"%s\"", cp);
152: errno = oerrno;
153: syserror();
154: }
155:
156: char *
157: genindent(indent)
158: register int indent;
159: {
160: register char *cp;
161:
162: for (cp = genbuf; indent >= value(TABSTOP); indent -= value(TABSTOP))
163: *cp++ = '\t';
164: for (; indent > 0; indent--)
165: *cp++ = ' ';
166: return (cp);
167: }
168:
169: getDOT()
170: {
171:
172: getline(*dot);
173: }
174:
175: line *
176: getmark(c)
177: register int c;
178: {
179: register line *addr;
180:
181: for (addr = one; addr <= dol; addr++)
182: if (names[c - 'a'] == (*addr &~ 01)) {
183: return (addr);
184: }
185: return (0);
186: }
187:
188: getn(cp)
189: register char *cp;
190: {
191: register int i = 0;
192:
193: while (isdigit(*cp))
194: i = i * 10 + *cp++ - '0';
195: if (*cp)
196: return (0);
197: return (i);
198: }
199:
200: ignnEOF()
201: {
202: register int c = ex_getchar();
203:
204: if (c == EOF)
205: ungetchar(c);
206: else if (c=='"')
207: comment();
208: }
209:
210: iswhite(c)
211: int c;
212: {
213:
214: return (c == ' ' || c == '\t');
215: }
216:
217: junk(c)
218: register int c;
219: {
220:
221: if (c && !value(BEAUTIFY))
222: return (0);
223: if (c >= ' ' && c != TRIM)
224: return (0);
225: switch (c) {
226:
227: case '\t':
228: case '\n':
229: case '\f':
230: return (0);
231:
232: default:
233: return (1);
234: }
235: }
236:
237: killed()
238: {
239:
240: killcnt(addr2 - addr1 + 1);
241: }
242:
243: killcnt(cnt)
244: register int cnt;
245: {
246:
247: if (inopen) {
248: notecnt = cnt;
249: notenam = notesgn = "";
250: return;
251: }
252: if (!notable(cnt))
253: return;
254: ex_printf("%d lines", cnt);
255: if (value(TERSE) == 0) {
256: ex_printf(" %c%s", Command[0] | ' ', Command + 1);
257: if (Command[strlen(Command) - 1] != 'e')
258: ex_putchar('e');
259: ex_putchar('d');
260: }
261: putNFL();
262: }
263:
264: lineno(a)
265: line *a;
266: {
267:
268: return (a - zero);
269: }
270:
271: lineDOL()
272: {
273:
274: return (lineno(dol));
275: }
276:
277: lineDOT()
278: {
279:
280: return (lineno(dot));
281: }
282:
283: markDOT()
284: {
285:
286: markpr(dot);
287: }
288:
289: markpr(which)
290: line *which;
291: {
292:
293: if ((inglobal == 0 || inopen) && which <= endcore) {
294: names['z'-'a'+1] = *which & ~01;
295: if (inopen)
296: ncols['z'-'a'+1] = cursor;
297: }
298: }
299:
300: markreg(c)
301: register int c;
302: {
303:
304: if (c == '\'' || c == '`')
305: return ('z' + 1);
306: if (c >= 'a' && c <= 'z')
307: return (c);
308: return (0);
309: }
310:
311: /*
312: * Mesg decodes the terse/verbose strings. Thus
313: * 'xxx@yyy' -> 'xxx' if terse, else 'xxx yyy'
314: * 'xxx|yyy' -> 'xxx' if terse, else 'yyy'
315: * All others map to themselves.
316: */
317: char *
318: mesg(str)
319: register char *str;
320: {
321: register char *cp;
322:
323: str = strcpy(genbuf, str);
324: for (cp = str; *cp; cp++)
325: switch (*cp) {
326:
327: case '@':
328: if (value(TERSE))
329: *cp = 0;
330: else
331: *cp = ' ';
332: break;
333:
334: case '|':
335: if (value(TERSE) == 0)
336: return (cp + 1);
337: *cp = 0;
338: break;
339: }
340: return (str);
341: }
342:
343: /*VARARGS2*/
344: merror(seekpt, i)
345: #ifndef EXSTRINGS
346: char *seekpt;
347: #else
348: # ifdef lint
349: char *seekpt;
350: # else
351: int seekpt;
352: # endif
353: #endif
354: int i;
355: {
356: register char *cp = linebuf;
357:
358: if (seekpt == 0)
359: return;
360: merror1(seekpt);
361: if (*cp == '\n')
362: putnl(), cp++;
363: if (inopen > 0 && CE)
364: vclreol();
365: if (SO && SE)
366: putpad(SO);
367: ex_printf(mesg(cp), i);
368: if (SO && SE)
369: putpad(SE);
370: }
371:
372: merror1(seekpt)
373: #ifndef EXSTRINGS
374: char *seekpt;
375: #else
376: # ifdef lint
377: char *seekpt;
378: # else
379: int seekpt;
380: # endif
381: #endif
382: {
383:
384: #ifndef EXSTRINGS
385: strcpy(linebuf, seekpt);
386: #else
387: lseek(erfile, (long) seekpt, 0);
388: if (read(erfile, linebuf, 128) < 2)
389: CP(linebuf, "ERROR");
390: #endif
391: }
392:
393: morelines()
394: {
395: #ifdef UNIX_SBRK
396: char *sbrk();
397:
398: if ((int) sbrk(1024 * sizeof (line)) == -1)
399: return (-1);
400: endcore += 1024;
401: return (0);
402: #else
403: /*
404: * We can never be guaranteed that we can get more memory
405: * beyond "endcore". So we just punt every time.
406: */
407: return -1;
408: #endif
409: }
410:
411: nonzero()
412: {
413:
414: if (addr1 == zero) {
415: notempty();
416: error("Nonzero address required@on this command");
417: }
418: }
419:
420: notable(i)
421: int i;
422: {
423:
424: return (hush == 0 && !inglobal && i > value(REPORT));
425: }
426:
427:
428: notempty()
429: {
430:
431: if (dol == zero)
432: error("No lines@in the buffer");
433: }
434:
435:
436: netchHAD(cnt)
437: int cnt;
438: {
439:
440: netchange(lineDOL() - cnt);
441: }
442:
443: netchange(i)
444: register int i;
445: {
446: register char *cp;
447:
448: if (i > 0)
449: notesgn = cp = "more ";
450: else
451: notesgn = cp = "fewer ", i = -i;
452: if (inopen) {
453: notecnt = i;
454: notenam = "";
455: return;
456: }
457: if (!notable(i))
458: return;
459: ex_printf(mesg("%d %slines@in file after %s"), i, cp, Command);
460: putNFL();
461: }
462:
463: putmark(addr)
464: line *addr;
465: {
466:
467: putmk1(addr, putline());
468: }
469:
470: putmk1(addr, n)
471: register line *addr;
472: int n;
473: {
474: register line *markp;
475: register oldglobmk;
476:
477: oldglobmk = *addr & 1;
478: *addr &= ~1;
479: for (markp = (anymarks ? names : &names['z'-'a'+1]);
480: markp <= &names['z'-'a'+1]; markp++)
481: if (*markp == *addr)
482: *markp = n;
483: *addr = n | oldglobmk;
484: }
485:
486: char *
487: plural(i)
488: long i;
489: {
490:
491: return (i == 1 ? "" : "s");
492: }
493:
494: int qcount();
495: short vcntcol;
496:
497: qcolumn(lim, gp)
498: register char *lim, *gp;
499: {
500: register int x;
501: int (*OO)();
502:
503: OO = Outchar;
504: Outchar = qcount;
505: vcntcol = 0;
506: if (lim != NULL)
507: x = lim[1], lim[1] = 0;
508: pline(0);
509: if (lim != NULL)
510: lim[1] = x;
511: if (gp)
512: while (*gp)
513: ex_putchar(*gp++);
514: Outchar = OO;
515: return (vcntcol);
516: }
517:
518: int
519: qcount(c)
520: int c;
521: {
522:
523: if (c == '\t') {
524: vcntcol += value(TABSTOP) - vcntcol % value(TABSTOP);
525: return;
526: }
527: vcntcol++;
528: }
529:
530: reverse(a1, a2)
531: register line *a1, *a2;
532: {
533: register line t;
534:
535: for (;;) {
536: t = *--a2;
537: if (a2 <= a1)
538: return;
539: *a2 = *a1;
540: *a1++ = t;
541: }
542: }
543:
544: save(a1, a2)
545: line *a1;
546: register line *a2;
547: {
548: register int more;
549:
550: if (!FIXUNDO)
551: return;
552: #ifdef TRACE
553: if (trace)
554: vudump("before save");
555: #endif
556: undkind = UNDNONE;
557: undadot = dot;
558: more = (a2 - a1 + 1) - (unddol - dol);
559: while (more > (endcore - truedol))
560: if (morelines() < 0)
561: #ifdef UNIX_SBRK
562: error("Out of memory@saving lines for undo - try using ed");
563: #else
564: error("Out of memory@saving lines for undo - try increasing linelimit");
565: #endif
566: if (more)
567: (*(more > 0 ? copywR : copyw))(unddol + more + 1, unddol + 1,
568: (truedol - unddol));
569: unddol += more;
570: truedol += more;
571: copyw(dol + 1, a1, a2 - a1 + 1);
572: undkind = UNDALL;
573: unddel = a1 - 1;
574: undap1 = a1;
575: undap2 = a2 + 1;
576: #ifdef TRACE
577: if (trace)
578: vudump("after save");
579: #endif
580: }
581:
582: save12()
583: {
584:
585: save(addr1, addr2);
586: }
587:
588: saveall()
589: {
590:
591: save(one, dol);
592: }
593:
594: span()
595: {
596:
597: return (addr2 - addr1 + 1);
598: }
599:
600: ex_sync()
601: {
602:
603: chng = 0;
604: tchng = 0;
605: xchng = 0;
606: }
607:
608:
609: skipwh()
610: {
611: register int wh;
612:
613: wh = 0;
614: while (iswhite(peekchar())) {
615: wh++;
616: ignchar();
617: }
618: return (wh);
619: }
620:
621: /*VARARGS2*/
622: smerror(seekpt, cp)
623: #ifdef lint
624: char *seekpt;
625: #else
626: int seekpt;
627: #endif
628: char *cp;
629: {
630:
631: if (seekpt == 0)
632: return;
633: merror1(seekpt);
634: if (inopen && CE)
635: vclreol();
636: if (SO && SE)
637: putpad(SO);
638: lprintf(mesg(linebuf), cp);
639: if (SO && SE)
640: putpad(SE);
641: }
642:
643: char *
644: strend(cp)
645: register char *cp;
646: {
647:
648: while (*cp)
649: cp++;
650: return (cp);
651: }
652:
653: strcLIN(dp)
654: char *dp;
655: {
656:
657: CP(linebuf, dp);
658: }
659:
660: syserror()
661: {
662: char *strerror();
663:
664: dirtcnt = 0;
665: ex_putchar(' ');
666: error(strerror(errno));
667: }
668:
669: /*
670: * Return the column number that results from being in column col and
671: * hitting a tab, where tabs are set every ts columns. Work right for
672: * the case where col > COLUMNS, even if ts does not divide COLUMNS.
673: */
674: tabcol(col, ts)
675: int col, ts;
676: {
677: int offset, result;
678:
679: if (col >= COLUMNS) {
680: offset = COLUMNS * (col/COLUMNS);
681: col -= offset;
682: } else
683: offset = 0;
684: result = col + ts - (col % ts) + offset;
685: return (result);
686: }
687:
688: char *
689: vfindcol(i)
690: int i;
691: {
692: register char *cp;
693: register int (*OO)() = Outchar;
694:
695: Outchar = qcount;
696: ignore(qcolumn(linebuf - 1, NOSTR));
697: for (cp = linebuf; *cp && vcntcol < i; cp++)
698: ex_putchar(*cp);
699: if (cp != linebuf)
700: cp--;
701: Outchar = OO;
702: return (cp);
703: }
704:
705: char *
706: vskipwh(cp)
707: register char *cp;
708: {
709:
710: while (iswhite(*cp) && cp[1])
711: cp++;
712: return (cp);
713: }
714:
715:
716: char *
717: vpastwh(cp)
718: register char *cp;
719: {
720:
721: while (iswhite(*cp))
722: cp++;
723: return (cp);
724: }
725:
726: whitecnt(cp)
727: register char *cp;
728: {
729: register int i;
730:
731: i = 0;
732: for (;;)
733: switch (*cp++) {
734:
735: case '\t':
736: i += value(TABSTOP) - i % value(TABSTOP);
737: break;
738:
739: case ' ':
740: i++;
741: break;
742:
743: default:
744: return (i);
745: }
746: }
747:
748: #ifdef lint
749: Ignore(a)
750: char *a;
751: {
752:
753: a = a;
754: }
755:
756: Ignorf(a)
757: int (*a)();
758: {
759:
760: a = a;
761: }
762: #endif
763:
764: markit(addr)
765: line *addr;
766: {
767:
768: if (addr != dot && addr >= one && addr <= dol)
769: markDOT();
770: }
771:
772: /*
773: * The following code is defensive programming against a bug in the
774: * pdp-11 overlay implementation. Sometimes it goes nuts and asks
775: * for an overlay with some garbage number, which generates an emt
776: * trap. This is a less than elegant solution, but it is somewhat
777: * better than core dumping and losing your work, leaving your tty
778: * in a weird state, etc.
779: */
780: int _ovno;
781: onemt()
782: {
783: signal(SIGEMT, onemt);
784: /* 2 and 3 are valid on 11/40 type vi, so */
785: if (_ovno < 0 || _ovno > 3)
786: _ovno = 0;
787: error("emt trap, _ovno is %d @ - try again");
788: }
789:
790: /*
791: * When a hangup occurs our actions are similar to a preserve
792: * command. If the buffer has not been [Modified], then we do
793: * nothing but remove the temporary files and exit.
794: * Otherwise, we sync the temp file and then attempt a preserve.
795: * If the preserve succeeds, we unlink our temp files.
796: * If the preserve fails, we leave the temp files as they are
797: * as they are a backup even without preservation if they
798: * are not removed.
799: */
800: onhup()
801: {
802:
803: /*
804: * USG tty driver can send multiple HUP's!!
805: */
806: signal(SIGINT, SIG_IGN);
807: signal(SIGHUP, SIG_IGN);
808: if (chng == 0) {
809: cleanup(1);
810: ex_exit(0);
811: }
812: if (setexit() == 0) {
813: if (preserve()) {
814: cleanup(1);
815: ex_exit(0);
816: }
817: }
818: ex_exit(1);
819: }
820:
821: /*
822: * An interrupt occurred. Drain any output which
823: * is still in the output buffering pipeline.
824: * Catch interrupts again. Unless we are in visual
825: * reset the output state (out of -nl mode, e.g).
826: * Then like a normal error (with the \n before Interrupt
827: * suppressed in visual mode).
828: */
829: onintr()
830: {
831:
832: #ifndef CBREAK
833: signal(SIGINT, onintr);
834: #else
835: signal(SIGINT, inopen ? vintr : onintr);
836: #endif
837: alarm(0); /* in case we were called from map */
838: draino();
839: if (!inopen) {
840: pstop();
841: setlastchar('\n');
842: #ifdef CBREAK
843: }
844: #else
845: } else
846: vraw();
847: #endif
848: error("\nInterrupt" + inopen);
849: }
850:
851: /*
852: * If we are interruptible, enable interrupts again.
853: * In some critical sections we turn interrupts off,
854: * but not very often.
855: */
856: setrupt()
857: {
858:
859: if (ruptible) {
860: #ifndef CBREAK
861: signal(SIGINT, onintr);
862: #else
863: signal(SIGINT, inopen ? vintr : onintr);
864: #endif
865: #ifdef SIGTSTP
866: if (dosusp)
867: signal(SIGTSTP, onsusp);
868: #endif
869: }
870: }
871:
872: preserve()
873: {
874:
875: #ifdef VMUNIX
876: tflush();
877: #endif
878: synctmp();
879: pid = vfork();
880: if (pid < 0)
881: return (0);
882: if (pid == 0) {
883: close(0);
884: dup(tfile);
885: execl(_PATH_EXPRESERVE, "expreserve", (char *) 0);
886: ex_exit(1);
887: }
888: waitfor();
889: if (rpid == pid && status == 0)
890: return (1);
891: return (0);
892: }
893:
894: #ifndef V6
895: ex_exit(i)
896: int i;
897: {
898:
899: # ifdef TRACE
900: if (trace)
901: fclose(trace);
902: # endif
903: _exit(i);
904: }
905: #endif
906:
907: #ifdef SIGTSTP
908: /*
909: * We have just gotten a susp. Suspend and prepare to resume.
910: */
911: onsusp()
912: {
913: ttymode f;
914: struct winsize win;
915:
916: f = setty(normf);
917: vnfl();
918: putpad(TE);
919: flush();
920:
921: (void) sigsetmask(0);
922: signal(SIGTSTP, SIG_DFL);
923: kill(0, SIGTSTP);
924:
925: /* the pc stops here */
926:
927: signal(SIGTSTP, onsusp);
928: vcontin(0);
929: ignore(setty(f));
930: if (!inopen)
931: error((char *) 0);
932: else {
933: #ifdef TIOCGWINSZ
934: if (ioctl(0, TIOCGWINSZ, &win) >= 0)
935: if (win.ws_row != winsz.ws_row ||
936: win.ws_col != winsz.ws_col)
937: winch();
938: #endif
939: if (vcnt < 0) {
940: vcnt = -vcnt;
941: if (state == VISUAL)
942: vclear();
943: else if (state == CRTOPEN)
944: vcnt = 0;
945: }
946: vdirty(0, LINES);
947: vrepaint(cursor);
948: }
949: }
950: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.