cleanups, add manual page
[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
5a6c967e 8static char *sccsid = "@(#)ex_subr.c 7.11 (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"
15
16/*
17 * Random routines, in alphabetical order.
18 */
19
20any(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
32backtab(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
46change()
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 */
59column(cp)
60 register char *cp;
61{
62
63 if (cp == 0)
64 cp = &linebuf[LBSIZE - 2];
65 return (qcolumn(cp, (char *) 0));
66}
67
d266c416
MH
68/*
69 * Ignore a comment to the end of the line.
70 * This routine eats the trailing newline so don't call newline().
71 */
72comment()
73{
74 register int c;
75
76 do {
5a6c967e 77 c = ex_getchar();
d266c416
MH
78 } while (c != '\n' && c != EOF);
79 if (c == EOF)
80 ungetchar(c);
81}
82
b6ea9402
MH
83Copy(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
94copyw(to, from, size)
95 register line *from, *to;
96 register int size;
97{
b6ea9402
MH
98 if (size > 0)
99 do
100 *to++ = *from++;
101 while (--size > 0);
102}
103
104copywR(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
113ctlof(c)
114 int c;
115{
116
117 return (c == TRIM ? '?' : c | ('A' - 1));
118}
119
120dingdong()
121{
122
123 if (VB)
124 putpad(VB);
125 else if (value(ERRORBELLS))
126 putch('\207');
127}
128
129fixindent(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
145filioerr(cp)
146 char *cp;
147{
148 register int oerrno = errno;
149
150 lprintf("\"%s\"", cp);
151 errno = oerrno;
152 syserror();
153}
154
155char *
156genindent(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
168getDOT()
169{
170
171 getline(*dot);
172}
173
174line *
175getmark(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
187getn(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
199ignnEOF()
200{
5a6c967e 201 register int c = ex_getchar();
b6ea9402
MH
202
203 if (c == EOF)
204 ungetchar(c);
d266c416
MH
205 else if (c=='"')
206 comment();
b6ea9402
MH
207}
208
209iswhite(c)
210 int c;
211{
212
213 return (c == ' ' || c == '\t');
214}
215
216junk(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
236killed()
237{
238
239 killcnt(addr2 - addr1 + 1);
240}
241
242killcnt(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;
5a6c967e 253 ex_printf("%d lines", cnt);
b6ea9402 254 if (value(TERSE) == 0) {
5a6c967e 255 ex_printf(" %c%s", Command[0] | ' ', Command + 1);
b6ea9402 256 if (Command[strlen(Command) - 1] != 'e')
5a6c967e
CH
257 ex_putchar('e');
258 ex_putchar('d');
b6ea9402
MH
259 }
260 putNFL();
261}
262
263lineno(a)
264 line *a;
265{
266
267 return (a - zero);
268}
269
270lineDOL()
271{
272
273 return (lineno(dol));
274}
275
276lineDOT()
277{
278
279 return (lineno(dot));
280}
281
282markDOT()
283{
284
285 markpr(dot);
286}
287
288markpr(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
299markreg(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 */
316char *
317mesg(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*/
343merror(seekpt, i)
5a6c967e 344#ifndef EXSTRINGS
b6ea9402
MH
345 char *seekpt;
346#else
44232d5b
MH
347# ifdef lint
348 char *seekpt;
349# else
b6ea9402 350 int seekpt;
44232d5b 351# endif
b6ea9402
MH
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++;
cb3ac212 362 if (inopen > 0 && CE)
b6ea9402
MH
363 vclreol();
364 if (SO && SE)
365 putpad(SO);
5a6c967e 366 ex_printf(mesg(cp), i);
b6ea9402
MH
367 if (SO && SE)
368 putpad(SE);
369}
370
371merror1(seekpt)
5a6c967e 372#ifndef EXSTRINGS
b6ea9402
MH
373 char *seekpt;
374#else
44232d5b
MH
375# ifdef lint
376 char *seekpt;
377# else
b6ea9402 378 int seekpt;
44232d5b 379# endif
b6ea9402
MH
380#endif
381{
382
5a6c967e 383#ifndef EXSTRINGS
44232d5b
MH
384 strcpy(linebuf, seekpt);
385#else
b6ea9402
MH
386 lseek(erfile, (long) seekpt, 0);
387 if (read(erfile, linebuf, 128) < 2)
388 CP(linebuf, "ERROR");
44232d5b 389#endif
b6ea9402
MH
390}
391
392morelines()
393{
5a6c967e
CH
394#ifdef UNIX_SBRK
395 char *sbrk();
b6ea9402
MH
396
397 if ((int) sbrk(1024 * sizeof (line)) == -1)
398 return (-1);
399 endcore += 1024;
400 return (0);
5a6c967e
CH
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
b6ea9402
MH
408}
409
410nonzero()
411{
412
413 if (addr1 == zero) {
414 notempty();
415 error("Nonzero address required@on this command");
416 }
417}
418
419notable(i)
420 int i;
421{
422
423 return (hush == 0 && !inglobal && i > value(REPORT));
424}
425
426
427notempty()
428{
429
430 if (dol == zero)
431 error("No lines@in the buffer");
432}
433
434
435netchHAD(cnt)
436 int cnt;
437{
438
439 netchange(lineDOL() - cnt);
440}
441
442netchange(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;
5a6c967e 458 ex_printf(mesg("%d %slines@in file after %s"), i, cp, Command);
b6ea9402
MH
459 putNFL();
460}
461
462putmark(addr)
463 line *addr;
464{
465
466 putmk1(addr, putline());
467}
468
469putmk1(addr, n)
470 register line *addr;
471 int n;
472{
473 register line *markp;
d266c416 474 register oldglobmk;
b6ea9402 475
d266c416 476 oldglobmk = *addr & 1;
b6ea9402
MH
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;
d266c416 482 *addr = n | oldglobmk;
b6ea9402
MH
483}
484
485char *
486plural(i)
487 long i;
488{
489
490 return (i == 1 ? "" : "s");
491}
492
493int qcount();
494short vcntcol;
495
496qcolumn(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)
5a6c967e 512 ex_putchar(*gp++);
b6ea9402
MH
513 Outchar = OO;
514 return (vcntcol);
515}
516
517int
518qcount(c)
519 int c;
520{
521
522 if (c == '\t') {
523 vcntcol += value(TABSTOP) - vcntcol % value(TABSTOP);
524 return;
525 }
526 vcntcol++;
527}
528
529reverse(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
543save(a1, a2)
544 line *a1;
545 register line *a2;
546{
547 register int more;
548
887e3e0d
MH
549 if (!FIXUNDO)
550 return;
551#ifdef TRACE
552 if (trace)
553 vudump("before save");
554#endif
b6ea9402
MH
555 undkind = UNDNONE;
556 undadot = dot;
557 more = (a2 - a1 + 1) - (unddol - dol);
558 while (more > (endcore - truedol))
559 if (morelines() < 0)
5a6c967e 560#ifdef UNIX_SBRK
04379bab 561 error("Out of memory@saving lines for undo - try using ed");
5a6c967e
CH
562#else
563 error("Out of memory@saving lines for undo - try increasing linelimit");
564#endif
b6ea9402
MH
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;
887e3e0d
MH
575#ifdef TRACE
576 if (trace)
577 vudump("after save");
578#endif
b6ea9402
MH
579}
580
581save12()
582{
583
584 save(addr1, addr2);
585}
586
587saveall()
588{
589
590 save(one, dol);
591}
592
593span()
594{
595
596 return (addr2 - addr1 + 1);
597}
598
5a6c967e 599ex_sync()
b6ea9402
MH
600{
601
602 chng = 0;
603 tchng = 0;
604 xchng = 0;
605}
606
607
608skipwh()
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*/
621smerror(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
b6ea9402
MH
642char *
643strend(cp)
644 register char *cp;
645{
646
647 while (*cp)
648 cp++;
649 return (cp);
650}
651
652strcLIN(dp)
653 char *dp;
654{
655
656 CP(linebuf, dp);
657}
658
659syserror()
660{
661 register int e = errno;
5a6c967e 662#ifndef vms
ecfce8ed
RC
663 extern int sys_nerr;
664 extern char *sys_errlist[];
5a6c967e
CH
665#else
666 extern noshare int sys_nerr;
667 extern noshare char *sys_errlist[];
668#endif
b6ea9402
MH
669
670 dirtcnt = 0;
5a6c967e 671 ex_putchar(' ');
ecfce8ed
RC
672 if (e >= 0 && e <= sys_nerr)
673 error(sys_errlist[e]);
b6ea9402 674 else
5a6c967e
CH
675#ifdef vms
676 if (e == EVMSERR) {
677 error("VMS system error %d", vaxc$errno);
678 perror("vmserror");
679 }
680 else
681#endif
b6ea9402
MH
682 error("System error %d", e);
683}
684
d266c416
MH
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 */
690tabcol(col, ts)
691int 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
b6ea9402
MH
704char *
705vfindcol(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++)
5a6c967e 714 ex_putchar(*cp);
b6ea9402
MH
715 if (cp != linebuf)
716 cp--;
717 Outchar = OO;
718 return (cp);
719}
720
721char *
722vskipwh(cp)
723 register char *cp;
724{
725
726 while (iswhite(*cp) && cp[1])
727 cp++;
728 return (cp);
729}
730
731
732char *
733vpastwh(cp)
734 register char *cp;
735{
736
737 while (iswhite(*cp))
738 cp++;
739 return (cp);
740}
741
742whitecnt(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
765Ignore(a)
766 char *a;
767{
768
769 a = a;
770}
771
772Ignorf(a)
773 int (*a)();
774{
775
776 a = a;
777}
778#endif
779
780markit(addr)
781 line *addr;
782{
783
784 if (addr != dot && addr >= one && addr <= dol)
785 markDOT();
786}
9d962274
MH
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 */
796int _ovno;
797onemt()
798{
9d962274 799 signal(SIGEMT, onemt);
9d962274
MH
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}
16fb7022
MH
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 */
816onhup()
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);
5a6c967e 826 ex_exit(0);
16fb7022
MH
827 }
828 if (setexit() == 0) {
829 if (preserve()) {
830 cleanup(1);
5a6c967e 831 ex_exit(0);
16fb7022
MH
832 }
833 }
5a6c967e 834 ex_exit(1);
16fb7022
MH
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 */
845onintr()
846{
847
848#ifndef CBREAK
849 signal(SIGINT, onintr);
850#else
851 signal(SIGINT, inopen ? vintr : onintr);
852#endif
299f2784 853 alarm(0); /* in case we were called from map */
16fb7022
MH
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 */
872setrupt()
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
888preserve()
889{
890
891#ifdef VMUNIX
892 tflush();
893#endif
894 synctmp();
5a6c967e 895 pid = vfork();
16fb7022
MH
896 if (pid < 0)
897 return (0);
898 if (pid == 0) {
899 close(0);
900 dup(tfile);
901 execl(EXPRESERVE, "expreserve", (char *) 0);
5a6c967e 902 ex_exit(1);
16fb7022
MH
903 }
904 waitfor();
905 if (rpid == pid && status == 0)
906 return (1);
907 return (0);
908}
909
910#ifndef V6
5a6c967e 911ex_exit(i)
16fb7022
MH
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 */
927onsusp()
928{
929 ttymode f;
f8305ab2 930 struct winsize win;
16fb7022
MH
931
932 f = setty(normf);
933 vnfl();
934 putpad(TE);
935 flush();
936
2ec23540 937 (void) sigsetmask(0);
16fb7022
MH
938 signal(SIGTSTP, SIG_DFL);
939 kill(0, SIGTSTP);
940
941 /* the pc stops here */
942
943 signal(SIGTSTP, onsusp);
944 vcontin(0);
5a6c967e 945 ignore(setty(f));
16fb7022 946 if (!inopen)
5a6c967e 947 error((char *) 0);
16fb7022 948 else {
5a6c967e 949#ifdef TIOCGWINSZ
f8305ab2 950 if (ioctl(0, TIOCGWINSZ, &win) >= 0)
0151ea50
SL
951 if (win.ws_row != winsz.ws_row ||
952 win.ws_col != winsz.ws_col)
f8305ab2 953 winch();
5a6c967e 954#endif
16fb7022
MH
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}
60b36ddb 966#endif