add offsets, new fields
[unix-history] / usr / src / usr.bin / ex / ex_put.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
70190965 8static char *sccsid = "@(#)ex_put.c 7.9 (Berkeley) %G%";
19d73a0e
DF
9#endif not lint
10
e45f2c96
MH
11#include "ex.h"
12#include "ex_tty.h"
13#include "ex_vis.h"
14
15/*
16 * Terminal driving and line formatting routines.
17 * Basic motion optimizations are done here as well
18 * as formatting of lines (printing of control characters,
19 * line numbering and the like).
20 */
21
22/*
23 * The routines outchar, putchar and pline are actually
24 * variables, and these variables point at the current definitions
25 * of the routines. See the routine setflav.
26 * We sometimes make outchar be routines which catch the characters
27 * to be printed, e.g. if we want to see how long a line is.
28 * During open/visual, outchar and putchar will be set to
29 * routines in the file ex_vput.c (vputchar, vinschar, etc.).
30 */
31int (*Outchar)() = termchar;
32int (*Putchar)() = normchar;
33int (*Pline)() = normline;
34
35int (*
36setlist(t))()
37 bool t;
38{
39 register int (*P)();
40
41 listf = t;
42 P = Putchar;
43 Putchar = t ? listchar : normchar;
44 return (P);
45}
46
47int (*
48setnumb(t))()
49 bool t;
50{
51 register int (*P)();
52
53 numberf = t;
54 P = Pline;
55 Pline = t ? numbline : normline;
56 return (P);
57}
58
59/*
60 * Format c for list mode; leave things in common
61 * with normal print mode to be done by normchar.
62 */
63listchar(c)
64 register short c;
65{
66
67 c &= (TRIM|QUOTE);
68 switch (c) {
69
70 case '\t':
71 case '\b':
72 outchar('^');
73 c = ctlof(c);
74 break;
75
76 case '\n':
77 break;
78
79 case '\n' | QUOTE:
80 outchar('$');
81 break;
82
83 default:
84 if (c & QUOTE)
85 break;
86 if (c < ' ' && c != '\n' || c == DELETE)
87 outchar('^'), c = ctlof(c);
88 break;
89 }
90 normchar(c);
91}
92
93/*
94 * Format c for printing. Handle funnies of upper case terminals
95 * and crocky hazeltines which don't have ~.
96 */
97normchar(c)
98 register short c;
99{
100 register char *colp;
101
102 c &= (TRIM|QUOTE);
103 if (c == '~' && HZ) {
104 normchar('\\');
105 c = '^';
106 }
107 if (c & QUOTE)
108 switch (c) {
109
110 case ' ' | QUOTE:
111 case '\b' | QUOTE:
112 break;
113
114 case QUOTE:
115 return;
116
117 default:
118 c &= TRIM;
119 }
120 else if (c < ' ' && (c != '\b' || !OS) && c != '\n' && c != '\t' || c == DELETE)
121 putchar('^'), c = ctlof(c);
122 else if (UPPERCASE)
123 if (isupper(c)) {
124 outchar('\\');
125 c = tolower(c);
126 } else {
127 colp = "({)}!|^~'`";
128 while (*colp++)
129 if (c == *colp++) {
130 outchar('\\');
131 c = colp[-2];
132 break;
133 }
134 }
135 outchar(c);
136}
137
138/*
139 * Print a line with a number.
140 */
141numbline(i)
142 int i;
143{
144
145 if (shudclob)
146 slobber(' ');
147 printf("%6d ", i);
148 normline();
149}
150
151/*
152 * Normal line output, no numbering.
153 */
154normline()
155{
156 register char *cp;
157
158 if (shudclob)
159 slobber(linebuf[0]);
160 /* pdp-11 doprnt is not reentrant so can't use "printf" here
161 in case we are tracing */
162 for (cp = linebuf; *cp;)
163 putchar(*cp++);
164 if (!inopen)
165 putchar('\n' | QUOTE);
166}
167
168/*
169 * Given c at the beginning of a line, determine whether
170 * the printing of the line will erase or otherwise obliterate
171 * the prompt which was printed before. If it won't, do it now.
172 */
173slobber(c)
174 int c;
175{
176
177 shudclob = 0;
178 switch (c) {
179
180 case '\t':
181 if (Putchar == listchar)
182 return;
183 break;
184
185 default:
186 return;
187
188 case ' ':
189 case 0:
190 break;
191 }
192 if (OS)
193 return;
194 flush();
195 putch(' ');
196 if (BC)
197 tputs(BC, 0, putch);
198 else
199 putch('\b');
200}
201
202/*
203 * The output buffer is initialized with a useful error
204 * message so we don't have to keep it in data space.
205 */
d266c416 206static char linb[66];
3c7b865a 207char *linp = linb;
e45f2c96
MH
208
209/*
210 * Phadnl records when we have already had a complete line ending with \n.
211 * If another line starts without a flush, and the terminal suggests it,
212 * we switch into -nl mode so that we can send lineffeeds to avoid
213 * a lot of spacing.
214 */
215static bool phadnl;
216
217/*
218 * Indirect to current definition of putchar.
219 */
220putchar(c)
221 int c;
222{
223
224 (*Putchar)(c);
225}
226
227/*
228 * Termchar routine for command mode.
229 * Watch for possible switching to -nl mode.
230 * Otherwise flush into next level of buffering when
231 * small buffer fills or at a newline.
232 */
233termchar(c)
234 int c;
235{
236
237 if (pfast == 0 && phadnl)
238 pstart();
239 if (c == '\n')
240 phadnl = 1;
241 else if (linp >= &linb[63])
242 flush1();
243 *linp++ = c;
244 if (linp >= &linb[63]) {
245 fgoto();
246 flush1();
247 }
248}
249
250flush()
251{
252
253 flush1();
254 flush2();
255}
256
257/*
258 * Flush from small line buffer into output buffer.
259 * Work here is destroying motion into positions, and then
260 * letting fgoto do the optimized motion.
261 */
262flush1()
263{
264 register char *lp;
265 register short c;
266
267 *linp = 0;
268 lp = linb;
269 while (*lp)
270 switch (c = *lp++) {
271
272 case '\r':
273 destline += destcol / COLUMNS;
274 destcol = 0;
275 continue;
276
277 case '\b':
278 if (destcol)
279 destcol--;
280 continue;
281
282 case ' ':
283 destcol++;
284 continue;
285
286 case '\t':
287 destcol += value(TABSTOP) - destcol % value(TABSTOP);
288 continue;
289
290 case '\n':
291 destline += destcol / COLUMNS + 1;
292 if (destcol != 0 && destcol % COLUMNS == 0)
293 destline--;
294 destcol = 0;
295 continue;
296
297 default:
298 fgoto();
299 for (;;) {
300 if (AM == 0 && outcol == COLUMNS)
301 fgoto();
302 c &= TRIM;
303 putch(c);
304 if (c == '\b') {
305 outcol--;
306 destcol--;
307 } else if (c >= ' ' && c != DELETE) {
308 outcol++;
309 destcol++;
310 if (XN && outcol % COLUMNS == 0)
299f2784 311 putch('\r'), putch('\n');
e45f2c96
MH
312 }
313 c = *lp++;
314 if (c <= ' ')
315 break;
316 }
317 --lp;
318 continue;
319 }
320 linp = linb;
321}
322
323flush2()
324{
325
326 fgoto();
327 flusho();
328 pstop();
329}
330
331/*
332 * Sync the position of the output cursor.
333 * Most work here is rounding for terminal boundaries getting the
334 * column position implied by wraparound or the lack thereof and
335 * rolling up the screen to get destline on the screen.
336 */
337fgoto()
338{
339 register int l, c;
340
341 if (destcol > COLUMNS - 1) {
342 destline += destcol / COLUMNS;
343 destcol %= COLUMNS;
344 }
345 if (outcol > COLUMNS - 1) {
346 l = (outcol + 1) / COLUMNS;
347 outline += l;
348 outcol %= COLUMNS;
349 if (AM == 0) {
350 while (l > 0) {
351 if (pfast)
d266c416
MH
352 if (xCR)
353 tputs(xCR, 0, putch);
354 else
355 putch('\r');
356 if (xNL)
357 tputs(xNL, 0, putch);
358 else
359 putch('\n');
e45f2c96
MH
360 l--;
361 }
362 outcol = 0;
363 }
364 if (outline > LINES - 1) {
365 destline -= outline - (LINES - 1);
366 outline = LINES - 1;
367 }
368 }
369 if (destline > LINES - 1) {
370 l = destline;
371 destline = LINES - 1;
372 if (outline < LINES - 1) {
373 c = destcol;
374 if (pfast == 0 && (!CA || holdcm))
375 destcol = 0;
376 fgoto();
377 destcol = c;
378 }
379 while (l > LINES - 1) {
d266c416
MH
380 /*
381 * The following linefeed (or simulation thereof)
382 * is supposed to scroll up the screen, since we
383 * are on the bottom line. We make the assumption
384 * that linefeed will scroll. If ns is in the
385 * capability list this won't work. We should
386 * probably have an sc capability but sf will
387 * generally take the place if it works.
388 *
389 * Superbee glitch: in the middle of the screen we
390 * have to use esc B (down) because linefeed screws up
391 * in "Efficient Paging" (what a joke) mode (which is
392 * essential in some SB's because CRLF mode puts garbage
393 * in at end of memory), but you must use linefeed to
394 * scroll since down arrow won't go past memory end.
395 * I turned this off after recieving Paul Eggert's
396 * Superbee description which wins better.
397 */
398 if (xNL /* && !XB */ && pfast)
399 tputs(xNL, 0, putch);
400 else
401 putch('\n');
e45f2c96
MH
402 l--;
403 if (pfast == 0)
404 outcol = 0;
405 }
406 }
407 if (destline < outline && !(CA && !holdcm || UP != NOSTR))
408 destline = outline;
409 if (CA && !holdcm)
410 if (plod(costCM) > 0)
411 plod(0);
412 else
413 tputs(tgoto(CM, destcol, destline), 0, putch);
414 else
415 plod(0);
416 outline = destline;
417 outcol = destcol;
418}
419
420/*
421 * Tab to column col by flushing and then setting destcol.
422 * Used by "set all".
423 */
424tab(col)
425 int col;
426{
427
428 flush1();
429 destcol = col;
430}
431
432/*
433 * Move (slowly) to destination.
434 * Hard thing here is using home cursor on really deficient terminals.
435 * Otherwise just use cursor motions, hacking use of tabs and overtabbing
436 * and backspace.
437 */
438
439static int plodcnt, plodflg;
440
441plodput(c)
442{
443
444 if (plodflg)
445 plodcnt--;
446 else
447 putch(c);
448}
449
450plod(cnt)
451{
452 register int i, j, k;
453 register int soutcol, soutline;
454
455 plodcnt = plodflg = cnt;
456 soutcol = outcol;
457 soutline = outline;
d266c416
MH
458 /*
459 * Consider homing and moving down/right from there, vs moving
460 * directly with local motions to the right spot.
461 */
e45f2c96 462 if (HO) {
d266c416
MH
463 /*
464 * i is the cost to home and tab/space to the right to
465 * get to the proper column. This assumes ND space costs
466 * 1 char. So i+destcol is cost of motion with home.
467 */
e45f2c96 468 if (GT)
d266c416 469 i = (destcol / value(HARDTABS)) + (destcol % value(HARDTABS));
e45f2c96
MH
470 else
471 i = destcol;
d266c416
MH
472 /*
473 * j is cost to move locally without homing
474 */
475 if (destcol >= outcol) { /* if motion is to the right */
476 j = destcol / value(HARDTABS) - outcol / value(HARDTABS);
477 if (GT && j)
478 j += destcol % value(HARDTABS);
e45f2c96
MH
479 else
480 j = destcol - outcol;
d266c416
MH
481 } else
482 /* leftward motion only works if we can backspace. */
e45f2c96 483 if (outcol - destcol <= i && (BS || BC))
d266c416 484 i = j = outcol - destcol; /* cheaper to backspace */
e45f2c96 485 else
d266c416
MH
486 j = i + 1; /* impossibly expensive */
487
488 /* k is the absolute value of vertical distance */
e45f2c96
MH
489 k = outline - destline;
490 if (k < 0)
491 k = -k;
492 j += k;
d266c416
MH
493
494 /*
495 * Decision. We may not have a choice if no UP.
496 */
497 if (i + destline < j || (!UP && destline < outline)) {
498 /*
499 * Cheaper to home. Do it now and pretend it's a
500 * regular local motion.
501 */
e45f2c96
MH
502 tputs(HO, 0, plodput);
503 outcol = outline = 0;
504 } else if (LL) {
d266c416
MH
505 /*
506 * Quickly consider homing down and moving from there.
507 * Assume cost of LL is 2.
508 */
e45f2c96 509 k = (LINES - 1) - destline;
d266c416 510 if (i + k + 2 < j && (k<=0 || UP)) {
e45f2c96
MH
511 tputs(LL, 0, plodput);
512 outcol = 0;
513 outline = LINES - 1;
514 }
515 }
d266c416
MH
516 } else
517 /*
518 * No home and no up means it's impossible, so we return an
519 * incredibly big number to make cursor motion win out.
520 */
521 if (!UP && destline < outline)
522 return (500);
e45f2c96 523 if (GT)
d266c416
MH
524 i = destcol % value(HARDTABS)
525 + destcol / value(HARDTABS);
e45f2c96
MH
526 else
527 i = destcol;
528/*
529 if (BT && outcol > destcol && (j = (((outcol+7) & ~7) - destcol - 1) >> 3)) {
530 j *= (k = strlen(BT));
531 if ((k += (destcol&7)) > 4)
532 j += 8 - (destcol&7);
533 else
534 j += k;
535 } else
536*/
537 j = outcol - destcol;
538 /*
539 * If we will later need a \n which will turn into a \r\n by
540 * the system or the terminal, then don't bother to try to \r.
541 */
542 if ((NONL || !pfast) && outline < destline)
543 goto dontcr;
544 /*
545 * If the terminal will do a \r\n and there isn't room for it,
546 * then we can't afford a \r.
547 */
548 if (NC && outline >= destline)
549 goto dontcr;
550 /*
551 * If it will be cheaper, or if we can't back up, then send
552 * a return preliminarily.
553 */
554 if (j > i + 1 || outcol > destcol && !BS && !BC) {
d266c416
MH
555 /*
556 * BUG: this doesn't take the (possibly long) length
557 * of xCR into account.
558 */
559 if (xCR)
560 tputs(xCR, 0, plodput);
561 else
562 plodput('\r');
e45f2c96 563 if (NC) {
d266c416
MH
564 if (xNL)
565 tputs(xNL, 0, plodput);
566 else
567 plodput('\n');
e45f2c96
MH
568 outline++;
569 }
570 outcol = 0;
571 }
572dontcr:
17687128 573 /* Move down, if necessary, until we are at the desired line */
e45f2c96 574 while (outline < destline) {
17687128 575 j = destline - outline;
d68a9fd3 576 if (j > costDP && DOWN_PARM) {
17687128
MH
577 /* Win big on Tek 4025 */
578 tputs(tgoto(DOWN_PARM, 0, j), j, plodput);
579 outline += j;
580 }
581 else {
582 outline++;
583 if (xNL && pfast)
584 tputs(xNL, 0, plodput);
585 else
586 plodput('\n');
587 }
e45f2c96
MH
588 if (plodcnt < 0)
589 goto out;
590 if (NONL || pfast == 0)
591 outcol = 0;
592 }
593 if (BT)
17687128
MH
594 k = strlen(BT); /* should probably be cost(BT) and moved out */
595 /* Move left, if necessary, to desired column */
e45f2c96
MH
596 while (outcol > destcol) {
597 if (plodcnt < 0)
598 goto out;
e45f2c96
MH
599 if (BT && !insmode && outcol - destcol > 4+k) {
600 tputs(BT, 0, plodput);
601 outcol--;
17687128 602 outcol -= outcol % value(HARDTABS); /* outcol &= ~7; */
e45f2c96
MH
603 continue;
604 }
17687128 605 j = outcol - destcol;
d68a9fd3 606 if (j > costLP && LEFT_PARM) {
17687128
MH
607 tputs(tgoto(LEFT_PARM, 0, j), j, plodput);
608 outcol -= j;
609 }
610 else {
611 outcol--;
612 if (BC)
613 tputs(BC, 0, plodput);
614 else
615 plodput('\b');
616 }
e45f2c96 617 }
17687128 618 /* Move up, if necessary, to desired row */
e45f2c96 619 while (outline > destline) {
17687128 620 j = outline - destline;
090a8083 621 if (UP_PARM && j > 1) {
17687128
MH
622 /* Win big on Tek 4025 */
623 tputs(tgoto(UP_PARM, 0, j), j, plodput);
624 outline -= j;
625 }
626 else {
627 outline--;
628 tputs(UP, 0, plodput);
629 }
e45f2c96
MH
630 if (plodcnt < 0)
631 goto out;
632 }
17687128
MH
633 /*
634 * Now move to the right, if necessary. We first tab to
635 * as close as we can get.
636 */
e45f2c96 637 if (GT && !insmode && destcol - outcol > 1) {
17687128
MH
638 /* tab to right as far as possible without passing col */
639 for (;;) {
640 i = tabcol(outcol, value(HARDTABS));
641 if (i > destcol)
642 break;
e45f2c96
MH
643 if (TA)
644 tputs(TA, 0, plodput);
645 else
646 plodput('\t');
647 outcol = i;
648 }
17687128 649 /* consider another tab and then some backspaces */
e45f2c96
MH
650 if (destcol - outcol > 4 && i < COLUMNS && (BC || BS)) {
651 if (TA)
652 tputs(TA, 0, plodput);
653 else
654 plodput('\t');
655 outcol = i;
17687128
MH
656 /*
657 * Back up. Don't worry about LEFT_PARM because
658 * it's never more than 4 spaces anyway.
659 */
e45f2c96
MH
660 while (outcol > destcol) {
661 outcol--;
662 if (BC)
663 tputs(BC, 0, plodput);
664 else
665 plodput('\b');
666 }
667 }
668 }
17687128
MH
669 /*
670 * We've tabbed as much as possible. If we still need to go
671 * further (not exact or can't tab) space over. This is a
672 * very common case when moving to the right with space.
673 */
e45f2c96 674 while (outcol < destcol) {
17687128 675 j = destcol - outcol;
d68a9fd3 676 if (j > costRP && RIGHT_PARM) {
17687128
MH
677 /*
678 * This probably happens rarely, if at all.
679 * It seems mainly useful for ANSI terminals
680 * with no hardware tabs, and I don't know
681 * of any such terminal at the moment.
682 */
683 tputs(tgoto(RIGHT_PARM, 0, j), j, plodput);
684 outcol += j;
685 }
686 else {
687 /*
688 * move one char to the right. We don't use ND space
689 * because it's better to just print the char we are
690 * moving over. There are various exceptions, however.
691 * If !inopen, vtube contains garbage. If the char is
692 * a null or a tab we want to print a space. Other
693 * random chars we use space for instead, too.
694 */
695 if (!inopen || vtube[outline]==NULL ||
696 (i=vtube[outline][outcol]) < ' ')
697 i = ' ';
698 if(i & QUOTE) /* mjm: no sign extension on 3B */
699 i = ' ';
700 if (insmode && ND)
701 tputs(ND, 0, plodput);
702 else
703 plodput(i);
704 outcol++;
705 }
e45f2c96
MH
706 if (plodcnt < 0)
707 goto out;
708 }
709out:
710 if (plodflg) {
711 outcol = soutcol;
712 outline = soutline;
713 }
714 return(plodcnt);
715}
716
717/*
718 * An input line arrived.
719 * Calculate new (approximate) screen line position.
720 * Approximate because kill character echoes newline with
721 * no feedback and also because of long input lines.
722 */
723noteinp()
724{
725
726 outline++;
727 if (outline > LINES - 1)
728 outline = LINES - 1;
729 destline = outline;
730 destcol = outcol = 0;
731}
732
733/*
734 * Something weird just happened and we
735 * lost track of whats happening out there.
736 * Since we cant, in general, read where we are
737 * we just reset to some known state.
738 * On cursor addressible terminals setting to unknown
739 * will force a cursor address soon.
740 */
741termreset()
742{
743
744 endim();
745 if (TI) /* otherwise it flushes anyway, and 'set tty=dumb' vomits */
746 putpad(TI); /*adb change -- emit terminal initial sequence */
747 destcol = 0;
748 destline = LINES - 1;
749 if (CA) {
750 outcol = UKCOL;
751 outline = UKCOL;
752 } else {
753 outcol = destcol;
754 outline = destline;
755 }
756}
757
758/*
759 * Low level buffering, with the ability to drain
760 * buffered output without printing it.
761 */
762char *obp = obuf;
763
764draino()
765{
766
767 obp = obuf;
768}
769
770flusho()
771{
772
773 if (obp != obuf) {
774 write(1, obuf, obp - obuf);
775 obp = obuf;
776 }
777}
778
779putnl()
780{
781
782 putchar('\n');
783}
784
785putS(cp)
786 char *cp;
787{
788
789 if (cp == NULL)
790 return;
791 while (*cp)
792 putch(*cp++);
793}
794
795
796putch(c)
797 int c;
798{
799
299f2784
MH
800#ifdef OLD3BTTY /* mjm */
801 if(c == '\n') /* mjm: Fake "\n\r" for '\n' til fix in 3B firmware */
802 putch('\r'); /* mjm: vi does "stty -icanon" => -onlcr !! */
803#endif
d266c416 804 *obp++ = c & 0177;
e45f2c96
MH
805 if (obp >= &obuf[sizeof obuf])
806 flusho();
807}
808
809/*
810 * Miscellaneous routines related to output.
811 */
812
e45f2c96
MH
813/*
814 * Put with padding
815 */
816putpad(cp)
817 char *cp;
818{
819
820 flush();
821 tputs(cp, 0, putch);
822}
823
824/*
825 * Set output through normal command mode routine.
826 */
827setoutt()
828{
829
830 Outchar = termchar;
831}
832
833/*
834 * Printf (temporarily) in list mode.
835 */
836/*VARARGS2*/
837lprintf(cp, dp)
838 char *cp, *dp;
839{
840 register int (*P)();
841
842 P = setlist(1);
843 printf(cp, dp);
844 Putchar = P;
845}
846
847/*
848 * Newline + flush.
849 */
850putNFL()
851{
852
853 putnl();
854 flush();
855}
856
857/*
858 * Try to start -nl mode.
859 */
860pstart()
861{
862
863 if (NONL)
864 return;
865 if (!value(OPTIMIZE))
866 return;
867 if (ruptible == 0 || pfast)
868 return;
869 fgoto();
870 flusho();
871 pfast = 1;
872 normtty++;
d266c416 873#ifndef USG3TTY
e45f2c96 874 tty.sg_flags = normf & ~(ECHO|XTABS|CRMOD);
d266c416
MH
875#else
876 tty = normf;
877 tty.c_oflag &= ~(ONLCR|TAB3);
878 tty.c_lflag &= ~ECHO;
879#endif
e45f2c96
MH
880 sTTY(1);
881}
882
883/*
884 * Stop -nl mode.
885 */
886pstop()
887{
888
889 if (inopen)
890 return;
891 phadnl = 0;
892 linp = linb;
893 draino();
894 normal(normf);
895 pfast &= ~1;
896}
897
898/*
899 * Prep tty for open mode.
900 */
d266c416 901ttymode
e45f2c96
MH
902ostart()
903{
d266c416 904 ttymode f;
e45f2c96
MH
905
906 if (!intty)
907 error("Open and visual must be used interactively");
908 gTTY(1);
909 normtty++;
d266c416 910#ifndef USG3TTY
e45f2c96 911 f = tty.sg_flags;
d266c416
MH
912 tty.sg_flags = (normf &~ (ECHO|XTABS|CRMOD)) |
913# ifdef CBREAK
914 CBREAK;
915# else
916 RAW;
917# endif
918# ifdef TIOCGETC
919 ttcharoff();
920# endif
e45f2c96 921#else
d266c416
MH
922 f = tty;
923 tty = normf;
924 tty.c_iflag &= ~ICRNL;
925 tty.c_lflag &= ~(ECHO|ICANON);
14382c50 926 tty.c_oflag &= ~(TAB3|ONLCR);
d266c416
MH
927 tty.c_cc[VMIN] = 1;
928 tty.c_cc[VTIME] = 1;
929 ttcharoff();
e45f2c96
MH
930#endif
931 sTTY(1);
d266c416 932 tostart();
e45f2c96
MH
933 pfast |= 2;
934 return (f);
935}
936
d266c416
MH
937/* actions associated with putting the terminal in open mode */
938tostart()
939{
940 putpad(VS);
941 putpad(KS);
9cc49269
MH
942 if (!value(MESG)) {
943 if (ttynbuf[0] == 0) {
944 register char *tn;
945 if ((tn=ttyname(2)) == NULL &&
946 (tn=ttyname(1)) == NULL &&
947 (tn=ttyname(0)) == NULL)
948 ttynbuf[0] = 1;
949 else
950 strcpy(ttynbuf, tn);
951 }
952 if (ttynbuf[0] != 1) {
953 struct stat sbuf;
954 stat(ttynbuf, &sbuf);
955 ttymesg = sbuf.st_mode & 0777;
956 chmod(ttynbuf,
957#ifdef UCBV7
958 /*
959 * This applies to the UCB V7 Pdp-11 system with the
960 * -u write option only.
961 */
962 0611 /* 11 = urgent only allowed */
963#else
964 0600
965#endif
966 );
967 }
968 }
d266c416
MH
969}
970
971/*
972 * Turn off start/stop chars if they aren't the default ^S/^Q.
973 * This is so idiots who make esc their start/stop don't lose.
974 * We always turn off quit since datamedias send ^\ for their
975 * right arrow key.
976 */
977#ifdef TIOCGETC
978ttcharoff()
979{
980 nttyc.t_quitc = '\377';
981 if (nttyc.t_startc != CTRL(q))
982 nttyc.t_startc = '\377';
983 if (nttyc.t_stopc != CTRL(s))
984 nttyc.t_stopc = '\377';
985# ifdef TIOCLGET
986 nlttyc.t_suspc = '\377'; /* ^Z */
987 nlttyc.t_dsuspc = '\377'; /* ^Y */
988 nlttyc.t_flushc = '\377'; /* ^O */
989 nlttyc.t_lnextc = '\377'; /* ^V */
990# endif
991}
992#endif
993
994#ifdef USG3TTY
995ttcharoff()
996{
997 tty.c_cc[VQUIT] = '\377';
998# ifdef VSTART
999 /*
1000 * The following is sample code if USG ever lets people change
1001 * their start/stop chars. As long as they can't we can't get
1002 * into trouble so we just leave them alone.
1003 */
1004 if (tty.c_cc[VSTART] != CTRL(q))
1005 tty.c_cc[VSTART] = '\377';
1006 if (tty.c_cc[VSTOP] != CTRL(s))
1007 tty.c_cc[VSTOP] = '\377';
1008# endif
1009}
1010#endif
1011
e45f2c96
MH
1012/*
1013 * Stop open, restoring tty modes.
1014 */
1015ostop(f)
d266c416 1016 ttymode f;
e45f2c96
MH
1017{
1018
d266c416 1019#ifndef USG3TTY
e45f2c96 1020 pfast = (f & CRMOD) == 0;
d266c416 1021#else
3c7b865a 1022 pfast = (f.c_oflag & ONLCR) == 0;
d266c416 1023#endif
e45f2c96
MH
1024 termreset(), fgoto(), flusho();
1025 normal(f);
d266c416
MH
1026 tostop();
1027}
1028
1029/* Actions associated with putting the terminal in the right mode. */
1030tostop()
1031{
e45f2c96
MH
1032 putpad(VE);
1033 putpad(KE);
c2480b3f 1034 if (!value(MESG) && ttynbuf[0]>1)
d266c416 1035 chmod(ttynbuf, ttymesg);
e45f2c96
MH
1036}
1037
1038#ifndef CBREAK
1039/*
1040 * Into cooked mode for interruptibility.
1041 */
1042vcook()
1043{
1044
1045 tty.sg_flags &= ~RAW;
1046 sTTY(1);
1047}
1048
1049/*
1050 * Back into raw mode.
1051 */
1052vraw()
1053{
1054
1055 tty.sg_flags |= RAW;
1056 sTTY(1);
1057}
1058#endif
1059
1060/*
1061 * Restore flags to normal state f.
1062 */
1063normal(f)
d266c416 1064 ttymode f;
e45f2c96
MH
1065{
1066
1067 if (normtty > 0) {
1068 setty(f);
1069 normtty--;
1070 }
1071}
1072
1073/*
1074 * Straight set of flags to state f.
1075 */
d266c416 1076ttymode
e45f2c96 1077setty(f)
d266c416 1078 ttymode f;
e45f2c96 1079{
d266c416 1080#ifndef USG3TTY
e45f2c96 1081 register int ot = tty.sg_flags;
d266c416
MH
1082#else
1083 ttymode ot;
1084 ot = tty;
1085#endif
e45f2c96 1086
d266c416
MH
1087#ifndef USG3TTY
1088 if (f == normf) {
e45f2c96 1089 nttyc = ottyc;
d266c416
MH
1090# ifdef TIOCLGET
1091 nlttyc = olttyc;
1092# endif
1093 } else
1094 ttcharoff();
e45f2c96 1095 tty.sg_flags = f;
d266c416
MH
1096#else
1097 if (tty.c_lflag & ICANON)
1098 ttcharoff();
1099 tty = f;
1100#endif
e45f2c96
MH
1101 sTTY(1);
1102 return (ot);
1103}
1104
1105gTTY(i)
1106 int i;
1107{
1108
d266c416 1109#ifndef USG3TTY
e45f2c96 1110 ignore(gtty(i, &tty));
d266c416 1111# ifdef TIOCGETC
e45f2c96
MH
1112 ioctl(i, TIOCGETC, &ottyc);
1113 nttyc = ottyc;
d266c416 1114# endif
bdbbb330 1115# ifdef TIOCGLTC
d266c416
MH
1116 ioctl(i, TIOCGLTC, &olttyc);
1117 nlttyc = olttyc;
1118# endif
1119#else
1120 ioctl(i, TCGETA, &tty);
e45f2c96
MH
1121#endif
1122}
1123
d266c416
MH
1124/*
1125 * sTTY: set the tty modes on file descriptor i to be what's
1126 * currently in global "tty". (Also use nttyc if needed.)
1127 */
e45f2c96
MH
1128sTTY(i)
1129 int i;
1130{
1131
d266c416
MH
1132#ifndef USG3TTY
1133# ifdef USG
1134 /* Bug in USG tty driver, put out a DEL as a patch. */
1135 if (tty.sg_ospeed >= B1200)
1136 write(1, "\377", 1);
1137# endif
1138
1139# ifdef TIOCSETN
1140 /* Don't flush typeahead if we don't have to */
e45f2c96 1141 ioctl(i, TIOCSETN, &tty);
d266c416
MH
1142# else
1143 /* We have to. Too bad. */
e45f2c96 1144 stty(i, &tty);
d266c416
MH
1145# endif
1146
1147# ifdef TIOCGETC
1148 /* Update the other random chars while we're at it. */
e45f2c96 1149 ioctl(i, TIOCSETC, &nttyc);
d266c416 1150# endif
bdbbb330 1151# ifdef TIOCSLTC
d266c416
MH
1152 ioctl(i, TIOCSLTC, &nlttyc);
1153# endif
1154
1155#else
1156 /* USG 3 very simple: just set everything */
1157 ioctl(i, TCSETAW, &tty);
e45f2c96
MH
1158#endif
1159}
1160
1161/*
1162 * Print newline, or blank if in open/visual
1163 */
1164noonl()
1165{
1166
1167 putchar(Outchar != termchar ? ' ' : '\n');
1168}