1 /*-
2 * Copyright (c) 1980, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.proprietary.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)ex_put.c 8.1 (Berkeley) 06/09/93";
10 #endif /* not lint */
11
12 #include "ex.h"
13 #include "ex_tty.h"
14 #include "ex_vis.h"
15
16 /*
17 * Terminal driving and line formatting routines.
18 * Basic motion optimizations are done here as well
19 * as formatting of lines (printing of control characters,
20 * line numbering and the like).
21 */
22
23 /*
24 * The routines outchar, putchar and pline are actually
25 * variables, and these variables point at the current definitions
26 * of the routines. See the routine setflav.
27 * We sometimes make outchar be routines which catch the characters
28 * to be printed, e.g. if we want to see how long a line is.
29 * During open/visual, outchar and putchar will be set to
30 * routines in the file ex_vput.c (vputchar, vinschar, etc.).
31 */
32 int (*Outchar)() = termchar;
33 int (*Put_char)() = normchar;
34 int (*Pline)() = normline;
35
36 int (*
37 setlist(t))()
38 bool t;
39 {
40 register int (*P)();
41
42 listf = t;
43 P = Put_char;
44 Put_char = t ? listchar : normchar;
45 return (P);
46 }
47
48 int (*
49 setnumb(t))()
50 bool t;
51 {
52 register int (*P)();
53
54 numberf = t;
55 P = Pline;
56 Pline = t ? numbline : normline;
57 return (P);
58 }
59
60 /*
61 * Format c for list mode; leave things in common
62 * with normal print mode to be done by normchar.
63 */
listchar(c)64 listchar(c)
65 register short c;
66 {
67
68 c &= (TRIM|QUOTE);
69 switch (c) {
70
71 case '\t':
72 case '\b':
73 outchar('^');
74 c = ctlof(c);
75 break;
76
77 case '\n':
78 break;
79
80 case '\n' | QUOTE:
81 outchar('$');
82 break;
83
84 default:
85 if (c & QUOTE)
86 break;
87 if (c < ' ' && c != '\n' || c == DELETE)
88 outchar('^'), c = ctlof(c);
89 break;
90 }
91 normchar(c);
92 }
93
94 /*
95 * Format c for printing. Handle funnies of upper case terminals
96 * and crocky hazeltines which don't have ~.
97 */
normchar(c)98 normchar(c)
99 register short c;
100 {
101 register char *colp;
102
103 c &= (TRIM|QUOTE);
104 if (c == '~' && HZ) {
105 normchar('\\');
106 c = '^';
107 }
108 if (c & QUOTE)
109 switch (c) {
110
111 case ' ' | QUOTE:
112 case '\b' | QUOTE:
113 break;
114
115 case QUOTE:
116 return;
117
118 default:
119 c &= TRIM;
120 }
121 else if (c < ' ' && (c != '\b' || !OS) && c != '\n' && c != '\t' || c == DELETE)
122 ex_putchar('^'), c = ctlof(c);
123 else if (UPPERCASE)
124 if (isupper(c)) {
125 outchar('\\');
126 c = tolower(c);
127 } else {
128 colp = "({)}!|^~'`";
129 while (*colp++)
130 if (c == *colp++) {
131 outchar('\\');
132 c = colp[-2];
133 break;
134 }
135 }
136 outchar(c);
137 }
138
139 /*
140 * Print a line with a number.
141 */
numbline(i)142 numbline(i)
143 int i;
144 {
145
146 if (shudclob)
147 slobber(' ');
148 ex_printf("%6d ", i);
149 normline();
150 }
151
152 /*
153 * Normal line output, no numbering.
154 */
normline()155 normline()
156 {
157 register char *cp;
158
159 if (shudclob)
160 slobber(linebuf[0]);
161 /* pdp-11 doprnt is not reentrant so can't use "printf" here
162 in case we are tracing */
163 for (cp = linebuf; *cp;)
164 ex_putchar(*cp++);
165 if (!inopen)
166 ex_putchar('\n' | QUOTE);
167 }
168
169 /*
170 * Given c at the beginning of a line, determine whether
171 * the printing of the line will erase or otherwise obliterate
172 * the prompt which was printed before. If it won't, do it now.
173 */
slobber(c)174 slobber(c)
175 int c;
176 {
177
178 shudclob = 0;
179 switch (c) {
180
181 case '\t':
182 if (Put_char == listchar)
183 return;
184 break;
185
186 default:
187 return;
188
189 case ' ':
190 case 0:
191 break;
192 }
193 if (OS)
194 return;
195 flush();
196 putch(' ');
197 if (BC)
198 tputs(BC, 0, putch);
199 else
200 putch('\b');
201 }
202
203 /*
204 * The output buffer is initialized with a useful error
205 * message so we don't have to keep it in data space.
206 */
207 static char linb[66];
208 char *linp = linb;
209
210 /*
211 * Phadnl records when we have already had a complete line ending with \n.
212 * If another line starts without a flush, and the terminal suggests it,
213 * we switch into -nl mode so that we can send lineffeeds to avoid
214 * a lot of spacing.
215 */
216 static bool phadnl;
217
218 /*
219 * Indirect to current definition of putchar.
220 */
ex_putchar(c)221 ex_putchar(c)
222 int c;
223 {
224
225 (*Put_char)(c);
226 }
227
228 /*
229 * Termchar routine for command mode.
230 * Watch for possible switching to -nl mode.
231 * Otherwise flush into next level of buffering when
232 * small buffer fills or at a newline.
233 */
termchar(c)234 termchar(c)
235 int c;
236 {
237
238 if (pfast == 0 && phadnl)
239 pstart();
240 if (c == '\n')
241 phadnl = 1;
242 else if (linp >= &linb[63])
243 flush1();
244 *linp++ = c;
245 if (linp >= &linb[63]) {
246 fgoto();
247 flush1();
248 }
249 }
250
flush()251 flush()
252 {
253
254 flush1();
255 flush2();
256 }
257
258 /*
259 * Flush from small line buffer into output buffer.
260 * Work here is destroying motion into positions, and then
261 * letting fgoto do the optimized motion.
262 */
flush1()263 flush1()
264 {
265 register char *lp;
266 register short c;
267
268 *linp = 0;
269 lp = linb;
270 while (*lp)
271 switch (c = *lp++) {
272
273 case '\r':
274 destline += destcol / COLUMNS;
275 destcol = 0;
276 continue;
277
278 case '\b':
279 if (destcol)
280 destcol--;
281 continue;
282
283 case ' ':
284 destcol++;
285 continue;
286
287 case '\t':
288 destcol += value(TABSTOP) - destcol % value(TABSTOP);
289 continue;
290
291 case '\n':
292 destline += destcol / COLUMNS + 1;
293 if (destcol != 0 && destcol % COLUMNS == 0)
294 destline--;
295 destcol = 0;
296 continue;
297
298 default:
299 fgoto();
300 for (;;) {
301 if (AM == 0 && outcol == COLUMNS)
302 fgoto();
303 c &= TRIM;
304 putch(c);
305 if (c == '\b') {
306 outcol--;
307 destcol--;
308 } else if (c >= ' ' && c != DELETE) {
309 outcol++;
310 destcol++;
311 if (XN && outcol % COLUMNS == 0)
312 putch('\r'), putch('\n');
313 }
314 c = *lp++;
315 if (c <= ' ')
316 break;
317 }
318 --lp;
319 continue;
320 }
321 linp = linb;
322 }
323
flush2()324 flush2()
325 {
326
327 fgoto();
328 flusho();
329 pstop();
330 }
331
332 /*
333 * Sync the position of the output cursor.
334 * Most work here is rounding for terminal boundaries getting the
335 * column position implied by wraparound or the lack thereof and
336 * rolling up the screen to get destline on the screen.
337 */
fgoto()338 fgoto()
339 {
340 register int l, c;
341
342 if (destcol > COLUMNS - 1) {
343 destline += destcol / COLUMNS;
344 destcol %= COLUMNS;
345 }
346 if (outcol > COLUMNS - 1) {
347 l = (outcol + 1) / COLUMNS;
348 outline += l;
349 outcol %= COLUMNS;
350 if (AM == 0) {
351 while (l > 0) {
352 if (pfast)
353 if (xCR)
354 tputs(xCR, 0, putch);
355 else
356 putch('\r');
357 if (xNL)
358 tputs(xNL, 0, putch);
359 else
360 putch('\n');
361 l--;
362 }
363 outcol = 0;
364 }
365 if (outline > LINES - 1) {
366 destline -= outline - (LINES - 1);
367 outline = LINES - 1;
368 }
369 }
370 if (destline > LINES - 1) {
371 l = destline;
372 destline = LINES - 1;
373 if (outline < LINES - 1) {
374 c = destcol;
375 if (pfast == 0 && (!CA || holdcm))
376 destcol = 0;
377 fgoto();
378 destcol = c;
379 }
380 while (l > LINES - 1) {
381 /*
382 * The following linefeed (or simulation thereof)
383 * is supposed to scroll up the screen, since we
384 * are on the bottom line. We make the assumption
385 * that linefeed will scroll. If ns is in the
386 * capability list this won't work. We should
387 * probably have an sc capability but sf will
388 * generally take the place if it works.
389 *
390 * Superbee glitch: in the middle of the screen we
391 * have to use esc B (down) because linefeed screws up
392 * in "Efficient Paging" (what a joke) mode (which is
393 * essential in some SB's because CRLF mode puts garbage
394 * in at end of memory), but you must use linefeed to
395 * scroll since down arrow won't go past memory end.
396 * I turned this off after recieving Paul Eggert's
397 * Superbee description which wins better.
398 */
399 if (xNL /* && !XB */ && pfast)
400 tputs(xNL, 0, putch);
401 else
402 putch('\n');
403 l--;
404 if (pfast == 0)
405 outcol = 0;
406 }
407 }
408 if (destline < outline && !(CA && !holdcm || UP != NOSTR))
409 destline = outline;
410 if (CA && !holdcm)
411 if (plod(costCM) > 0)
412 plod(0);
413 else
414 tputs(tgoto(CM, destcol, destline), 0, putch);
415 else
416 plod(0);
417 outline = destline;
418 outcol = destcol;
419 }
420
421 /*
422 * Tab to column col by flushing and then setting destcol.
423 * Used by "set all".
424 */
tab(col)425 tab(col)
426 int col;
427 {
428
429 flush1();
430 destcol = col;
431 }
432
433 /*
434 * Move (slowly) to destination.
435 * Hard thing here is using home cursor on really deficient terminals.
436 * Otherwise just use cursor motions, hacking use of tabs and overtabbing
437 * and backspace.
438 */
439
440 static int plodcnt, plodflg;
441
plodput(c)442 plodput(c)
443 {
444
445 if (plodflg)
446 plodcnt--;
447 else
448 putch(c);
449 }
450
plod(cnt)451 plod(cnt)
452 {
453 register int i, j, k;
454 register int soutcol, soutline;
455
456 plodcnt = plodflg = cnt;
457 soutcol = outcol;
458 soutline = outline;
459 /*
460 * Consider homing and moving down/right from there, vs moving
461 * directly with local motions to the right spot.
462 */
463 if (HO) {
464 /*
465 * i is the cost to home and tab/space to the right to
466 * get to the proper column. This assumes ND space costs
467 * 1 char. So i+destcol is cost of motion with home.
468 */
469 if (GT)
470 i = (destcol / value(HARDTABS)) + (destcol % value(HARDTABS));
471 else
472 i = destcol;
473 /*
474 * j is cost to move locally without homing
475 */
476 if (destcol >= outcol) { /* if motion is to the right */
477 j = destcol / value(HARDTABS) - outcol / value(HARDTABS);
478 if (GT && j)
479 j += destcol % value(HARDTABS);
480 else
481 j = destcol - outcol;
482 } else
483 /* leftward motion only works if we can backspace. */
484 if (outcol - destcol <= i && (BS || BC))
485 i = j = outcol - destcol; /* cheaper to backspace */
486 else
487 j = i + 1; /* impossibly expensive */
488
489 /* k is the absolute value of vertical distance */
490 k = outline - destline;
491 if (k < 0)
492 k = -k;
493 j += k;
494
495 /*
496 * Decision. We may not have a choice if no UP.
497 */
498 if (i + destline < j || (!UP && destline < outline)) {
499 /*
500 * Cheaper to home. Do it now and pretend it's a
501 * regular local motion.
502 */
503 tputs(HO, 0, plodput);
504 outcol = outline = 0;
505 } else if (LL) {
506 /*
507 * Quickly consider homing down and moving from there.
508 * Assume cost of LL is 2.
509 */
510 k = (LINES - 1) - destline;
511 if (i + k + 2 < j && (k<=0 || UP)) {
512 tputs(LL, 0, plodput);
513 outcol = 0;
514 outline = LINES - 1;
515 }
516 }
517 } else
518 /*
519 * No home and no up means it's impossible, so we return an
520 * incredibly big number to make cursor motion win out.
521 */
522 if (!UP && destline < outline)
523 return (500);
524 if (GT)
525 i = destcol % value(HARDTABS)
526 + destcol / value(HARDTABS);
527 else
528 i = destcol;
529 /*
530 if (BT && outcol > destcol && (j = (((outcol+7) & ~7) - destcol - 1) >> 3)) {
531 j *= (k = strlen(BT));
532 if ((k += (destcol&7)) > 4)
533 j += 8 - (destcol&7);
534 else
535 j += k;
536 } else
537 */
538 j = outcol - destcol;
539 /*
540 * If we will later need a \n which will turn into a \r\n by
541 * the system or the terminal, then don't bother to try to \r.
542 */
543 if ((NONL || !pfast) && outline < destline)
544 goto dontcr;
545 /*
546 * If the terminal will do a \r\n and there isn't room for it,
547 * then we can't afford a \r.
548 */
549 if (NC && outline >= destline)
550 goto dontcr;
551 /*
552 * If it will be cheaper, or if we can't back up, then send
553 * a return preliminarily.
554 */
555 if (j > i + 1 || outcol > destcol && !BS && !BC) {
556 /*
557 * BUG: this doesn't take the (possibly long) length
558 * of xCR into account.
559 */
560 if (xCR)
561 tputs(xCR, 0, plodput);
562 else
563 plodput('\r');
564 if (NC) {
565 if (xNL)
566 tputs(xNL, 0, plodput);
567 else
568 plodput('\n');
569 outline++;
570 }
571 outcol = 0;
572 }
573 dontcr:
574 /* Move down, if necessary, until we are at the desired line */
575 while (outline < destline) {
576 j = destline - outline;
577 if (j > costDP && DOWN_PARM) {
578 /* Win big on Tek 4025 */
579 tputs(tgoto(DOWN_PARM, 0, j), j, plodput);
580 outline += j;
581 }
582 else {
583 outline++;
584 if (xNL && pfast)
585 tputs(xNL, 0, plodput);
586 else
587 plodput('\n');
588 }
589 if (plodcnt < 0)
590 goto out;
591 if (NONL || pfast == 0)
592 outcol = 0;
593 }
594 if (BT)
595 k = strlen(BT); /* should probably be cost(BT) and moved out */
596 /* Move left, if necessary, to desired column */
597 while (outcol > destcol) {
598 if (plodcnt < 0)
599 goto out;
600 if (BT && !insmode && outcol - destcol > 4+k) {
601 tputs(BT, 0, plodput);
602 outcol--;
603 outcol -= outcol % value(HARDTABS); /* outcol &= ~7; */
604 continue;
605 }
606 j = outcol - destcol;
607 if (j > costLP && LEFT_PARM) {
608 tputs(tgoto(LEFT_PARM, 0, j), j, plodput);
609 outcol -= j;
610 }
611 else {
612 outcol--;
613 if (BC)
614 tputs(BC, 0, plodput);
615 else
616 plodput('\b');
617 }
618 }
619 /* Move up, if necessary, to desired row */
620 while (outline > destline) {
621 j = outline - destline;
622 if (UP_PARM && j > 1) {
623 /* Win big on Tek 4025 */
624 tputs(tgoto(UP_PARM, 0, j), j, plodput);
625 outline -= j;
626 }
627 else {
628 outline--;
629 tputs(UP, 0, plodput);
630 }
631 if (plodcnt < 0)
632 goto out;
633 }
634 /*
635 * Now move to the right, if necessary. We first tab to
636 * as close as we can get.
637 */
638 if (GT && !insmode && destcol - outcol > 1) {
639 /* tab to right as far as possible without passing col */
640 for (;;) {
641 i = tabcol(outcol, value(HARDTABS));
642 if (i > destcol)
643 break;
644 if (TA)
645 tputs(TA, 0, plodput);
646 else
647 plodput('\t');
648 outcol = i;
649 }
650 /* consider another tab and then some backspaces */
651 if (destcol - outcol > 4 && i < COLUMNS && (BC || BS)) {
652 if (TA)
653 tputs(TA, 0, plodput);
654 else
655 plodput('\t');
656 outcol = i;
657 /*
658 * Back up. Don't worry about LEFT_PARM because
659 * it's never more than 4 spaces anyway.
660 */
661 while (outcol > destcol) {
662 outcol--;
663 if (BC)
664 tputs(BC, 0, plodput);
665 else
666 plodput('\b');
667 }
668 }
669 }
670 /*
671 * We've tabbed as much as possible. If we still need to go
672 * further (not exact or can't tab) space over. This is a
673 * very common case when moving to the right with space.
674 */
675 while (outcol < destcol) {
676 j = destcol - outcol;
677 if (j > costRP && RIGHT_PARM) {
678 /*
679 * This probably happens rarely, if at all.
680 * It seems mainly useful for ANSI terminals
681 * with no hardware tabs, and I don't know
682 * of any such terminal at the moment.
683 */
684 tputs(tgoto(RIGHT_PARM, 0, j), j, plodput);
685 outcol += j;
686 }
687 else {
688 /*
689 * move one char to the right. We don't use ND space
690 * because it's better to just print the char we are
691 * moving over. There are various exceptions, however.
692 * If !inopen, vtube contains garbage. If the char is
693 * a null or a tab we want to print a space. Other
694 * random chars we use space for instead, too.
695 */
696 if (!inopen || vtube[outline]==NULL ||
697 (i=vtube[outline][outcol]) < ' ')
698 i = ' ';
699 if(i & QUOTE) /* mjm: no sign extension on 3B */
700 i = ' ';
701 if (insmode && ND)
702 tputs(ND, 0, plodput);
703 else
704 plodput(i);
705 outcol++;
706 }
707 if (plodcnt < 0)
708 goto out;
709 }
710 out:
711 if (plodflg) {
712 outcol = soutcol;
713 outline = soutline;
714 }
715 return(plodcnt);
716 }
717
718 /*
719 * An input line arrived.
720 * Calculate new (approximate) screen line position.
721 * Approximate because kill character echoes newline with
722 * no feedback and also because of long input lines.
723 */
noteinp()724 noteinp()
725 {
726
727 outline++;
728 if (outline > LINES - 1)
729 outline = LINES - 1;
730 destline = outline;
731 destcol = outcol = 0;
732 }
733
734 /*
735 * Something weird just happened and we
736 * lost track of whats happening out there.
737 * Since we cant, in general, read where we are
738 * we just reset to some known state.
739 * On cursor addressible terminals setting to unknown
740 * will force a cursor address soon.
741 */
termreset()742 termreset()
743 {
744
745 endim();
746 if (TI) /* otherwise it flushes anyway, and 'set tty=dumb' vomits */
747 putpad(TI); /*adb change -- emit terminal initial sequence */
748 destcol = 0;
749 destline = LINES - 1;
750 if (CA) {
751 outcol = UKCOL;
752 outline = UKCOL;
753 } else {
754 outcol = destcol;
755 outline = destline;
756 }
757 }
758
759 /*
760 * Low level buffering, with the ability to drain
761 * buffered output without printing it.
762 */
763 char *obp = obuf;
764
draino()765 draino()
766 {
767
768 obp = obuf;
769 }
770
flusho()771 flusho()
772 {
773
774 if (obp != obuf) {
775 #ifndef vms
776 write(1, obuf, obp - obuf);
777 #else
778 vms_write(1, obuf, obp - obuf);
779 #endif
780 obp = obuf;
781 }
782 }
783
putnl()784 putnl()
785 {
786
787 ex_putchar('\n');
788 }
789
ex_putS(cp)790 ex_putS(cp)
791 char *cp;
792 {
793
794 if (cp == NULL)
795 return;
796 while (*cp)
797 putch(*cp++);
798 }
799
800
putch(c)801 putch(c)
802 int c;
803 {
804
805 #ifdef OLD3BTTY /* mjm */
806 if(c == '\n') /* mjm: Fake "\n\r" for '\n' til fix in 3B firmware */
807 putch('\r'); /* mjm: vi does "stty -icanon" => -onlcr !! */
808 #endif
809 *obp++ = c & 0177;
810 if (obp >= &obuf[sizeof obuf])
811 flusho();
812 }
813
814 /*
815 * Miscellaneous routines related to output.
816 */
817
818 /*
819 * Put with padding
820 */
putpad(cp)821 putpad(cp)
822 char *cp;
823 {
824
825 flush();
826 tputs(cp, 0, putch);
827 }
828
829 /*
830 * Set output through normal command mode routine.
831 */
setoutt()832 setoutt()
833 {
834
835 Outchar = termchar;
836 }
837
838 /*
839 * Printf (temporarily) in list mode.
840 */
841 /*VARARGS1*/
lprintf(cp,dp)842 lprintf(cp, dp)
843 char *cp, *dp;
844 {
845 register int (*P)();
846
847 P = setlist(1);
848 ex_printf(cp, dp);
849 Put_char = P;
850 }
851
852 /*
853 * Newline + flush.
854 */
putNFL()855 putNFL()
856 {
857
858 putnl();
859 flush();
860 }
861
862 /*
863 * Try to start -nl mode.
864 */
pstart()865 pstart()
866 {
867
868 if (NONL)
869 return;
870 if (!value(OPTIMIZE))
871 return;
872 if (ruptible == 0 || pfast)
873 return;
874 fgoto();
875 flusho();
876 pfast = 1;
877 normtty++;
878 #ifndef USG3TTY
879 tty.sg_flags = normf & ~(ECHO|XTABS|CRMOD);
880 #else
881 tty = normf;
882 tty.c_oflag &= ~(ONLCR|TAB3);
883 tty.c_lflag &= ~ECHO;
884 #endif
885 ex_sTTY(1);
886 }
887
888 /*
889 * Stop -nl mode.
890 */
pstop()891 pstop()
892 {
893
894 if (inopen)
895 return;
896 phadnl = 0;
897 linp = linb;
898 draino();
899 normal(normf);
900 pfast &= ~1;
901 }
902
903 /*
904 * Prep tty for open mode.
905 */
906 ttymode
ostart()907 ostart()
908 {
909 ttymode f;
910
911 if (!intty)
912 error("Open and visual must be used interactively");
913 ex_gTTY(1);
914 normtty++;
915 #ifndef USG3TTY
916 f = tty.sg_flags;
917 tty.sg_flags = (normf &~ (ECHO|XTABS|CRMOD)) |
918 # ifdef CBREAK
919 CBREAK;
920 # else
921 RAW;
922 # endif
923 # ifdef TIOCGETC
924 ttcharoff();
925 # endif
926 #else
927 f = tty;
928 tty = normf;
929 tty.c_iflag &= ~ICRNL;
930 tty.c_lflag &= ~(ECHO|ICANON);
931 tty.c_oflag &= ~(TAB3|ONLCR);
932 tty.c_cc[VMIN] = 1;
933 tty.c_cc[VTIME] = 1;
934 ttcharoff();
935 #endif
936 ex_sTTY(1);
937 tostart();
938 pfast |= 2;
939 return (f);
940 }
941
942 /* actions associated with putting the terminal in open mode */
tostart()943 tostart()
944 {
945 putpad(VS);
946 putpad(KS);
947 if (!value(MESG)) {
948 if (ttynbuf[0] == 0) {
949 register char *tn;
950 if ((tn=ttyname(2)) == NULL &&
951 (tn=ttyname(1)) == NULL &&
952 (tn=ttyname(0)) == NULL)
953 ttynbuf[0] = 1;
954 else
955 strcpy(ttynbuf, tn);
956 }
957 if (ttynbuf[0] != 1) {
958 struct stat sbuf;
959 stat(ttynbuf, &sbuf);
960 ttymesg = sbuf.st_mode & 0777;
961 chmod(ttynbuf,
962 #ifdef UCBV7
963 /*
964 * This applies to the UCB V7 Pdp-11 system with the
965 * -u write option only.
966 */
967 0611 /* 11 = urgent only allowed */
968 #else
969 0600
970 #endif
971 );
972 }
973 }
974 }
975
976 /*
977 * Turn off start/stop chars if they aren't the default ^S/^Q.
978 * This is so idiots who make esc their start/stop don't lose.
979 * We always turn off quit since datamedias send ^\ for their
980 * right arrow key.
981 */
982 #ifdef TIOCGETC
ttcharoff()983 ttcharoff()
984 {
985 nttyc.t_quitc = '\377';
986 if (nttyc.t_startc != CTRL('q'))
987 nttyc.t_startc = '\377';
988 if (nttyc.t_stopc != CTRL('s'))
989 nttyc.t_stopc = '\377';
990 # ifdef TIOCLGET
991 nlttyc.t_suspc = '\377'; /* ^Z */
992 nlttyc.t_dsuspc = '\377'; /* ^Y */
993 nlttyc.t_flushc = '\377'; /* ^O */
994 nlttyc.t_lnextc = '\377'; /* ^V */
995 # endif
996 }
997 #endif
998
999 #ifdef USG3TTY
ttcharoff()1000 ttcharoff()
1001 {
1002 tty.c_cc[VQUIT] = '\377';
1003 # ifdef VSTART
1004 /*
1005 * The following is sample code if USG ever lets people change
1006 * their start/stop chars. As long as they can't we can't get
1007 * into trouble so we just leave them alone.
1008 */
1009 if (tty.c_cc[VSTART] != CTRL('q'))
1010 tty.c_cc[VSTART] = '\377';
1011 if (tty.c_cc[VSTOP] != CTRL('s'))
1012 tty.c_cc[VSTOP] = '\377';
1013 # endif
1014 }
1015 #endif
1016
1017 /*
1018 * Stop open, restoring tty modes.
1019 */
ostop(f)1020 ostop(f)
1021 ttymode f;
1022 {
1023
1024 #ifndef USG3TTY
1025 pfast = (f & CRMOD) == 0;
1026 #else
1027 pfast = (f.c_oflag & ONLCR) == 0;
1028 #endif
1029 termreset(), fgoto(), flusho();
1030 normal(f);
1031 tostop();
1032 }
1033
1034 /* Actions associated with putting the terminal in the right mode. */
tostop()1035 tostop()
1036 {
1037 putpad(VE);
1038 putpad(KE);
1039 if (!value(MESG) && ttynbuf[0]>1)
1040 chmod(ttynbuf, ttymesg);
1041 }
1042
1043 #ifndef CBREAK
1044 /*
1045 * Into cooked mode for interruptibility.
1046 */
vcook()1047 vcook()
1048 {
1049
1050 tty.sg_flags &= ~RAW;
1051 ex_sTTY(1);
1052 }
1053
1054 /*
1055 * Back into raw mode.
1056 */
vraw()1057 vraw()
1058 {
1059
1060 tty.sg_flags |= RAW;
1061 ex_sTTY(1);
1062 }
1063 #endif
1064
1065 /*
1066 * Restore flags to normal state f.
1067 */
normal(f)1068 normal(f)
1069 ttymode f;
1070 {
1071
1072 if (normtty > 0) {
1073 ignore(setty(f));
1074 normtty--;
1075 }
1076 }
1077
1078 /*
1079 * Straight set of flags to state f.
1080 */
1081 ttymode
setty(f)1082 setty(f)
1083 ttymode f;
1084 {
1085 #ifndef USG3TTY
1086 register int ot = tty.sg_flags;
1087 #else
1088 ttymode ot;
1089 ot = tty;
1090 #endif
1091
1092 #ifndef USG3TTY
1093 # ifdef TIOCGETC
1094 if (f == normf) {
1095 nttyc = ottyc;
1096 # ifdef TIOCLGET
1097 nlttyc = olttyc;
1098 # endif
1099 } else
1100 ttcharoff();
1101 # endif
1102 tty.sg_flags = f;
1103 #else
1104 if (tty.c_lflag & ICANON)
1105 ttcharoff();
1106 tty = f;
1107 #endif
1108 ex_sTTY(1);
1109 return (ot);
1110 }
1111
ex_gTTY(i)1112 ex_gTTY(i)
1113 int i;
1114 {
1115
1116 #ifndef USG3TTY
1117 ignore(ioctl(i, TIOCGETP, &tty));
1118 # ifdef TIOCGETC
1119 ioctl(i, TIOCGETC, (char *) &ottyc);
1120 nttyc = ottyc;
1121 # endif
1122 # ifdef TIOCGLTC
1123 ioctl(i, TIOCGLTC, (char *) &olttyc);
1124 nlttyc = olttyc;
1125 # endif
1126 #else
1127 ioctl(i, TCGETA, (char *) &tty);
1128 #endif
1129 }
1130
1131 /*
1132 * ex_sTTY: set the tty modes on file descriptor i to be what's
1133 * currently in global "tty". (Also use nttyc if needed.)
1134 */
ex_sTTY(i)1135 ex_sTTY(i)
1136 int i;
1137 {
1138
1139 #ifndef USG3TTY
1140 # ifdef USG
1141 /* Bug in USG tty driver, put out a DEL as a patch. */
1142 if (tty.sg_ospeed >= B1200)
1143 write(1, "\377", 1);
1144 # endif
1145
1146 # ifdef TIOCSETN
1147 /* Don't flush typeahead if we don't have to */
1148 ioctl(i, TIOCSETN, (char *) &tty);
1149 # else
1150 /* We have to. Too bad. */
1151 stty(i, &tty);
1152 # endif
1153
1154 # ifdef TIOCGETC
1155 /* Update the other random chars while we're at it. */
1156 ioctl(i, TIOCSETC, (char *) &nttyc);
1157 # endif
1158 # ifdef TIOCSLTC
1159 ioctl(i, TIOCSLTC, (char *) &nlttyc);
1160 # endif
1161
1162 #else
1163 /* USG 3 very simple: just set everything */
1164 ioctl(i, TCSETAW, (char *) &tty);
1165 #endif
1166 }
1167
1168 /*
1169 * Print newline, or blank if in open/visual
1170 */
noonl()1171 noonl()
1172 {
1173
1174 ex_putchar(Outchar != termchar ? ' ' : '\n');
1175 }
1176