xref: /original-bsd/usr.bin/ex/ex_put.c (revision fbed46ce)
1 /* Copyright (c) 1981 Regents of the University of California */
2 static char *sccsid = "@(#)ex_put.c	7.7	10/16/81";
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  */
23 int	(*Outchar)() = termchar;
24 int	(*Putchar)() = normchar;
25 int	(*Pline)() = normline;
26 
27 int (*
28 setlist(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 
39 int (*
40 setnumb(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  */
55 listchar(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  */
89 normchar(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  */
133 numbline(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  */
146 normline()
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  */
165 slobber(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  */
198 static	char linb[66];
199 char *linp = linb;
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  */
207 static	bool phadnl;
208 
209 /*
210  * Indirect to current definition of putchar.
211  */
212 putchar(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  */
225 termchar(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 
242 flush()
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  */
254 flush1()
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)
303 						putch('\r'), putch('\n');
304 				}
305 				c = *lp++;
306 				if (c <= ' ')
307 					break;
308 			}
309 			--lp;
310 			continue;
311 		}
312 	linp = linb;
313 }
314 
315 flush2()
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  */
329 fgoto()
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)
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');
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) {
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');
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  */
416 tab(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 
431 static int plodcnt, plodflg;
432 
433 plodput(c)
434 {
435 
436 	if (plodflg)
437 		plodcnt--;
438 	else
439 		putch(c);
440 }
441 
442 plod(cnt)
443 {
444 	register int i, j, k;
445 	register int soutcol, soutline;
446 
447 	plodcnt = plodflg = cnt;
448 	soutcol = outcol;
449 	soutline = outline;
450 	/*
451 	 * Consider homing and moving down/right from there, vs moving
452 	 * directly with local motions to the right spot.
453 	 */
454 	if (HO) {
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 		 */
460 		if (GT)
461 			i = (destcol / value(HARDTABS)) + (destcol % value(HARDTABS));
462 		else
463 			i = destcol;
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);
471 			else
472 				j = destcol - outcol;
473 		} else
474 			/* leftward motion only works if we can backspace. */
475 			if (outcol - destcol <= i && (BS || BC))
476 				i = j = outcol - destcol; /* cheaper to backspace */
477 			else
478 				j = i + 1; /* impossibly expensive */
479 
480 		/* k is the absolute value of vertical distance */
481 		k = outline - destline;
482 		if (k < 0)
483 			k = -k;
484 		j += k;
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 			 */
494 			tputs(HO, 0, plodput);
495 			outcol = outline = 0;
496 		} else if (LL) {
497 			/*
498 			 * Quickly consider homing down and moving from there.
499 			 * Assume cost of LL is 2.
500 			 */
501 			k = (LINES - 1) - destline;
502 			if (i + k + 2 < j && (k<=0 || UP)) {
503 				tputs(LL, 0, plodput);
504 				outcol = 0;
505 				outline = LINES - 1;
506 			}
507 		}
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);
515 	if (GT)
516 		i = destcol % value(HARDTABS)
517 		    + destcol / value(HARDTABS);
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) {
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');
555 		if (NC) {
556 			if (xNL)
557 				tputs(xNL, 0, plodput);
558 			else
559 				plodput('\n');
560 			outline++;
561 		}
562 		outcol = 0;
563 	}
564 dontcr:
565 	/* Move down, if necessary, until we are at the desired line */
566 	while (outline < destline) {
567 		j = destline - outline;
568 		if (j > costDP && DOWN_PARM) {
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 		}
580 		if (plodcnt < 0)
581 			goto out;
582 		if (NONL || pfast == 0)
583 			outcol = 0;
584 	}
585 	if (BT)
586 		k = strlen(BT);	/* should probably be cost(BT) and moved out */
587 	/* Move left, if necessary, to desired column */
588 	while (outcol > destcol) {
589 		if (plodcnt < 0)
590 			goto out;
591 		if (BT && !insmode && outcol - destcol > 4+k) {
592 			tputs(BT, 0, plodput);
593 			outcol--;
594 			outcol -= outcol % value(HARDTABS); /* outcol &= ~7; */
595 			continue;
596 		}
597 		j = outcol - destcol;
598 		if (j > costLP && LEFT_PARM) {
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 		}
609 	}
610 	/* Move up, if necessary, to desired row */
611 	while (outline > destline) {
612 		j = outline - destline;
613 		if (UP_PARM && j > 1) {
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 		}
622 		if (plodcnt < 0)
623 			goto out;
624 	}
625 	/*
626 	 * Now move to the right, if necessary.  We first tab to
627 	 * as close as we can get.
628 	 */
629 	if (GT && !insmode && destcol - outcol > 1) {
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;
635 			if (TA)
636 				tputs(TA, 0, plodput);
637 			else
638 				plodput('\t');
639 			outcol = i;
640 		}
641 		/* consider another tab and then some backspaces */
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;
648 			/*
649 			 * Back up.  Don't worry about LEFT_PARM because
650 			 * it's never more than 4 spaces anyway.
651 			 */
652 			while (outcol > destcol) {
653 				outcol--;
654 				if (BC)
655 					tputs(BC, 0, plodput);
656 				else
657 					plodput('\b');
658 			}
659 		}
660 	}
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 	 */
666 	while (outcol < destcol) {
667 		j = destcol - outcol;
668 		if (j > costRP && RIGHT_PARM) {
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 		}
698 		if (plodcnt < 0)
699 			goto out;
700 	}
701 out:
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  */
715 noteinp()
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  */
733 termreset()
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  */
754 char	*obp = obuf;
755 
756 draino()
757 {
758 
759 	obp = obuf;
760 }
761 
762 flusho()
763 {
764 
765 	if (obp != obuf) {
766 		write(1, obuf, obp - obuf);
767 		obp = obuf;
768 	}
769 }
770 
771 putnl()
772 {
773 
774 	putchar('\n');
775 }
776 
777 putS(cp)
778 	char *cp;
779 {
780 
781 	if (cp == NULL)
782 		return;
783 	while (*cp)
784 		putch(*cp++);
785 }
786 
787 
788 putch(c)
789 	int c;
790 {
791 
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
796 	*obp++ = c & 0177;
797 	if (obp >= &obuf[sizeof obuf])
798 		flusho();
799 }
800 
801 /*
802  * Miscellaneous routines related to output.
803  */
804 
805 /*
806  * Put with padding
807  */
808 putpad(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  */
819 setoutt()
820 {
821 
822 	Outchar = termchar;
823 }
824 
825 /*
826  * Printf (temporarily) in list mode.
827  */
828 /*VARARGS2*/
829 lprintf(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  */
842 putNFL()
843 {
844 
845 	putnl();
846 	flush();
847 }
848 
849 /*
850  * Try to start -nl mode.
851  */
852 pstart()
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++;
865 #ifndef USG3TTY
866 	tty.sg_flags = normf & ~(ECHO|XTABS|CRMOD);
867 #else
868 	tty = normf;
869 	tty.c_oflag &= ~(ONLCR|TAB3);
870 	tty.c_lflag &= ~ECHO;
871 #endif
872 	sTTY(1);
873 }
874 
875 /*
876  * Stop -nl mode.
877  */
878 pstop()
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  */
893 ttymode
894 ostart()
895 {
896 	ttymode f;
897 
898 	if (!intty)
899 		error("Open and visual must be used interactively");
900 	gTTY(1);
901 	normtty++;
902 #ifndef USG3TTY
903 	f = tty.sg_flags;
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
913 #else
914 	f = tty;
915 	tty = normf;
916 	tty.c_iflag &= ~ICRNL;
917 	tty.c_lflag &= ~(ECHO|ICANON);
918 	tty.c_oflag &= ~(TAB3|ONLCR);
919 	tty.c_cc[VMIN] = 1;
920 	tty.c_cc[VTIME] = 1;
921 	ttcharoff();
922 #endif
923 	sTTY(1);
924 	tostart();
925 	pfast |= 2;
926 	return (f);
927 }
928 
929 /* actions associated with putting the terminal in open mode */
930 tostart()
931 {
932 	putpad(VS);
933 	putpad(KS);
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 	}
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
970 ttcharoff()
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
987 ttcharoff()
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 
1004 /*
1005  * Stop open, restoring tty modes.
1006  */
1007 ostop(f)
1008 	ttymode f;
1009 {
1010 
1011 #ifndef USG3TTY
1012 	pfast = (f & CRMOD) == 0;
1013 #else
1014 	pfast = (f.c_oflag & ONLCR) == 0;
1015 #endif
1016 	termreset(), fgoto(), flusho();
1017 	normal(f);
1018 	tostop();
1019 }
1020 
1021 /* Actions associated with putting the terminal in the right mode. */
1022 tostop()
1023 {
1024 	putpad(VE);
1025 	putpad(KE);
1026 	if (!value(MESG) && ttynbuf[0]>1)
1027 		chmod(ttynbuf, ttymesg);
1028 }
1029 
1030 #ifndef CBREAK
1031 /*
1032  * Into cooked mode for interruptibility.
1033  */
1034 vcook()
1035 {
1036 
1037 	tty.sg_flags &= ~RAW;
1038 	sTTY(1);
1039 }
1040 
1041 /*
1042  * Back into raw mode.
1043  */
1044 vraw()
1045 {
1046 
1047 	tty.sg_flags |= RAW;
1048 	sTTY(1);
1049 }
1050 #endif
1051 
1052 /*
1053  * Restore flags to normal state f.
1054  */
1055 normal(f)
1056 	ttymode f;
1057 {
1058 
1059 	if (normtty > 0) {
1060 		setty(f);
1061 		normtty--;
1062 	}
1063 }
1064 
1065 /*
1066  * Straight set of flags to state f.
1067  */
1068 ttymode
1069 setty(f)
1070 	ttymode f;
1071 {
1072 #ifndef USG3TTY
1073 	register int ot = tty.sg_flags;
1074 #else
1075 	ttymode ot;
1076 	ot = tty;
1077 #endif
1078 
1079 #ifndef USG3TTY
1080 	if (f == normf) {
1081 		nttyc = ottyc;
1082 # ifdef TIOCLGET
1083 		nlttyc = olttyc;
1084 # endif
1085 	} else
1086 		ttcharoff();
1087 	tty.sg_flags = f;
1088 #else
1089 	if (tty.c_lflag & ICANON)
1090 		ttcharoff();
1091 	tty = f;
1092 #endif
1093 	sTTY(1);
1094 	return (ot);
1095 }
1096 
1097 gTTY(i)
1098 	int i;
1099 {
1100 
1101 #ifndef USG3TTY
1102 	ignore(gtty(i, &tty));
1103 # ifdef TIOCGETC
1104 	ioctl(i, TIOCGETC, &ottyc);
1105 	nttyc = ottyc;
1106 # endif
1107 # ifdef TIOCGLTC
1108 	ioctl(i, TIOCGLTC, &olttyc);
1109 	nlttyc = olttyc;
1110 # endif
1111 #else
1112 	ioctl(i, TCGETA, &tty);
1113 #endif
1114 }
1115 
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  */
1120 sTTY(i)
1121 	int i;
1122 {
1123 
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 */
1133 	ioctl(i, TIOCSETN, &tty);
1134 # else
1135 	/* We have to.  Too bad. */
1136 	stty(i, &tty);
1137 # endif
1138 
1139 # ifdef TIOCGETC
1140 	/* Update the other random chars while we're at it. */
1141 	ioctl(i, TIOCSETC, &nttyc);
1142 # endif
1143 # ifdef TIOCSLTC
1144 	ioctl(i, TIOCSLTC, &nlttyc);
1145 # endif
1146 
1147 #else
1148 	/* USG 3 very simple: just set everything */
1149 	ioctl(i, TCSETAW, &tty);
1150 #endif
1151 }
1152 
1153 /*
1154  * Print newline, or blank if in open/visual
1155  */
1156 noonl()
1157 {
1158 
1159 	putchar(Outchar != termchar ? ' ' : '\n');
1160 }
1161