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