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