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