xref: /original-bsd/usr.bin/ex/ex_put.c (revision 79cf7955)
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.11 (Berkeley) 01/02/88";
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	(*Put_char)() = 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 = Put_char;
43 	Put_char = 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 		ex_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 	ex_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 		ex_putchar(*cp++);
164 	if (!inopen)
165 		ex_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 (Put_char == 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 ex_putchar(c)
221 	int c;
222 {
223 
224 	(*Put_char)(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 #ifndef vms
775 		write(1, obuf, obp - obuf);
776 #else
777 		vms_write(1, obuf, obp - obuf);
778 #endif
779 		obp = obuf;
780 	}
781 }
782 
783 putnl()
784 {
785 
786 	ex_putchar('\n');
787 }
788 
789 ex_putS(cp)
790 	char *cp;
791 {
792 
793 	if (cp == NULL)
794 		return;
795 	while (*cp)
796 		putch(*cp++);
797 }
798 
799 
800 putch(c)
801 	int c;
802 {
803 
804 #ifdef OLD3BTTY		/* mjm */
805 	if(c == '\n')	/* mjm: Fake "\n\r" for '\n' til fix in 3B firmware */
806 		putch('\r');	/* mjm: vi does "stty -icanon" => -onlcr !! */
807 #endif
808 	*obp++ = c & 0177;
809 	if (obp >= &obuf[sizeof obuf])
810 		flusho();
811 }
812 
813 /*
814  * Miscellaneous routines related to output.
815  */
816 
817 /*
818  * Put with padding
819  */
820 putpad(cp)
821 	char *cp;
822 {
823 
824 	flush();
825 	tputs(cp, 0, putch);
826 }
827 
828 /*
829  * Set output through normal command mode routine.
830  */
831 setoutt()
832 {
833 
834 	Outchar = termchar;
835 }
836 
837 /*
838  * Printf (temporarily) in list mode.
839  */
840 /*VARARGS1*/
841 lprintf(cp, dp)
842 	char *cp, *dp;
843 {
844 	register int (*P)();
845 
846 	P = setlist(1);
847 	ex_printf(cp, dp);
848 	Put_char = P;
849 }
850 
851 /*
852  * Newline + flush.
853  */
854 putNFL()
855 {
856 
857 	putnl();
858 	flush();
859 }
860 
861 /*
862  * Try to start -nl mode.
863  */
864 pstart()
865 {
866 
867 	if (NONL)
868 		return;
869  	if (!value(OPTIMIZE))
870 		return;
871 	if (ruptible == 0 || pfast)
872 		return;
873 	fgoto();
874 	flusho();
875 	pfast = 1;
876 	normtty++;
877 #ifndef USG3TTY
878 	tty.sg_flags = normf & ~(ECHO|XTABS|CRMOD);
879 #else
880 	tty = normf;
881 	tty.c_oflag &= ~(ONLCR|TAB3);
882 	tty.c_lflag &= ~ECHO;
883 #endif
884 	ex_sTTY(1);
885 }
886 
887 /*
888  * Stop -nl mode.
889  */
890 pstop()
891 {
892 
893 	if (inopen)
894 		return;
895 	phadnl = 0;
896 	linp = linb;
897 	draino();
898 	normal(normf);
899 	pfast &= ~1;
900 }
901 
902 /*
903  * Prep tty for open mode.
904  */
905 ttymode
906 ostart()
907 {
908 	ttymode f;
909 
910 	if (!intty)
911 		error("Open and visual must be used interactively");
912 	ex_gTTY(1);
913 	normtty++;
914 #ifndef USG3TTY
915 	f = tty.sg_flags;
916 	tty.sg_flags = (normf &~ (ECHO|XTABS|CRMOD)) |
917 # ifdef CBREAK
918 							CBREAK;
919 # else
920 							RAW;
921 # endif
922 # ifdef TIOCGETC
923 	ttcharoff();
924 # endif
925 #else
926 	f = tty;
927 	tty = normf;
928 	tty.c_iflag &= ~ICRNL;
929 	tty.c_lflag &= ~(ECHO|ICANON);
930 	tty.c_oflag &= ~(TAB3|ONLCR);
931 	tty.c_cc[VMIN] = 1;
932 	tty.c_cc[VTIME] = 1;
933 	ttcharoff();
934 #endif
935 	ex_sTTY(1);
936 	tostart();
937 	pfast |= 2;
938 	return (f);
939 }
940 
941 /* actions associated with putting the terminal in open mode */
942 tostart()
943 {
944 	putpad(VS);
945 	putpad(KS);
946 	if (!value(MESG)) {
947 		if (ttynbuf[0] == 0) {
948 			register char *tn;
949 			if ((tn=ttyname(2)) == NULL &&
950 			    (tn=ttyname(1)) == NULL &&
951 			    (tn=ttyname(0)) == NULL)
952 				ttynbuf[0] = 1;
953 			else
954 				strcpy(ttynbuf, tn);
955 		}
956 		if (ttynbuf[0] != 1) {
957 			struct stat sbuf;
958 			stat(ttynbuf, &sbuf);
959 			ttymesg = sbuf.st_mode & 0777;
960 			chmod(ttynbuf,
961 #ifdef UCBV7
962 	/*
963 	 * This applies to the UCB V7 Pdp-11 system with the
964 	 * -u write option only.
965 	 */
966 					0611	/* 11 = urgent only allowed */
967 #else
968 					0600
969 #endif
970 						);
971 		}
972 	}
973 }
974 
975 /*
976  * Turn off start/stop chars if they aren't the default ^S/^Q.
977  * This is so idiots who make esc their start/stop don't lose.
978  * We always turn off quit since datamedias send ^\ for their
979  * right arrow key.
980  */
981 #ifdef TIOCGETC
982 ttcharoff()
983 {
984 	nttyc.t_quitc = '\377';
985 	if (nttyc.t_startc != CTRL('q'))
986 		nttyc.t_startc = '\377';
987 	if (nttyc.t_stopc != CTRL('s'))
988 		nttyc.t_stopc = '\377';
989 # ifdef TIOCLGET
990 	nlttyc.t_suspc = '\377';	/* ^Z */
991 	nlttyc.t_dsuspc = '\377';	/* ^Y */
992 	nlttyc.t_flushc = '\377';	/* ^O */
993 	nlttyc.t_lnextc = '\377';	/* ^V */
994 # endif
995 }
996 #endif
997 
998 #ifdef USG3TTY
999 ttcharoff()
1000 {
1001 	tty.c_cc[VQUIT] = '\377';
1002 # ifdef VSTART
1003 	/*
1004 	 * The following is sample code if USG ever lets people change
1005 	 * their start/stop chars.  As long as they can't we can't get
1006 	 * into trouble so we just leave them alone.
1007 	 */
1008 	if (tty.c_cc[VSTART] != CTRL('q'))
1009 		tty.c_cc[VSTART] = '\377';
1010 	if (tty.c_cc[VSTOP] != CTRL('s'))
1011 		tty.c_cc[VSTOP] = '\377';
1012 # endif
1013 }
1014 #endif
1015 
1016 /*
1017  * Stop open, restoring tty modes.
1018  */
1019 ostop(f)
1020 	ttymode f;
1021 {
1022 
1023 #ifndef USG3TTY
1024 	pfast = (f & CRMOD) == 0;
1025 #else
1026 	pfast = (f.c_oflag & ONLCR) == 0;
1027 #endif
1028 	termreset(), fgoto(), flusho();
1029 	normal(f);
1030 	tostop();
1031 }
1032 
1033 /* Actions associated with putting the terminal in the right mode. */
1034 tostop()
1035 {
1036 	putpad(VE);
1037 	putpad(KE);
1038 	if (!value(MESG) && ttynbuf[0]>1)
1039 		chmod(ttynbuf, ttymesg);
1040 }
1041 
1042 #ifndef CBREAK
1043 /*
1044  * Into cooked mode for interruptibility.
1045  */
1046 vcook()
1047 {
1048 
1049 	tty.sg_flags &= ~RAW;
1050 	ex_sTTY(1);
1051 }
1052 
1053 /*
1054  * Back into raw mode.
1055  */
1056 vraw()
1057 {
1058 
1059 	tty.sg_flags |= RAW;
1060 	ex_sTTY(1);
1061 }
1062 #endif
1063 
1064 /*
1065  * Restore flags to normal state f.
1066  */
1067 normal(f)
1068 	ttymode f;
1069 {
1070 
1071 	if (normtty > 0) {
1072 		ignore(setty(f));
1073 		normtty--;
1074 	}
1075 }
1076 
1077 /*
1078  * Straight set of flags to state f.
1079  */
1080 ttymode
1081 setty(f)
1082 	ttymode f;
1083 {
1084 #ifndef USG3TTY
1085 	register int ot = tty.sg_flags;
1086 #else
1087 	ttymode ot;
1088 	ot = tty;
1089 #endif
1090 
1091 #ifndef USG3TTY
1092 # ifdef TIOCGETC
1093 	if (f == normf) {
1094 		nttyc = ottyc;
1095 # ifdef TIOCLGET
1096 		nlttyc = olttyc;
1097 # endif
1098 	} else
1099 		ttcharoff();
1100 # endif
1101 	tty.sg_flags = f;
1102 #else
1103 	if (tty.c_lflag & ICANON)
1104 		ttcharoff();
1105 	tty = f;
1106 #endif
1107 	ex_sTTY(1);
1108 	return (ot);
1109 }
1110 
1111 ex_gTTY(i)
1112 	int i;
1113 {
1114 
1115 #ifndef USG3TTY
1116 	ignore(gtty(i, &tty));
1117 # ifdef TIOCGETC
1118 	ioctl(i, TIOCGETC, (char *) &ottyc);
1119 	nttyc = ottyc;
1120 # endif
1121 # ifdef TIOCGLTC
1122 	ioctl(i, TIOCGLTC, (char *) &olttyc);
1123 	nlttyc = olttyc;
1124 # endif
1125 #else
1126 	ioctl(i, TCGETA, (char *) &tty);
1127 #endif
1128 }
1129 
1130 /*
1131  * ex_sTTY: set the tty modes on file descriptor i to be what's
1132  * currently in global "tty".  (Also use nttyc if needed.)
1133  */
1134 ex_sTTY(i)
1135 	int i;
1136 {
1137 
1138 #ifndef USG3TTY
1139 # ifdef USG
1140 	/* Bug in USG tty driver, put out a DEL as a patch. */
1141 	if (tty.sg_ospeed >= B1200)
1142 		write(1, "\377", 1);
1143 # endif
1144 
1145 # ifdef TIOCSETN
1146 	/* Don't flush typeahead if we don't have to */
1147 	ioctl(i, TIOCSETN, (char *) &tty);
1148 # else
1149 	/* We have to.  Too bad. */
1150 	stty(i, &tty);
1151 # endif
1152 
1153 # ifdef TIOCGETC
1154 	/* Update the other random chars while we're at it. */
1155 	ioctl(i, TIOCSETC, (char *) &nttyc);
1156 # endif
1157 # ifdef TIOCSLTC
1158 	ioctl(i, TIOCSLTC, (char *) &nlttyc);
1159 # endif
1160 
1161 #else
1162 	/* USG 3 very simple: just set everything */
1163 	ioctl(i, TCSETAW, (char *) &tty);
1164 #endif
1165 }
1166 
1167 /*
1168  * Print newline, or blank if in open/visual
1169  */
1170 noonl()
1171 {
1172 
1173 	ex_putchar(Outchar != termchar ? ' ' : '\n');
1174 }
1175