* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
static char *sccsid
= "@(#)ex_put.c 7.10 (Berkeley) %G%";
* Terminal driving and line formatting routines.
* Basic motion optimizations are done here as well
* as formatting of lines (printing of control characters,
* line numbering and the like).
* The routines outchar, putchar and pline are actually
* variables, and these variables point at the current definitions
* of the routines. See the routine setflav.
* We sometimes make outchar be routines which catch the characters
* to be printed, e.g. if we want to see how long a line is.
* During open/visual, outchar and putchar will be set to
* routines in the file ex_vput.c (vputchar, vinschar, etc.).
int (*Outchar
)() = termchar
;
int (*Put_char
)() = normchar
;
int (*Pline
)() = normline
;
Put_char
= t
? listchar
: normchar
;
Pline
= t
? numbline
: normline
;
* Format c for list mode; leave things in common
* with normal print mode to be done by normchar.
if (c
< ' ' && c
!= '\n' || c
== DELETE
)
outchar('^'), c
= ctlof(c
);
* Format c for printing. Handle funnies of upper case terminals
* and crocky hazeltines which don't have ~.
else if (c
< ' ' && (c
!= '\b' || !OS
) && c
!= '\n' && c
!= '\t' || c
== DELETE
)
ex_putchar('^'), c
= ctlof(c
);
* Print a line with a number.
* Normal line output, no numbering.
/* pdp-11 doprnt is not reentrant so can't use "printf" here
in case we are tracing */
ex_putchar('\n' | QUOTE
);
* Given c at the beginning of a line, determine whether
* the printing of the line will erase or otherwise obliterate
* the prompt which was printed before. If it won't, do it now.
if (Put_char
== listchar
)
* The output buffer is initialized with a useful error
* message so we don't have to keep it in data space.
* Phadnl records when we have already had a complete line ending with \n.
* If another line starts without a flush, and the terminal suggests it,
* we switch into -nl mode so that we can send lineffeeds to avoid
* Indirect to current definition of putchar.
* Termchar routine for command mode.
* Watch for possible switching to -nl mode.
* Otherwise flush into next level of buffering when
* small buffer fills or at a newline.
if (pfast
== 0 && phadnl
)
else if (linp
>= &linb
[63])
* Flush from small line buffer into output buffer.
* Work here is destroying motion into positions, and then
* letting fgoto do the optimized motion.
destline
+= destcol
/ COLUMNS
;
destcol
+= value(TABSTOP
) - destcol
% value(TABSTOP
);
destline
+= destcol
/ COLUMNS
+ 1;
if (destcol
!= 0 && destcol
% COLUMNS
== 0)
if (AM
== 0 && outcol
== COLUMNS
)
} else if (c
>= ' ' && c
!= DELETE
) {
if (XN
&& outcol
% COLUMNS
== 0)
putch('\r'), putch('\n');
* Sync the position of the output cursor.
* Most work here is rounding for terminal boundaries getting the
* column position implied by wraparound or the lack thereof and
* rolling up the screen to get destline on the screen.
if (destcol
> COLUMNS
- 1) {
destline
+= destcol
/ COLUMNS
;
if (outcol
> COLUMNS
- 1) {
l
= (outcol
+ 1) / COLUMNS
;
if (outline
> LINES
- 1) {
destline
-= outline
- (LINES
- 1);
if (destline
> LINES
- 1) {
if (outline
< LINES
- 1) {
if (pfast
== 0 && (!CA
|| holdcm
))
* The following linefeed (or simulation thereof)
* is supposed to scroll up the screen, since we
* are on the bottom line. We make the assumption
* that linefeed will scroll. If ns is in the
* capability list this won't work. We should
* probably have an sc capability but sf will
* generally take the place if it works.
* Superbee glitch: in the middle of the screen we
* have to use esc B (down) because linefeed screws up
* in "Efficient Paging" (what a joke) mode (which is
* essential in some SB's because CRLF mode puts garbage
* in at end of memory), but you must use linefeed to
* scroll since down arrow won't go past memory end.
* I turned this off after recieving Paul Eggert's
* Superbee description which wins better.
if (xNL
/* && !XB */ && pfast
)
if (destline
< outline
&& !(CA
&& !holdcm
|| UP
!= NOSTR
))
tputs(tgoto(CM
, destcol
, destline
), 0, putch
);
* Tab to column col by flushing and then setting destcol.
* Move (slowly) to destination.
* Hard thing here is using home cursor on really deficient terminals.
* Otherwise just use cursor motions, hacking use of tabs and overtabbing
static int plodcnt
, plodflg
;
register int soutcol
, soutline
;
* Consider homing and moving down/right from there, vs moving
* directly with local motions to the right spot.
* i is the cost to home and tab/space to the right to
* get to the proper column. This assumes ND space costs
* 1 char. So i+destcol is cost of motion with home.
i
= (destcol
/ value(HARDTABS
)) + (destcol
% value(HARDTABS
));
* j is cost to move locally without homing
if (destcol
>= outcol
) { /* if motion is to the right */
j
= destcol
/ value(HARDTABS
) - outcol
/ value(HARDTABS
);
j
+= destcol
% value(HARDTABS
);
/* leftward motion only works if we can backspace. */
if (outcol
- destcol
<= i
&& (BS
|| BC
))
i
= j
= outcol
- destcol
; /* cheaper to backspace */
j
= i
+ 1; /* impossibly expensive */
/* k is the absolute value of vertical distance */
* Decision. We may not have a choice if no UP.
if (i
+ destline
< j
|| (!UP
&& destline
< outline
)) {
* Cheaper to home. Do it now and pretend it's a
* Quickly consider homing down and moving from there.
* Assume cost of LL is 2.
k
= (LINES
- 1) - destline
;
if (i
+ k
+ 2 < j
&& (k
<=0 || UP
)) {
* No home and no up means it's impossible, so we return an
* incredibly big number to make cursor motion win out.
if (!UP
&& destline
< outline
)
i
= destcol
% value(HARDTABS
)
+ destcol
/ value(HARDTABS
);
if (BT && outcol > destcol && (j = (((outcol+7) & ~7) - destcol - 1) >> 3)) {
if ((k += (destcol&7)) > 4)
* If we will later need a \n which will turn into a \r\n by
* the system or the terminal, then don't bother to try to \r.
if ((NONL
|| !pfast
) && outline
< destline
)
* If the terminal will do a \r\n and there isn't room for it,
* then we can't afford a \r.
if (NC
&& outline
>= destline
)
* If it will be cheaper, or if we can't back up, then send
* a return preliminarily.
if (j
> i
+ 1 || outcol
> destcol
&& !BS
&& !BC
) {
* BUG: this doesn't take the (possibly long) length
/* Move down, if necessary, until we are at the desired line */
while (outline
< destline
) {
if (j
> costDP
&& DOWN_PARM
) {
/* Win big on Tek 4025 */
tputs(tgoto(DOWN_PARM
, 0, j
), j
, plodput
);
k
= strlen(BT
); /* should probably be cost(BT) and moved out */
/* Move left, if necessary, to desired column */
while (outcol
> destcol
) {
if (BT
&& !insmode
&& outcol
- destcol
> 4+k
) {
outcol
-= outcol
% value(HARDTABS
); /* outcol &= ~7; */
if (j
> costLP
&& LEFT_PARM
) {
tputs(tgoto(LEFT_PARM
, 0, j
), j
, plodput
);
/* Move up, if necessary, to desired row */
while (outline
> destline
) {
/* Win big on Tek 4025 */
tputs(tgoto(UP_PARM
, 0, j
), j
, plodput
);
* Now move to the right, if necessary. We first tab to
* as close as we can get.
if (GT
&& !insmode
&& destcol
- outcol
> 1) {
/* tab to right as far as possible without passing col */
i
= tabcol(outcol
, value(HARDTABS
));
/* consider another tab and then some backspaces */
if (destcol
- outcol
> 4 && i
< COLUMNS
&& (BC
|| BS
)) {
* Back up. Don't worry about LEFT_PARM because
* it's never more than 4 spaces anyway.
while (outcol
> destcol
) {
* We've tabbed as much as possible. If we still need to go
* further (not exact or can't tab) space over. This is a
* very common case when moving to the right with space.
while (outcol
< destcol
) {
if (j
> costRP
&& RIGHT_PARM
) {
* This probably happens rarely, if at all.
* It seems mainly useful for ANSI terminals
* with no hardware tabs, and I don't know
* of any such terminal at the moment.
tputs(tgoto(RIGHT_PARM
, 0, j
), j
, plodput
);
* move one char to the right. We don't use ND space
* because it's better to just print the char we are
* moving over. There are various exceptions, however.
* If !inopen, vtube contains garbage. If the char is
* a null or a tab we want to print a space. Other
* random chars we use space for instead, too.
if (!inopen
|| vtube
[outline
]==NULL
||
(i
=vtube
[outline
][outcol
]) < ' ')
if(i
& QUOTE
) /* mjm: no sign extension on 3B */
* Calculate new (approximate) screen line position.
* Approximate because kill character echoes newline with
* no feedback and also because of long input lines.
* Something weird just happened and we
* lost track of whats happening out there.
* Since we cant, in general, read where we are
* we just reset to some known state.
* On cursor addressible terminals setting to unknown
* will force a cursor address soon.
if (TI
) /* otherwise it flushes anyway, and 'set tty=dumb' vomits */
putpad(TI
); /*adb change -- emit terminal initial sequence */
* Low level buffering, with the ability to drain
* buffered output without printing it.
write(1, obuf
, obp
- obuf
);
vms_write(1, obuf
, obp
- obuf
);
#ifdef OLD3BTTY /* mjm */
if(c
== '\n') /* mjm: Fake "\n\r" for '\n' til fix in 3B firmware */
putch('\r'); /* mjm: vi does "stty -icanon" => -onlcr !! */
if (obp
>= &obuf
[sizeof obuf
])
* Miscellaneous routines related to output.
* Set output through normal command mode routine.
* Printf (temporarily) in list mode.
if (ruptible
== 0 || pfast
)
tty
.sg_flags
= normf
& ~(ECHO
|XTABS
|CRMOD
);
tty
.c_oflag
&= ~(ONLCR
|TAB3
);
* Prep tty for open mode.
error("Open and visual must be used interactively");
tty
.sg_flags
= (normf
&~ (ECHO
|XTABS
|CRMOD
)) |
tty
.c_lflag
&= ~(ECHO
|ICANON
);
tty
.c_oflag
&= ~(TAB3
|ONLCR
);
/* actions associated with putting the terminal in open mode */
if ((tn
=ttyname(2)) == NULL
&&
(tn
=ttyname(1)) == NULL
&&
ttymesg
= sbuf
.st_mode
& 0777;
* This applies to the UCB V7 Pdp-11 system with the
0611 /* 11 = urgent only allowed */
* Turn off start/stop chars if they aren't the default ^S/^Q.
* This is so idiots who make esc their start/stop don't lose.
* We always turn off quit since datamedias send ^\ for their
if (nttyc
.t_startc
!= CTRL(q
))
if (nttyc
.t_stopc
!= CTRL(s
))
nlttyc
.t_suspc
= '\377'; /* ^Z */
nlttyc
.t_dsuspc
= '\377'; /* ^Y */
nlttyc
.t_flushc
= '\377'; /* ^O */
nlttyc
.t_lnextc
= '\377'; /* ^V */
tty
.c_cc
[VQUIT
] = '\377';
* The following is sample code if USG ever lets people change
* their start/stop chars. As long as they can't we can't get
* into trouble so we just leave them alone.
if (tty
.c_cc
[VSTART
] != CTRL(q
))
tty
.c_cc
[VSTART
] = '\377';
if (tty
.c_cc
[VSTOP
] != CTRL(s
))
tty
.c_cc
[VSTOP
] = '\377';
* Stop open, restoring tty modes.
pfast
= (f
& CRMOD
) == 0;
pfast
= (f
.c_oflag
& ONLCR
) == 0;
termreset(), fgoto(), flusho();
/* Actions associated with putting the terminal in the right mode. */
if (!value(MESG
) && ttynbuf
[0]>1)
* Into cooked mode for interruptibility.
* Restore flags to normal state f.
* Straight set of flags to state f.
register int ot
= tty
.sg_flags
;
if (tty
.c_lflag
& ICANON
)
ioctl(i
, TIOCGETC
, (char *) &ottyc
);
ioctl(i
, TIOCGLTC
, (char *) &olttyc
);
ioctl(i
, TCGETA
, (char *) &tty
);
* ex_sTTY: set the tty modes on file descriptor i to be what's
* currently in global "tty". (Also use nttyc if needed.)
/* Bug in USG tty driver, put out a DEL as a patch. */
if (tty
.sg_ospeed
>= B1200
)
/* Don't flush typeahead if we don't have to */
ioctl(i
, TIOCSETN
, (char *) &tty
);
/* We have to. Too bad. */
/* Update the other random chars while we're at it. */
ioctl(i
, TIOCSETC
, (char *) &nttyc
);
ioctl(i
, TIOCSLTC
, (char *) &nlttyc
);
/* USG 3 very simple: just set everything */
ioctl(i
, TCSETAW
, (char *) &tty
);
* Print newline, or blank if in open/visual
ex_putchar(Outchar
!= termchar
? ' ' : '\n');