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