xref: /original-bsd/usr.bin/ex/ex_put.c (revision de38840f)
1 /* Copyright (c) 1981 Regents of the University of California */
2 static char *sccsid = "@(#)ex_put.c	7.1	07/08/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 static	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 	while (outline < destline) {
566 		outline++;
567 		if (xNL && pfast)
568 			tputs(xNL, 0, plodput);
569 		else
570 			plodput('\n');
571 		if (plodcnt < 0)
572 			goto out;
573 		if (NONL || pfast == 0)
574 			outcol = 0;
575 	}
576 	if (BT)
577 		k = strlen(BT);
578 	while (outcol > destcol) {
579 		if (plodcnt < 0)
580 			goto out;
581 /*
582 		if (BT && !insmode && outcol - destcol > 4+k) {
583 			tputs(BT, 0, plodput);
584 			outcol--;
585 			outcol &= ~7;
586 			continue;
587 		}
588 */
589 		outcol--;
590 		if (BC)
591 			tputs(BC, 0, plodput);
592 		else
593 			plodput('\b');
594 	}
595 	while (outline > destline) {
596 		outline--;
597 		tputs(UP, 0, plodput);
598 		if (plodcnt < 0)
599 			goto out;
600 	}
601 	if (GT && !insmode && destcol - outcol > 1) {
602 	for (;;) {
603 		i = tabcol(outcol, value(HARDTABS));
604 		if (i > destcol)
605 			break;
606 			if (TA)
607 				tputs(TA, 0, plodput);
608 			else
609 				plodput('\t');
610 			outcol = i;
611 		}
612 		if (destcol - outcol > 4 && i < COLUMNS && (BC || BS)) {
613 			if (TA)
614 				tputs(TA, 0, plodput);
615 			else
616 				plodput('\t');
617 			outcol = i;
618 			while (outcol > destcol) {
619 				outcol--;
620 				if (BC)
621 					tputs(BC, 0, plodput);
622 				else
623 					plodput('\b');
624 			}
625 		}
626 	}
627 	while (outcol < destcol) {
628 		/*
629 		 * move one char to the right.  We don't use ND space
630 		 * because it's better to just print the char we are
631 		 * moving over.  There are various exceptions, however.
632 		 * If !inopen, vtube contains garbage.  If the char is
633 		 * a null or a tab we want to print a space.  Other random
634 		 * chars we use space for instead, too.
635 		 */
636 		if (!inopen || vtube[outline]==NULL ||
637 			(i=vtube[outline][outcol]) < ' ')
638 			i = ' ';
639 		if(i & QUOTE)		/* mjm: no sign extension on 3B */
640 			i = ' ';
641 		if (insmode && ND)
642 			tputs(ND, 0, plodput);
643 		else
644 			plodput(i);
645 		outcol++;
646 		if (plodcnt < 0)
647 			goto out;
648 	}
649 out:
650 	if (plodflg) {
651 		outcol = soutcol;
652 		outline = soutline;
653 	}
654 	return(plodcnt);
655 }
656 
657 /*
658  * An input line arrived.
659  * Calculate new (approximate) screen line position.
660  * Approximate because kill character echoes newline with
661  * no feedback and also because of long input lines.
662  */
663 noteinp()
664 {
665 
666 	outline++;
667 	if (outline > LINES - 1)
668 		outline = LINES - 1;
669 	destline = outline;
670 	destcol = outcol = 0;
671 }
672 
673 /*
674  * Something weird just happened and we
675  * lost track of whats happening out there.
676  * Since we cant, in general, read where we are
677  * we just reset to some known state.
678  * On cursor addressible terminals setting to unknown
679  * will force a cursor address soon.
680  */
681 termreset()
682 {
683 
684 	endim();
685 	if (TI)	/* otherwise it flushes anyway, and 'set tty=dumb' vomits */
686 		putpad(TI);	 /*adb change -- emit terminal initial sequence */
687 	destcol = 0;
688 	destline = LINES - 1;
689 	if (CA) {
690 		outcol = UKCOL;
691 		outline = UKCOL;
692 	} else {
693 		outcol = destcol;
694 		outline = destline;
695 	}
696 }
697 
698 /*
699  * Low level buffering, with the ability to drain
700  * buffered output without printing it.
701  */
702 char	*obp = obuf;
703 
704 draino()
705 {
706 
707 	obp = obuf;
708 }
709 
710 flusho()
711 {
712 
713 	if (obp != obuf) {
714 		write(1, obuf, obp - obuf);
715 		obp = obuf;
716 	}
717 }
718 
719 putnl()
720 {
721 
722 	putchar('\n');
723 }
724 
725 putS(cp)
726 	char *cp;
727 {
728 
729 	if (cp == NULL)
730 		return;
731 	while (*cp)
732 		putch(*cp++);
733 }
734 
735 
736 putch(c)
737 	int c;
738 {
739 
740 #ifdef OLD3BTTY		/* mjm */
741 	if(c == '\n')	/* mjm: Fake "\n\r" for '\n' til fix in 3B firmware */
742 		putch('\r');	/* mjm: vi does "stty -icanon" => -onlcr !! */
743 #endif
744 	*obp++ = c & 0177;
745 	if (obp >= &obuf[sizeof obuf])
746 		flusho();
747 }
748 
749 /*
750  * Miscellaneous routines related to output.
751  */
752 
753 /*
754  * Put with padding
755  */
756 putpad(cp)
757 	char *cp;
758 {
759 
760 	flush();
761 	tputs(cp, 0, putch);
762 }
763 
764 /*
765  * Set output through normal command mode routine.
766  */
767 setoutt()
768 {
769 
770 	Outchar = termchar;
771 }
772 
773 /*
774  * Printf (temporarily) in list mode.
775  */
776 /*VARARGS2*/
777 lprintf(cp, dp)
778 	char *cp, *dp;
779 {
780 	register int (*P)();
781 
782 	P = setlist(1);
783 	printf(cp, dp);
784 	Putchar = P;
785 }
786 
787 /*
788  * Newline + flush.
789  */
790 putNFL()
791 {
792 
793 	putnl();
794 	flush();
795 }
796 
797 /*
798  * Try to start -nl mode.
799  */
800 pstart()
801 {
802 
803 	if (NONL)
804 		return;
805  	if (!value(OPTIMIZE))
806 		return;
807 	if (ruptible == 0 || pfast)
808 		return;
809 	fgoto();
810 	flusho();
811 	pfast = 1;
812 	normtty++;
813 #ifndef USG3TTY
814 	tty.sg_flags = normf & ~(ECHO|XTABS|CRMOD);
815 #else
816 	tty = normf;
817 	tty.c_oflag &= ~(ONLCR|TAB3);
818 	tty.c_lflag &= ~ECHO;
819 #endif
820 	sTTY(1);
821 }
822 
823 /*
824  * Stop -nl mode.
825  */
826 pstop()
827 {
828 
829 	if (inopen)
830 		return;
831 	phadnl = 0;
832 	linp = linb;
833 	draino();
834 	normal(normf);
835 	pfast &= ~1;
836 }
837 
838 /*
839  * Prep tty for open mode.
840  */
841 ttymode
842 ostart()
843 {
844 	ttymode f;
845 
846 	if (!intty)
847 		error("Open and visual must be used interactively");
848 	gTTY(1);
849 	normtty++;
850 #ifndef USG3TTY
851 	f = tty.sg_flags;
852 	tty.sg_flags = (normf &~ (ECHO|XTABS|CRMOD)) |
853 # ifdef CBREAK
854 							CBREAK;
855 # else
856 							RAW;
857 # endif
858 # ifdef TIOCGETC
859 	ttcharoff();
860 # endif
861 #else
862 	f = tty;
863 	tty = normf;
864 	tty.c_iflag &= ~ICRNL;
865 	tty.c_lflag &= ~(ECHO|ICANON);
866 	tty.c_oflag &= ~TAB3;
867 	tty.c_cc[VMIN] = 1;
868 	tty.c_cc[VTIME] = 1;
869 	ttcharoff();
870 #endif
871 	sTTY(1);
872 	tostart();
873 	pfast |= 2;
874 	return (f);
875 }
876 
877 /* actions associated with putting the terminal in open mode */
878 tostart()
879 {
880 	putpad(VS);
881 	putpad(KS);
882 	if (!value(MESG)) {
883 		if (ttynbuf[0] == 0) {
884 			register char *tn;
885 			if ((tn=ttyname(2)) == NULL &&
886 			    (tn=ttyname(1)) == NULL &&
887 			    (tn=ttyname(0)) == NULL)
888 				ttynbuf[0] = 1;
889 			else
890 				strcpy(ttynbuf, tn);
891 		}
892 		if (ttynbuf[0] != 1) {
893 			struct stat sbuf;
894 			stat(ttynbuf, &sbuf);
895 			ttymesg = sbuf.st_mode & 0777;
896 			chmod(ttynbuf,
897 #ifdef UCBV7
898 	/*
899 	 * This applies to the UCB V7 Pdp-11 system with the
900 	 * -u write option only.
901 	 */
902 					0611	/* 11 = urgent only allowed */
903 #else
904 					0600
905 #endif
906 						);
907 		}
908 	}
909 }
910 
911 /*
912  * Turn off start/stop chars if they aren't the default ^S/^Q.
913  * This is so idiots who make esc their start/stop don't lose.
914  * We always turn off quit since datamedias send ^\ for their
915  * right arrow key.
916  */
917 #ifdef TIOCGETC
918 ttcharoff()
919 {
920 	nttyc.t_quitc = '\377';
921 	if (nttyc.t_startc != CTRL(q))
922 		nttyc.t_startc = '\377';
923 	if (nttyc.t_stopc != CTRL(s))
924 		nttyc.t_stopc = '\377';
925 # ifdef TIOCLGET
926 	nlttyc.t_suspc = '\377';	/* ^Z */
927 	nlttyc.t_dsuspc = '\377';	/* ^Y */
928 	nlttyc.t_flushc = '\377';	/* ^O */
929 	nlttyc.t_lnextc = '\377';	/* ^V */
930 # endif
931 }
932 #endif
933 
934 #ifdef USG3TTY
935 ttcharoff()
936 {
937 	tty.c_cc[VQUIT] = '\377';
938 # ifdef VSTART
939 	/*
940 	 * The following is sample code if USG ever lets people change
941 	 * their start/stop chars.  As long as they can't we can't get
942 	 * into trouble so we just leave them alone.
943 	 */
944 	if (tty.c_cc[VSTART] != CTRL(q))
945 		tty.c_cc[VSTART] = '\377';
946 	if (tty.c_cc[VSTOP] != CTRL(s))
947 		tty.c_cc[VSTOP] = '\377';
948 # endif
949 }
950 #endif
951 
952 /*
953  * Stop open, restoring tty modes.
954  */
955 ostop(f)
956 	ttymode f;
957 {
958 
959 #ifndef USG3TTY
960 	pfast = (f & CRMOD) == 0;
961 #else
962 	pfast = (f.c_oflag & OCRNL) == 0;
963 #endif
964 	termreset(), fgoto(), flusho();
965 	normal(f);
966 	tostop();
967 }
968 
969 /* Actions associated with putting the terminal in the right mode. */
970 tostop()
971 {
972 	putpad(VE);
973 	putpad(KE);
974 	if (!value(MESG))
975 		chmod(ttynbuf, ttymesg);
976 }
977 
978 #ifndef CBREAK
979 /*
980  * Into cooked mode for interruptibility.
981  */
982 vcook()
983 {
984 
985 	tty.sg_flags &= ~RAW;
986 	sTTY(1);
987 }
988 
989 /*
990  * Back into raw mode.
991  */
992 vraw()
993 {
994 
995 	tty.sg_flags |= RAW;
996 	sTTY(1);
997 }
998 #endif
999 
1000 /*
1001  * Restore flags to normal state f.
1002  */
1003 normal(f)
1004 	ttymode f;
1005 {
1006 
1007 	if (normtty > 0) {
1008 		setty(f);
1009 		normtty--;
1010 	}
1011 }
1012 
1013 /*
1014  * Straight set of flags to state f.
1015  */
1016 ttymode
1017 setty(f)
1018 	ttymode f;
1019 {
1020 #ifndef USG3TTY
1021 	register int ot = tty.sg_flags;
1022 #else
1023 	ttymode ot;
1024 	ot = tty;
1025 #endif
1026 
1027 #ifndef USG3TTY
1028 	if (f == normf) {
1029 		nttyc = ottyc;
1030 # ifdef TIOCLGET
1031 		nlttyc = olttyc;
1032 # endif
1033 	} else
1034 		ttcharoff();
1035 	tty.sg_flags = f;
1036 #else
1037 	if (tty.c_lflag & ICANON)
1038 		ttcharoff();
1039 	tty = f;
1040 #endif
1041 	sTTY(1);
1042 	return (ot);
1043 }
1044 
1045 gTTY(i)
1046 	int i;
1047 {
1048 
1049 #ifndef USG3TTY
1050 	ignore(gtty(i, &tty));
1051 # ifdef TIOCGETC
1052 	ioctl(i, TIOCGETC, &ottyc);
1053 	nttyc = ottyc;
1054 # endif
1055 # ifdef TIOCGLTC
1056 	ioctl(i, TIOCGLTC, &olttyc);
1057 	nlttyc = olttyc;
1058 # endif
1059 #else
1060 	ioctl(i, TCGETA, &tty);
1061 #endif
1062 }
1063 
1064 /*
1065  * sTTY: set the tty modes on file descriptor i to be what's
1066  * currently in global "tty".  (Also use nttyc if needed.)
1067  */
1068 sTTY(i)
1069 	int i;
1070 {
1071 
1072 #ifndef USG3TTY
1073 # ifdef USG
1074 	/* Bug in USG tty driver, put out a DEL as a patch. */
1075 	if (tty.sg_ospeed >= B1200)
1076 		write(1, "\377", 1);
1077 # endif
1078 
1079 # ifdef TIOCSETN
1080 	/* Don't flush typeahead if we don't have to */
1081 	ioctl(i, TIOCSETN, &tty);
1082 # else
1083 	/* We have to.  Too bad. */
1084 	stty(i, &tty);
1085 # endif
1086 
1087 # ifdef TIOCGETC
1088 	/* Update the other random chars while we're at it. */
1089 	ioctl(i, TIOCSETC, &nttyc);
1090 # endif
1091 # ifdef TIOCSLTC
1092 	ioctl(i, TIOCSLTC, &nlttyc);
1093 # endif
1094 
1095 #else
1096 	/* USG 3 very simple: just set everything */
1097 	ioctl(i, TCSETAW, &tty);
1098 #endif
1099 }
1100 
1101 /*
1102  * Print newline, or blank if in open/visual
1103  */
1104 noonl()
1105 {
1106 
1107 	putchar(Outchar != termchar ? ' ' : '\n');
1108 }
1109