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: #if !defined(lint) && defined(DOSCCS)
8: static char *sccsid = "@(#)ex_subr.c 7.10.1 (2.11BSD) 1996/3/22";
9: #endif
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:
650: dirtcnt = 0;
651: putchar(' ');
652: error("%s", strerror(errno));
653: }
654:
655: /*
656: * Return the column number that results from being in column col and
657: * hitting a tab, where tabs are set every ts columns. Work right for
658: * the case where col > COLUMNS, even if ts does not divide COLUMNS.
659: */
660: tabcol(col, ts)
661: int col, ts;
662: {
663: int offset, result;
664:
665: if (col >= COLUMNS) {
666: offset = COLUMNS * (col/COLUMNS);
667: col -= offset;
668: } else
669: offset = 0;
670: result = col + ts - (col % ts) + offset;
671: return (result);
672: }
673:
674: char *
675: vfindcol(i)
676: int i;
677: {
678: register char *cp;
679: register int (*OO)() = Outchar;
680:
681: Outchar = qcount;
682: ignore(qcolumn(linebuf - 1, NOSTR));
683: for (cp = linebuf; *cp && vcntcol < i; cp++)
684: putchar(*cp);
685: if (cp != linebuf)
686: cp--;
687: Outchar = OO;
688: return (cp);
689: }
690:
691: char *
692: vskipwh(cp)
693: register char *cp;
694: {
695:
696: while (iswhite(*cp) && cp[1])
697: cp++;
698: return (cp);
699: }
700:
701:
702: char *
703: vpastwh(cp)
704: register char *cp;
705: {
706:
707: while (iswhite(*cp))
708: cp++;
709: return (cp);
710: }
711:
712: whitecnt(cp)
713: register char *cp;
714: {
715: register int i;
716:
717: i = 0;
718: for (;;)
719: switch (*cp++) {
720:
721: case '\t':
722: i += value(TABSTOP) - i % value(TABSTOP);
723: break;
724:
725: case ' ':
726: i++;
727: break;
728:
729: default:
730: return (i);
731: }
732: }
733:
734: #ifdef lint
735: Ignore(a)
736: char *a;
737: {
738:
739: a = a;
740: }
741:
742: Ignorf(a)
743: int (*a)();
744: {
745:
746: a = a;
747: }
748: #endif
749:
750: markit(addr)
751: line *addr;
752: {
753:
754: if (addr != dot && addr >= one && addr <= dol)
755: markDOT();
756: }
757:
758: /*
759: * The following code is defensive programming against a bug in the
760: * pdp-11 overlay implementation. Sometimes it goes nuts and asks
761: * for an overlay with some garbage number, which generates an emt
762: * trap. This is a less than elegant solution, but it is somewhat
763: * better than core dumping and losing your work, leaving your tty
764: * in a weird state, etc.
765: */
766: int _ovno;
767: onemt()
768: {
769: int oovno;
770:
771: signal(SIGEMT, onemt);
772: oovno = _ovno;
773: /* 2 and 3 are valid on 11/40 type vi, so */
774: if (_ovno < 0 || _ovno > 3)
775: _ovno = 0;
776: error("emt trap, _ovno is %d @ - try again");
777: }
778:
779: /*
780: * When a hangup occurs our actions are similar to a preserve
781: * command. If the buffer has not been [Modified], then we do
782: * nothing but remove the temporary files and exit.
783: * Otherwise, we sync the temp file and then attempt a preserve.
784: * If the preserve succeeds, we unlink our temp files.
785: * If the preserve fails, we leave the temp files as they are
786: * as they are a backup even without preservation if they
787: * are not removed.
788: */
789: onhup()
790: {
791:
792: /*
793: * USG tty driver can send multiple HUP's!!
794: */
795: signal(SIGINT, SIG_IGN);
796: signal(SIGHUP, SIG_IGN);
797: if (chng == 0) {
798: cleanup(1);
799: exit(0);
800: }
801: if (setexit() == 0) {
802: if (preserve()) {
803: cleanup(1);
804: exit(0);
805: }
806: }
807: exit(1);
808: }
809:
810: /*
811: * An interrupt occurred. Drain any output which
812: * is still in the output buffering pipeline.
813: * Catch interrupts again. Unless we are in visual
814: * reset the output state (out of -nl mode, e.g).
815: * Then like a normal error (with the \n before Interrupt
816: * suppressed in visual mode).
817: */
818: onintr()
819: {
820:
821: #ifndef CBREAK
822: signal(SIGINT, onintr);
823: #else
824: signal(SIGINT, inopen ? vintr : onintr);
825: #endif
826: alarm(0); /* in case we were called from map */
827: draino();
828: if (!inopen) {
829: pstop();
830: setlastchar('\n');
831: #ifdef CBREAK
832: }
833: #else
834: } else
835: vraw();
836: #endif
837: error("\nInterrupt" + inopen);
838: }
839:
840: /*
841: * If we are interruptible, enable interrupts again.
842: * In some critical sections we turn interrupts off,
843: * but not very often.
844: */
845: setrupt()
846: {
847:
848: if (ruptible) {
849: #ifndef CBREAK
850: signal(SIGINT, onintr);
851: #else
852: signal(SIGINT, inopen ? vintr : onintr);
853: #endif
854: #ifdef SIGTSTP
855: if (dosusp)
856: signal(SIGTSTP, onsusp);
857: #endif
858: }
859: }
860:
861: preserve()
862: {
863:
864: #ifdef VMUNIX
865: tflush();
866: #endif
867: synctmp();
868: pid = fork();
869: if (pid < 0)
870: return (0);
871: if (pid == 0) {
872: close(0);
873: dup(tfile);
874: execl(EXPRESERVE, "expreserve", (char *) 0);
875: exit(1);
876: }
877: waitfor();
878: if (rpid == pid && status == 0)
879: return (1);
880: return (0);
881: }
882:
883: #ifndef V6
884: exit(i)
885: int i;
886: {
887:
888: # ifdef TRACE
889: if (trace)
890: fclose(trace);
891: # endif
892: _exit(i);
893: }
894: #endif
895:
896: #ifdef SIGTSTP
897: /*
898: * We have just gotten a susp. Suspend and prepare to resume.
899: */
900: onsusp()
901: {
902: ttymode f;
903: int omask;
904: struct winsize win;
905:
906: f = setty(normf);
907: vnfl();
908: putpad(TE);
909: flush();
910:
911: (void) sigsetmask(0L);
912: signal(SIGTSTP, SIG_DFL);
913: kill(0, SIGTSTP);
914:
915: /* the pc stops here */
916:
917: signal(SIGTSTP, onsusp);
918: vcontin(0);
919: setty(f);
920: if (!inopen)
921: error(0);
922: else {
923: if (ioctl(0, TIOCGWINSZ, &win) >= 0)
924: if (win.ws_row != winsz.ws_row ||
925: win.ws_col != winsz.ws_col)
926: winch();
927: if (vcnt < 0) {
928: vcnt = -vcnt;
929: if (state == VISUAL)
930: vclear();
931: else if (state == CRTOPEN)
932: vcnt = 0;
933: }
934: vdirty(0, LINES);
935: vrepaint(cursor);
936: }
937: }
938: #endif