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