xref: /original-bsd/usr.bin/ex/ex_put.c (revision b9d18e58)
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
8 static char *sccsid = "@(#)ex_put.c	7.9 (Berkeley) 06/07/85";
9 #endif not lint
10 
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  */
31 int	(*Outchar)() = termchar;
32 int	(*Putchar)() = normchar;
33 int	(*Pline)() = normline;
34 
35 int (*
36 setlist(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 
47 int (*
48 setnumb(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  */
63 listchar(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  */
97 normchar(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  */
141 numbline(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  */
154 normline()
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  */
173 slobber(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  */
206 static	char linb[66];
207 char *linp = linb;
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  */
215 static	bool phadnl;
216 
217 /*
218  * Indirect to current definition of putchar.
219  */
220 putchar(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  */
233 termchar(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 
250 flush()
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  */
262 flush1()
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)
311 						putch('\r'), putch('\n');
312 				}
313 				c = *lp++;
314 				if (c <= ' ')
315 					break;
316 			}
317 			--lp;
318 			continue;
319 		}
320 	linp = linb;
321 }
322 
323 flush2()
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  */
337 fgoto()
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)
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');
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) {
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');
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  */
424 tab(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 
439 static int plodcnt, plodflg;
440 
441 plodput(c)
442 {
443 
444 	if (plodflg)
445 		plodcnt--;
446 	else
447 		putch(c);
448 }
449 
450 plod(cnt)
451 {
452 	register int i, j, k;
453 	register int soutcol, soutline;
454 
455 	plodcnt = plodflg = cnt;
456 	soutcol = outcol;
457 	soutline = outline;
458 	/*
459 	 * Consider homing and moving down/right from there, vs moving
460 	 * directly with local motions to the right spot.
461 	 */
462 	if (HO) {
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 		 */
468 		if (GT)
469 			i = (destcol / value(HARDTABS)) + (destcol % value(HARDTABS));
470 		else
471 			i = destcol;
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);
479 			else
480 				j = destcol - outcol;
481 		} else
482 			/* leftward motion only works if we can backspace. */
483 			if (outcol - destcol <= i && (BS || BC))
484 				i = j = outcol - destcol; /* cheaper to backspace */
485 			else
486 				j = i + 1; /* impossibly expensive */
487 
488 		/* k is the absolute value of vertical distance */
489 		k = outline - destline;
490 		if (k < 0)
491 			k = -k;
492 		j += k;
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 			 */
502 			tputs(HO, 0, plodput);
503 			outcol = outline = 0;
504 		} else if (LL) {
505 			/*
506 			 * Quickly consider homing down and moving from there.
507 			 * Assume cost of LL is 2.
508 			 */
509 			k = (LINES - 1) - destline;
510 			if (i + k + 2 < j && (k<=0 || UP)) {
511 				tputs(LL, 0, plodput);
512 				outcol = 0;
513 				outline = LINES - 1;
514 			}
515 		}
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);
523 	if (GT)
524 		i = destcol % value(HARDTABS)
525 		    + destcol / value(HARDTABS);
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) {
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');
563 		if (NC) {
564 			if (xNL)
565 				tputs(xNL, 0, plodput);
566 			else
567 				plodput('\n');
568 			outline++;
569 		}
570 		outcol = 0;
571 	}
572 dontcr:
573 	/* Move down, if necessary, until we are at the desired line */
574 	while (outline < destline) {
575 		j = destline - outline;
576 		if (j > costDP && DOWN_PARM) {
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 		}
588 		if (plodcnt < 0)
589 			goto out;
590 		if (NONL || pfast == 0)
591 			outcol = 0;
592 	}
593 	if (BT)
594 		k = strlen(BT);	/* should probably be cost(BT) and moved out */
595 	/* Move left, if necessary, to desired column */
596 	while (outcol > destcol) {
597 		if (plodcnt < 0)
598 			goto out;
599 		if (BT && !insmode && outcol - destcol > 4+k) {
600 			tputs(BT, 0, plodput);
601 			outcol--;
602 			outcol -= outcol % value(HARDTABS); /* outcol &= ~7; */
603 			continue;
604 		}
605 		j = outcol - destcol;
606 		if (j > costLP && LEFT_PARM) {
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 		}
617 	}
618 	/* Move up, if necessary, to desired row */
619 	while (outline > destline) {
620 		j = outline - destline;
621 		if (UP_PARM && j > 1) {
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 		}
630 		if (plodcnt < 0)
631 			goto out;
632 	}
633 	/*
634 	 * Now move to the right, if necessary.  We first tab to
635 	 * as close as we can get.
636 	 */
637 	if (GT && !insmode && destcol - outcol > 1) {
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;
643 			if (TA)
644 				tputs(TA, 0, plodput);
645 			else
646 				plodput('\t');
647 			outcol = i;
648 		}
649 		/* consider another tab and then some backspaces */
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;
656 			/*
657 			 * Back up.  Don't worry about LEFT_PARM because
658 			 * it's never more than 4 spaces anyway.
659 			 */
660 			while (outcol > destcol) {
661 				outcol--;
662 				if (BC)
663 					tputs(BC, 0, plodput);
664 				else
665 					plodput('\b');
666 			}
667 		}
668 	}
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 	 */
674 	while (outcol < destcol) {
675 		j = destcol - outcol;
676 		if (j > costRP && RIGHT_PARM) {
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 		}
706 		if (plodcnt < 0)
707 			goto out;
708 	}
709 out:
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  */
723 noteinp()
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  */
741 termreset()
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  */
762 char	*obp = obuf;
763 
764 draino()
765 {
766 
767 	obp = obuf;
768 }
769 
770 flusho()
771 {
772 
773 	if (obp != obuf) {
774 		write(1, obuf, obp - obuf);
775 		obp = obuf;
776 	}
777 }
778 
779 putnl()
780 {
781 
782 	putchar('\n');
783 }
784 
785 putS(cp)
786 	char *cp;
787 {
788 
789 	if (cp == NULL)
790 		return;
791 	while (*cp)
792 		putch(*cp++);
793 }
794 
795 
796 putch(c)
797 	int c;
798 {
799 
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
804 	*obp++ = c & 0177;
805 	if (obp >= &obuf[sizeof obuf])
806 		flusho();
807 }
808 
809 /*
810  * Miscellaneous routines related to output.
811  */
812 
813 /*
814  * Put with padding
815  */
816 putpad(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  */
827 setoutt()
828 {
829 
830 	Outchar = termchar;
831 }
832 
833 /*
834  * Printf (temporarily) in list mode.
835  */
836 /*VARARGS2*/
837 lprintf(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  */
850 putNFL()
851 {
852 
853 	putnl();
854 	flush();
855 }
856 
857 /*
858  * Try to start -nl mode.
859  */
860 pstart()
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++;
873 #ifndef USG3TTY
874 	tty.sg_flags = normf & ~(ECHO|XTABS|CRMOD);
875 #else
876 	tty = normf;
877 	tty.c_oflag &= ~(ONLCR|TAB3);
878 	tty.c_lflag &= ~ECHO;
879 #endif
880 	sTTY(1);
881 }
882 
883 /*
884  * Stop -nl mode.
885  */
886 pstop()
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  */
901 ttymode
902 ostart()
903 {
904 	ttymode f;
905 
906 	if (!intty)
907 		error("Open and visual must be used interactively");
908 	gTTY(1);
909 	normtty++;
910 #ifndef USG3TTY
911 	f = tty.sg_flags;
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
921 #else
922 	f = tty;
923 	tty = normf;
924 	tty.c_iflag &= ~ICRNL;
925 	tty.c_lflag &= ~(ECHO|ICANON);
926 	tty.c_oflag &= ~(TAB3|ONLCR);
927 	tty.c_cc[VMIN] = 1;
928 	tty.c_cc[VTIME] = 1;
929 	ttcharoff();
930 #endif
931 	sTTY(1);
932 	tostart();
933 	pfast |= 2;
934 	return (f);
935 }
936 
937 /* actions associated with putting the terminal in open mode */
938 tostart()
939 {
940 	putpad(VS);
941 	putpad(KS);
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 	}
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
978 ttcharoff()
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
995 ttcharoff()
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 
1012 /*
1013  * Stop open, restoring tty modes.
1014  */
1015 ostop(f)
1016 	ttymode f;
1017 {
1018 
1019 #ifndef USG3TTY
1020 	pfast = (f & CRMOD) == 0;
1021 #else
1022 	pfast = (f.c_oflag & ONLCR) == 0;
1023 #endif
1024 	termreset(), fgoto(), flusho();
1025 	normal(f);
1026 	tostop();
1027 }
1028 
1029 /* Actions associated with putting the terminal in the right mode. */
1030 tostop()
1031 {
1032 	putpad(VE);
1033 	putpad(KE);
1034 	if (!value(MESG) && ttynbuf[0]>1)
1035 		chmod(ttynbuf, ttymesg);
1036 }
1037 
1038 #ifndef CBREAK
1039 /*
1040  * Into cooked mode for interruptibility.
1041  */
1042 vcook()
1043 {
1044 
1045 	tty.sg_flags &= ~RAW;
1046 	sTTY(1);
1047 }
1048 
1049 /*
1050  * Back into raw mode.
1051  */
1052 vraw()
1053 {
1054 
1055 	tty.sg_flags |= RAW;
1056 	sTTY(1);
1057 }
1058 #endif
1059 
1060 /*
1061  * Restore flags to normal state f.
1062  */
1063 normal(f)
1064 	ttymode f;
1065 {
1066 
1067 	if (normtty > 0) {
1068 		setty(f);
1069 		normtty--;
1070 	}
1071 }
1072 
1073 /*
1074  * Straight set of flags to state f.
1075  */
1076 ttymode
1077 setty(f)
1078 	ttymode f;
1079 {
1080 #ifndef USG3TTY
1081 	register int ot = tty.sg_flags;
1082 #else
1083 	ttymode ot;
1084 	ot = tty;
1085 #endif
1086 
1087 #ifndef USG3TTY
1088 	if (f == normf) {
1089 		nttyc = ottyc;
1090 # ifdef TIOCLGET
1091 		nlttyc = olttyc;
1092 # endif
1093 	} else
1094 		ttcharoff();
1095 	tty.sg_flags = f;
1096 #else
1097 	if (tty.c_lflag & ICANON)
1098 		ttcharoff();
1099 	tty = f;
1100 #endif
1101 	sTTY(1);
1102 	return (ot);
1103 }
1104 
1105 gTTY(i)
1106 	int i;
1107 {
1108 
1109 #ifndef USG3TTY
1110 	ignore(gtty(i, &tty));
1111 # ifdef TIOCGETC
1112 	ioctl(i, TIOCGETC, &ottyc);
1113 	nttyc = ottyc;
1114 # endif
1115 # ifdef TIOCGLTC
1116 	ioctl(i, TIOCGLTC, &olttyc);
1117 	nlttyc = olttyc;
1118 # endif
1119 #else
1120 	ioctl(i, TCGETA, &tty);
1121 #endif
1122 }
1123 
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  */
1128 sTTY(i)
1129 	int i;
1130 {
1131 
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 */
1141 	ioctl(i, TIOCSETN, &tty);
1142 # else
1143 	/* We have to.  Too bad. */
1144 	stty(i, &tty);
1145 # endif
1146 
1147 # ifdef TIOCGETC
1148 	/* Update the other random chars while we're at it. */
1149 	ioctl(i, TIOCSETC, &nttyc);
1150 # endif
1151 # ifdef TIOCSLTC
1152 	ioctl(i, TIOCSLTC, &nlttyc);
1153 # endif
1154 
1155 #else
1156 	/* USG 3 very simple: just set everything */
1157 	ioctl(i, TCSETAW, &tty);
1158 #endif
1159 }
1160 
1161 /*
1162  * Print newline, or blank if in open/visual
1163  */
1164 noonl()
1165 {
1166 
1167 	putchar(Outchar != termchar ? ' ' : '\n');
1168 }
1169