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