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.10 (Berkeley) 6/7/85";
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:
16: /*
17: * Random routines, in alphabetical order.
18: */
19:
20: any(c, s)
21: int c;
22: register char *s;
23: {
24: register int x;
25:
26: while (x = *s++)
27: if (x == c)
28: return (1);
29: return (0);
30: }
31:
32: backtab(i)
33: register int i;
34: {
35: register int j;
36:
37: j = i % value(SHIFTWIDTH);
38: if (j == 0)
39: j = value(SHIFTWIDTH);
40: i -= j;
41: if (i < 0)
42: i = 0;
43: return (i);
44: }
45:
46: change()
47: {
48:
49: tchng++;
50: chng = tchng;
51: }
52:
53: /*
54: * Column returns the number of
55: * columns occupied by printing the
56: * characters through position cp of the
57: * current line.
58: */
59: column(cp)
60: register char *cp;
61: {
62:
63: if (cp == 0)
64: cp = &linebuf[LBSIZE - 2];
65: return (qcolumn(cp, (char *) 0));
66: }
67:
68: /*
69: * Ignore a comment to the end of the line.
70: * This routine eats the trailing newline so don't call newline().
71: */
72: ()
73: {
74: register int c;
75:
76: do {
77: c = getchar();
78: } while (c != '\n' && c != EOF);
79: if (c == EOF)
80: ungetchar(c);
81: }
82:
83: Copy(to, from, size)
84: register char *from, *to;
85: register int size;
86: {
87:
88: if (size > 0)
89: do
90: *to++ = *from++;
91: while (--size > 0);
92: }
93:
94: copyw(to, from, size)
95: register line *from, *to;
96: register int size;
97: {
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 = 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: printf("%d lines", cnt);
255: if (value(TERSE) == 0) {
256: printf(" %c%s", Command[0] | ' ', Command + 1);
257: if (Command[strlen(Command) - 1] != 'e')
258: putchar('e');
259: 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: #ifdef VMUNIX
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: printf(mesg(cp), i);
368: if (SO && SE)
369: putpad(SE);
370: }
371:
372: merror1(seekpt)
373: #ifdef VMUNIX
374: char *seekpt;
375: #else
376: # ifdef lint
377: char *seekpt;
378: # else
379: int seekpt;
380: # endif
381: #endif
382: {
383:
384: #ifdef VMUNIX
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:
396: if ((int) sbrk(1024 * sizeof (line)) == -1)
397: return (-1);
398: endcore += 1024;
399: return (0);
400: }
401:
402: nonzero()
403: {
404:
405: if (addr1 == zero) {
406: notempty();
407: error("Nonzero address required@on this command");
408: }
409: }
410:
411: notable(i)
412: int i;
413: {
414:
415: return (hush == 0 && !inglobal && i > value(REPORT));
416: }
417:
418:
419: notempty()
420: {
421:
422: if (dol == zero)
423: error("No lines@in the buffer");
424: }
425:
426:
427: netchHAD(cnt)
428: int cnt;
429: {
430:
431: netchange(lineDOL() - cnt);
432: }
433:
434: netchange(i)
435: register int i;
436: {
437: register char *cp;
438:
439: if (i > 0)
440: notesgn = cp = "more ";
441: else
442: notesgn = cp = "fewer ", i = -i;
443: if (inopen) {
444: notecnt = i;
445: notenam = "";
446: return;
447: }
448: if (!notable(i))
449: return;
450: printf(mesg("%d %slines@in file after %s"), i, cp, Command);
451: putNFL();
452: }
453:
454: putmark(addr)
455: line *addr;
456: {
457:
458: putmk1(addr, putline());
459: }
460:
461: putmk1(addr, n)
462: register line *addr;
463: int n;
464: {
465: register line *markp;
466: register oldglobmk;
467:
468: oldglobmk = *addr & 1;
469: *addr &= ~1;
470: for (markp = (anymarks ? names : &names['z'-'a'+1]);
471: markp <= &names['z'-'a'+1]; markp++)
472: if (*markp == *addr)
473: *markp = n;
474: *addr = n | oldglobmk;
475: }
476:
477: char *
478: plural(i)
479: long i;
480: {
481:
482: return (i == 1 ? "" : "s");
483: }
484:
485: int qcount();
486: short vcntcol;
487:
488: qcolumn(lim, gp)
489: register char *lim, *gp;
490: {
491: register int x;
492: int (*OO)();
493:
494: OO = Outchar;
495: Outchar = qcount;
496: vcntcol = 0;
497: if (lim != NULL)
498: x = lim[1], lim[1] = 0;
499: pline(0);
500: if (lim != NULL)
501: lim[1] = x;
502: if (gp)
503: while (*gp)
504: putchar(*gp++);
505: Outchar = OO;
506: return (vcntcol);
507: }
508:
509: int
510: qcount(c)
511: int c;
512: {
513:
514: if (c == '\t') {
515: vcntcol += value(TABSTOP) - vcntcol % value(TABSTOP);
516: return;
517: }
518: vcntcol++;
519: }
520:
521: reverse(a1, a2)
522: register line *a1, *a2;
523: {
524: register line t;
525:
526: for (;;) {
527: t = *--a2;
528: if (a2 <= a1)
529: return;
530: *a2 = *a1;
531: *a1++ = t;
532: }
533: }
534:
535: save(a1, a2)
536: line *a1;
537: register line *a2;
538: {
539: register int more;
540:
541: if (!FIXUNDO)
542: return;
543: #ifdef TRACE
544: if (trace)
545: vudump("before save");
546: #endif
547: undkind = UNDNONE;
548: undadot = dot;
549: more = (a2 - a1 + 1) - (unddol - dol);
550: while (more > (endcore - truedol))
551: if (morelines() < 0)
552: error("Out of memory@saving lines for undo - try using ed");
553: if (more)
554: (*(more > 0 ? copywR : copyw))(unddol + more + 1, unddol + 1,
555: (truedol - unddol));
556: unddol += more;
557: truedol += more;
558: copyw(dol + 1, a1, a2 - a1 + 1);
559: undkind = UNDALL;
560: unddel = a1 - 1;
561: undap1 = a1;
562: undap2 = a2 + 1;
563: #ifdef TRACE
564: if (trace)
565: vudump("after save");
566: #endif
567: }
568:
569: save12()
570: {
571:
572: save(addr1, addr2);
573: }
574:
575: saveall()
576: {
577:
578: save(one, dol);
579: }
580:
581: span()
582: {
583:
584: return (addr2 - addr1 + 1);
585: }
586:
587: sync()
588: {
589:
590: chng = 0;
591: tchng = 0;
592: xchng = 0;
593: }
594:
595:
596: skipwh()
597: {
598: register int wh;
599:
600: wh = 0;
601: while (iswhite(peekchar())) {
602: wh++;
603: ignchar();
604: }
605: return (wh);
606: }
607:
608: /*VARARGS2*/
609: smerror(seekpt, cp)
610: #ifdef lint
611: char *seekpt;
612: #else
613: int seekpt;
614: #endif
615: char *cp;
616: {
617:
618: if (seekpt == 0)
619: return;
620: merror1(seekpt);
621: if (inopen && CE)
622: vclreol();
623: if (SO && SE)
624: putpad(SO);
625: lprintf(mesg(linebuf), cp);
626: if (SO && SE)
627: putpad(SE);
628: }
629:
630: char *
631: strend(cp)
632: register char *cp;
633: {
634:
635: while (*cp)
636: cp++;
637: return (cp);
638: }
639:
640: strcLIN(dp)
641: char *dp;
642: {
643:
644: CP(linebuf, dp);
645: }
646:
647: syserror()
648: {
649: register int e = errno;
650: extern int sys_nerr;
651: extern char *sys_errlist[];
652:
653: dirtcnt = 0;
654: putchar(' ');
655: if (e >= 0 && e <= sys_nerr)
656: error(sys_errlist[e]);
657: else
658: error("System error %d", e);
659: }
660:
661: /*
662: * Return the column number that results from being in column col and
663: * hitting a tab, where tabs are set every ts columns. Work right for
664: * the case where col > COLUMNS, even if ts does not divide COLUMNS.
665: */
666: tabcol(col, ts)
667: int col, ts;
668: {
669: int offset, result;
670:
671: if (col >= COLUMNS) {
672: offset = COLUMNS * (col/COLUMNS);
673: col -= offset;
674: } else
675: offset = 0;
676: result = col + ts - (col % ts) + offset;
677: return (result);
678: }
679:
680: char *
681: vfindcol(i)
682: int i;
683: {
684: register char *cp;
685: register int (*OO)() = Outchar;
686:
687: Outchar = qcount;
688: ignore(qcolumn(linebuf - 1, NOSTR));
689: for (cp = linebuf; *cp && vcntcol < i; cp++)
690: putchar(*cp);
691: if (cp != linebuf)
692: cp--;
693: Outchar = OO;
694: return (cp);
695: }
696:
697: char *
698: vskipwh(cp)
699: register char *cp;
700: {
701:
702: while (iswhite(*cp) && cp[1])
703: cp++;
704: return (cp);
705: }
706:
707:
708: char *
709: vpastwh(cp)
710: register char *cp;
711: {
712:
713: while (iswhite(*cp))
714: cp++;
715: return (cp);
716: }
717:
718: whitecnt(cp)
719: register char *cp;
720: {
721: register int i;
722:
723: i = 0;
724: for (;;)
725: switch (*cp++) {
726:
727: case '\t':
728: i += value(TABSTOP) - i % value(TABSTOP);
729: break;
730:
731: case ' ':
732: i++;
733: break;
734:
735: default:
736: return (i);
737: }
738: }
739:
740: #ifdef lint
741: Ignore(a)
742: char *a;
743: {
744:
745: a = a;
746: }
747:
748: Ignorf(a)
749: int (*a)();
750: {
751:
752: a = a;
753: }
754: #endif
755:
756: markit(addr)
757: line *addr;
758: {
759:
760: if (addr != dot && addr >= one && addr <= dol)
761: markDOT();
762: }
763:
764: /*
765: * The following code is defensive programming against a bug in the
766: * pdp-11 overlay implementation. Sometimes it goes nuts and asks
767: * for an overlay with some garbage number, which generates an emt
768: * trap. This is a less than elegant solution, but it is somewhat
769: * better than core dumping and losing your work, leaving your tty
770: * in a weird state, etc.
771: */
772: int _ovno;
773: onemt()
774: {
775: int oovno;
776:
777: signal(SIGEMT, onemt);
778: oovno = _ovno;
779: /* 2 and 3 are valid on 11/40 type vi, so */
780: if (_ovno < 0 || _ovno > 3)
781: _ovno = 0;
782: error("emt trap, _ovno is %d @ - try again");
783: }
784:
785: /*
786: * When a hangup occurs our actions are similar to a preserve
787: * command. If the buffer has not been [Modified], then we do
788: * nothing but remove the temporary files and exit.
789: * Otherwise, we sync the temp file and then attempt a preserve.
790: * If the preserve succeeds, we unlink our temp files.
791: * If the preserve fails, we leave the temp files as they are
792: * as they are a backup even without preservation if they
793: * are not removed.
794: */
795: onhup()
796: {
797:
798: /*
799: * USG tty driver can send multiple HUP's!!
800: */
801: signal(SIGINT, SIG_IGN);
802: signal(SIGHUP, SIG_IGN);
803: if (chng == 0) {
804: cleanup(1);
805: exit(0);
806: }
807: if (setexit() == 0) {
808: if (preserve()) {
809: cleanup(1);
810: exit(0);
811: }
812: }
813: exit(1);
814: }
815:
816: /*
817: * An interrupt occurred. Drain any output which
818: * is still in the output buffering pipeline.
819: * Catch interrupts again. Unless we are in visual
820: * reset the output state (out of -nl mode, e.g).
821: * Then like a normal error (with the \n before Interrupt
822: * suppressed in visual mode).
823: */
824: onintr()
825: {
826:
827: #ifndef CBREAK
828: signal(SIGINT, onintr);
829: #else
830: signal(SIGINT, inopen ? vintr : onintr);
831: #endif
832: alarm(0); /* in case we were called from map */
833: draino();
834: if (!inopen) {
835: pstop();
836: setlastchar('\n');
837: #ifdef CBREAK
838: }
839: #else
840: } else
841: vraw();
842: #endif
843: error("\nInterrupt" + inopen);
844: }
845:
846: /*
847: * If we are interruptible, enable interrupts again.
848: * In some critical sections we turn interrupts off,
849: * but not very often.
850: */
851: setrupt()
852: {
853:
854: if (ruptible) {
855: #ifndef CBREAK
856: signal(SIGINT, onintr);
857: #else
858: signal(SIGINT, inopen ? vintr : onintr);
859: #endif
860: #ifdef SIGTSTP
861: if (dosusp)
862: signal(SIGTSTP, onsusp);
863: #endif
864: }
865: }
866:
867: preserve()
868: {
869:
870: #ifdef VMUNIX
871: tflush();
872: #endif
873: synctmp();
874: pid = fork();
875: if (pid < 0)
876: return (0);
877: if (pid == 0) {
878: close(0);
879: dup(tfile);
880: execl(EXPRESERVE, "expreserve", (char *) 0);
881: exit(1);
882: }
883: waitfor();
884: if (rpid == pid && status == 0)
885: return (1);
886: return (0);
887: }
888:
889: #ifndef V6
890: exit(i)
891: int i;
892: {
893:
894: # ifdef TRACE
895: if (trace)
896: fclose(trace);
897: # endif
898: _exit(i);
899: }
900: #endif
901:
902: #ifdef SIGTSTP
903: /*
904: * We have just gotten a susp. Suspend and prepare to resume.
905: */
906: onsusp()
907: {
908: ttymode f;
909: int omask;
910: struct winsize win;
911:
912: f = setty(normf);
913: vnfl();
914: putpad(TE);
915: flush();
916:
917: (void) sigsetmask(0);
918: signal(SIGTSTP, SIG_DFL);
919: kill(0, SIGTSTP);
920:
921: /* the pc stops here */
922:
923: signal(SIGTSTP, onsusp);
924: vcontin(0);
925: setty(f);
926: if (!inopen)
927: error(0);
928: else {
929: if (ioctl(0, TIOCGWINSZ, &win) >= 0)
930: if (win.ws_row != winsz.ws_row ||
931: win.ws_col != winsz.ws_col)
932: winch();
933: if (vcnt < 0) {
934: vcnt = -vcnt;
935: if (state == VISUAL)
936: vclear();
937: else if (state == CRTOPEN)
938: vcnt = 0;
939: }
940: vdirty(0, LINES);
941: vrepaint(cursor);
942: }
943: }
944: #endif