Commit 6548cf00 authored by Karoly Lorentey's avatar Karoly Lorentey
Browse files

Full support for multiple terminal I/O (with some rough edges).

lib-src/emacsclient.c (emacs_pid): New variable.  
(window_change): Forward the SIGWINCH signal to the Emacs process
after copying the size parameters to the proxy terminal.
(copy_from_to): New parameter (sigio), kill Emacs with SIGIO if it is
nonzero.
(main): Set emacs_pid.

lisp/server.el (server-process-filter): Send the pid of Emacs to emacsclient.

src/cm.c: Added tty parameters to all functions and all Wcm macro calls.

src/cm.h: Added tty parameters to all macros.   Updated function prototypes.
(Wcm): Moved to struct tty_output.

src/dispextern.h: Updated function prototypes.

src/dispnew.c: Added tty parameters to all Wcm macro calls.
(do_switch_frame): Make old frame obscured, not invisible, to solve
problems with other-frame.
(Wcm): Moved to struct tty_output.

src/keyboard.c (read_avail_input): Select the frame corresponding to
the tty that was read.  Slight rearrangement of tty loop.

src/lisp.h (tabs_safe_p): Removed duplicate prototype.

src/sysdep.c (hft_init, hft_reset): Added tty_output parameter.
(discard_tty_input): Discard input from all ttys on APOLLO, too.
Whatever it is.
(narrow_foreground_group, widen_foreground_group): Added tty parameter
(not really useful, the functions only work on the controlling tty.)
(tabs_safe_p): Added tty parameter.

src/term.c Added tty parameters to all Wcm macro calls.
Standardised updating_frame vs. selected frame and tty_output access.
(term_init): Allocate Wcm.
(syms_of_term): Provide the `multi-tty' feature.

src/termchar.h (struct tty_output): Added Wcm.

src/xdisp.c (try_window_id): Make sure we use the tty device
corresponding to the current frame.

git-archimport-id: lorentey@elte.hu--2004/emacs--multi-tty--0--patch-8
parent ce9d5d59
......@@ -13,7 +13,7 @@ I'm Károly Lőrentey. My address: lorentey@elte.hu.
Patches or suggestions are welcome!
Retrieving the branch:
Retrieving the latest version of the branch:
tla register-archive lorentey@elte.hu--2004 http://lorentey.web.elte.hu/arch/2004/
tla get lorentey@elte.hu--2004/emacs--multi-tty--0 <directory>
......@@ -24,21 +24,24 @@ Retrieving the branch:
STATUS
------
We can create frames on new tty devices, but there are problems with
redisplay. Input is read from all terminals (NOT via MULTIKBOARD!).
At the moment, the type of the new terminals must be the same as the
initial terminal. Emacsclient is extended to support opening a new
terminal frame.
Basic support is there; there are some rough edges, but it already
seems to be usable. Input is read from all terminals (NOT via
MULTIKBOARD!). At the moment, the type of the new terminals must be
the same as the initial terminal. Emacsclient was extended to support
opening a new terminal frame.
To try it out, start up the emacs server (M-x server-start), and then
start emacsclient with
(from a shell prompt on another terminal) start emacsclient with
emacsclient -h
If you exit emacs, both terminals are restored to their previous
You'll have two fully working frames on separate terminals. If you
exit emacs, both terminals should be restored to their previous
states.
X, Mac, Windows and DOS support is broken.
X, Mac, Windows and DOS support is broken at the moment.
Tested under GNU/Linux only.
NEWS
----
......@@ -47,7 +50,19 @@ For the NEWS file:
** Support for multiple terminal devices has been added. You can
specify a terminal device (`tty' parameter) and a terminal type
(`tty-type' parameter) to `make-terminal-frame'.
(`tty-type' parameter) to `make-terminal-frame'. `tty' must be a
terminal device created by the new emacsclient, or there will be
problems with terminal input and window resizes. (The kernel
notifies processes about pending input or terminal resizes only on
the controlling terminal, so we need emacsclient to sit on the real
terminal device, create SIGIO signals upon terminal input, and
forward SIGWINCH signals to us.)
You can test for the presence of multiple terminal support by
testing for the `multi-tty' feature.
** A make-frame-on-tty function has been added to make it easier to
create frames on new terminals.
** Emacsclient has been extended to support opening a new terminal
frame.
......@@ -58,8 +73,10 @@ CHANGELOG
See arch logs.
THINGS THAT ARE DONE
--------------------
DIARY OF CHANGES
----------------
(ex-TODO items with explanations.)
-- Introduce a new abstraction for terminal devices.
......@@ -80,12 +97,13 @@ THINGS THAT ARE DONE
-- Implement support for reading from multiple terminals.
(Done, read_avail_input tries to read from each terminal, until one
succeeds.)
succeeds. MULTIKBOARD is not used. Secondary terminals don't send
SIGIO!)
-- other-frame should cycle through the frames on the `current'
terminal.
terminal only.
(Done. A little fragile, but seems to work.)
(Done, by trivially modifiying next_frame and prev_frame.)
-- Support different terminal sizes.
......@@ -94,7 +112,8 @@ THINGS THAT ARE DONE
-- Make sure terminal resizes are handled gracefully. (Could be
problematic.)
(Done. We don't get SIGWINCH for additional ttys, though.)
(Done. We don't get automatic SIGWINCH for additional ttys,
though.)
-- Extend emacsclient to automatically open a new tty when it connects
to Emacs.
......@@ -106,46 +125,71 @@ THINGS THAT ARE DONE
(Done, but introduced ugly redisplay problems. Ugh.)
-- Fix redisplay problems.
(Done, it turned out that the entire Wcm structure must be moved
inside tty_output. Why was it so hard for me to find this out?)
-- Provide a way for emacsclient to tell Emacs that the tty has been
resized.
(Done, simply forward the SIGWINCH signal.)
-- Each keypress should automatically select the frame corresponding
to the terminal that it was coming from. This means that Emacs
must know from which terminal the last keyboard event came from.
(Multikeyboard support may help with this.)
(Done, it was quite simple.)
-- Fix SIGIO issue with secondary terminals.
(Done, emacsclient signals Emacs after writing to the proxy pseudo
terminal. This means that multi-tty does not work with raw ttys!)
THINGS TO DO
------------
** Fix redisplay problems.
** Implement sane error handling after initialization. (Currently
emacs exits if you specify a bad terminal type.) The helpful error
messages must still be provided when Emacs starts.
** C-g should work on secondary terminals.
** Make make-terminal-frame look up the tty and tty-type parameters
from the currently selected terminal before the global default.
** Move optimalization parameters (costs) from union output_data to
struct frame.
a backend-neutral per-device structure.
** Provide a way for emacsclient to tell Emacs that the tty has been
resized.
** Implement terminal deletion, i.e., deleting local frames, closing
the tty device and restoring its previous state without exiting
Emacs. This should be exported to the Lisp environment.
** Implement terminal deletion, i.e., closing the tty device and
restoring its previous state without exiting Emacs. This should be
exported to the Lisp interpreter.
** Implement automatic deletion of terminals, when the last frame on
** Implement automatic deletion of terminals when the last frame on
that terminal is closed.
** Put all cached terminal escape sequences into struct tty_output.
Currently, they are still stored in global variables, so we don't
really support multiple terminal types.
** Each keypress should automatically select the frame corresponding
to the terminal that it was coming from. This means that Emacs
must know from which terminal the last keyboard event came from.
(Multikeyboard support may help with this.)
** Make struct tty_output available from Lisp.
** Make parts of struct tty_output accessible from Lisp. The device
name and the type is sufficient.
** Implement support for starting an interactive Emacs session without
an initial frame. (The user would connect to it and open frames
later, with emacsclient.) Not necessary a good idea.
** Support raw secondary terminals. (This one is tricky, SIGIO works
only on the controlling terminal.)
** What does interrupt_input do? I tried to disable it for raw
secondary tty support, but it seems not to do anything useful.
** Fix X support.
** Do tty output through term_hooks, too.
** Allow simultaneous X and tty frames.
** Fix Mac support (I can't do this myself).
......
......@@ -380,6 +380,7 @@ int tty_erase_char;
int flow_control = 0;
int meta_key = 0;
char _sobuf[BUFSIZ];
int emacs_pid;
/* Adapted from init_sys_modes() in sysdep.c. */
int
......@@ -548,7 +549,7 @@ init_tty ()
void
window_change ()
{
int width, height;
int width = 0, height = 0;
#ifdef TIOCGWINSZ
{
......@@ -601,6 +602,9 @@ window_change ()
}
#endif /* not SunOS-style */
#endif /* not BSD-style */
if (width != 0 && height != 0)
kill (emacs_pid, SIGWINCH);
}
int in_conversation = 0;
......@@ -696,7 +700,7 @@ init_pty ()
}
int
copy_from_to (int in, int out)
copy_from_to (int in, int out, int sigio)
{
static char buf[BUFSIZ];
int nread = read (in, &buf, BUFSIZ);
......@@ -716,6 +720,11 @@ copy_from_to (int in, int out)
if (r < 0)
return 0; /* Error */
if (sigio)
{
kill (emacs_pid, SIGIO);
}
}
return 1;
}
......@@ -744,13 +753,13 @@ pty_conversation ()
if (FD_ISSET (master, &set))
{
/* Copy Emacs output to stdout. */
if (! copy_from_to (master, 0))
if (! copy_from_to (master, 0, 0))
return 1;
}
if (FD_ISSET (1, &set))
{
/* Forward user input to Emacs. */
if (! copy_from_to (1, master))
if (! copy_from_to (1, master, 1))
return 1;
}
}
......@@ -1078,6 +1087,18 @@ To start the server in Emacs, type \"M-x server-start\".\n",
if (here)
{
/* First of all, get the pid of the Emacs process.
XXX Is there is some nifty libc/kernel feature for doing this?
*/
str = fgets (string, BUFSIZ, in);
emacs_pid = atoi (str);
if (emacs_pid == 0)
{
reset_tty ();
fprintf (stderr, "%s: Could not get process id of Emacs\n", argv[0]);
fail (argc, argv);
}
if (! pty_conversation ())
{
reset_tty ();
......
......@@ -319,13 +319,15 @@ PROC is the server process. Format of STRING is \"PATH PATH PATH... \\n\"."
(server-select-display display)
(error (process-send-string proc (nth 1 err))
(setq request "")))))
;; Open a new tty at the client.
;; Open a new frame at the client. ARG is the name of the pseudo tty.
((and (equal "-pty" arg) (string-match "\\([^ ]*\\) \\([^ ]*\\) " request))
(let ((pty (server-unquote-arg (match-string 1 request)))
(type (server-unquote-arg (match-string 2 request))))
(setq request (substring request (match-end 0)))
(condition-case err
(progn
(make-terminal-frame `((tty . ,pty) (tty-type . ,type)))
(process-send-string proc (concat (number-to-string (emacs-pid)) "\n")))
(error (process-send-string proc (nth 1 err))
(setq request "")))))
;; ARG is a line number option.
......
......@@ -137,9 +137,9 @@ void
cmcheckmagic (tty)
struct tty_output *tty;
{
if (curX == FrameCols)
if (curX (tty) == FrameCols (tty))
{
if (!MagicWrap || curY >= FrameRows - 1)
if (!MagicWrap (tty) || curY (tty) >= FrameRows (tty) - 1)
abort ();
if (TTY_TERMSCRIPT (tty))
putc ('\r', TTY_TERMSCRIPT (tty));
......@@ -147,8 +147,8 @@ cmcheckmagic (tty)
if (TTY_TERMSCRIPT (tty))
putc ('\n', TTY_TERMSCRIPT (tty));
putc ('\n', TTY_OUTPUT (tty));
curX = 0;
curY++;
curX (tty) = 0;
curY (tty)++;
}
}
......@@ -160,21 +160,21 @@ cmcheckmagic (tty)
*/
void
cmcostinit ()
cmcostinit (struct tty_output *tty)
{
char *p;
#define COST(x,e) (x ? (cost = 0, tputs (x, 1, e), cost) : BIG)
#define CMCOST(x,e) ((x == 0) ? BIG : (p = tgoto(x, 0, 0), COST(p ,e)))
Wcm.cc_up = COST (Wcm.cm_up, evalcost);
Wcm.cc_down = COST (Wcm.cm_down, evalcost);
Wcm.cc_left = COST (Wcm.cm_left, evalcost);
Wcm.cc_right = COST (Wcm.cm_right, evalcost);
Wcm.cc_home = COST (Wcm.cm_home, evalcost);
Wcm.cc_cr = COST (Wcm.cm_cr, evalcost);
Wcm.cc_ll = COST (Wcm.cm_ll, evalcost);
Wcm.cc_tab = Wcm.cm_tabwidth ? COST (Wcm.cm_tab, evalcost) : BIG;
tty->Wcm->cc_up = COST (tty->Wcm->cm_up, evalcost);
tty->Wcm->cc_down = COST (tty->Wcm->cm_down, evalcost);
tty->Wcm->cc_left = COST (tty->Wcm->cm_left, evalcost);
tty->Wcm->cc_right = COST (tty->Wcm->cm_right, evalcost);
tty->Wcm->cc_home = COST (tty->Wcm->cm_home, evalcost);
tty->Wcm->cc_cr = COST (tty->Wcm->cm_cr, evalcost);
tty->Wcm->cc_ll = COST (tty->Wcm->cm_ll, evalcost);
tty->Wcm->cc_tab = tty->Wcm->cm_tabwidth ? COST (tty->Wcm->cm_tab, evalcost) : BIG;
/*
* These last three are actually minimum costs. When (if) they are
......@@ -185,9 +185,9 @@ cmcostinit ()
* cursor motion seem to take straight numeric values. --ACT)
*/
Wcm.cc_abs = CMCOST (Wcm.cm_abs, evalcost);
Wcm.cc_habs = CMCOST (Wcm.cm_habs, evalcost);
Wcm.cc_vabs = CMCOST (Wcm.cm_vabs, evalcost);
tty->Wcm->cc_abs = CMCOST (tty->Wcm->cm_abs, evalcost);
tty->Wcm->cc_habs = CMCOST (tty->Wcm->cm_habs, evalcost);
tty->Wcm->cc_vabs = CMCOST (tty->Wcm->cm_vabs, evalcost);
#undef CMCOST
#undef COST
......@@ -217,16 +217,16 @@ calccost (struct tty_output *tty, int srcy, int srcx, int dsty, int dstx, int do
don't believe the cursor position: give up here
and force use of absolute positioning. */
if (curX == Wcm.cm_cols)
if (curX (tty) == tty->Wcm->cm_cols)
goto fail;
totalcost = 0;
if ((deltay = dsty - srcy) == 0)
goto x;
if (deltay < 0)
p = Wcm.cm_up, c = Wcm.cc_up, deltay = -deltay;
p = tty->Wcm->cm_up, c = tty->Wcm->cc_up, deltay = -deltay;
else
p = Wcm.cm_down, c = Wcm.cc_down;
p = tty->Wcm->cm_down, c = tty->Wcm->cc_down;
if (c == BIG) { /* caint get thar from here */
if (doit)
printf ("OOPS");
......@@ -240,11 +240,11 @@ calccost (struct tty_output *tty, int srcy, int srcx, int dsty, int dstx, int do
if ((deltax = dstx - srcx) == 0)
goto done;
if (deltax < 0) {
p = Wcm.cm_left, c = Wcm.cc_left, deltax = -deltax;
p = tty->Wcm->cm_left, c = tty->Wcm->cc_left, deltax = -deltax;
goto dodelta; /* skip all the tab junk */
}
/* Tabs (the toughie) */
if (Wcm.cc_tab >= BIG || !Wcm.cm_usetabs)
if (tty->Wcm->cc_tab >= BIG || !tty->Wcm->cm_usetabs)
goto olddelta; /* forget it! */
/*
......@@ -255,12 +255,12 @@ calccost (struct tty_output *tty, int srcy, int srcx, int dsty, int dstx, int do
* we will put into tabx (for ntabs) and tab2x (for n2tabs)).
*/
ntabs = (deltax + srcx % Wcm.cm_tabwidth) / Wcm.cm_tabwidth;
ntabs = (deltax + srcx % tty->Wcm->cm_tabwidth) / tty->Wcm->cm_tabwidth;
n2tabs = ntabs + 1;
tabx = (srcx / Wcm.cm_tabwidth + ntabs) * Wcm.cm_tabwidth;
tab2x = tabx + Wcm.cm_tabwidth;
tabx = (srcx / tty->Wcm->cm_tabwidth + ntabs) * tty->Wcm->cm_tabwidth;
tab2x = tabx + tty->Wcm->cm_tabwidth;
if (tab2x >= Wcm.cm_cols) /* too far (past edge) */
if (tab2x >= tty->Wcm->cm_cols) /* too far (past edge) */
n2tabs = 0;
/*
......@@ -269,11 +269,11 @@ calccost (struct tty_output *tty, int srcy, int srcx, int dsty, int dstx, int do
*/
/* cost for ntabs + cost for right motion */
tabcost = ntabs ? ntabs * Wcm.cc_tab + (dstx - tabx) * Wcm.cc_right
tabcost = ntabs ? ntabs * tty->Wcm->cc_tab + (dstx - tabx) * tty->Wcm->cc_right
: BIG;
/* cost for n2tabs + cost for left motion */
c = n2tabs ? n2tabs * Wcm.cc_tab + (tab2x - dstx) * Wcm.cc_left
c = n2tabs ? n2tabs * tty->Wcm->cc_tab + (tab2x - dstx) * tty->Wcm->cc_left
: BIG;
if (c < tabcost) /* then cheaper to overshoot & back up */
......@@ -286,11 +286,11 @@ calccost (struct tty_output *tty, int srcy, int srcx, int dsty, int dstx, int do
* See if tabcost is less than just moving right
*/
if (tabcost < (deltax * Wcm.cc_right)) {
if (tabcost < (deltax * tty->Wcm->cc_right)) {
totalcost += tabcost; /* use the tabs */
if (doit)
while (--ntabs >= 0)
emacs_tputs (tty, Wcm.cm_tab, 1, cmputc);
emacs_tputs (tty, tty->Wcm->cm_tab, 1, cmputc);
srcx = tabx;
}
......@@ -303,9 +303,9 @@ calccost (struct tty_output *tty, int srcy, int srcx, int dsty, int dstx, int do
goto done;
olddelta:
if (deltax > 0)
p = Wcm.cm_right, c = Wcm.cc_right;
p = tty->Wcm->cm_right, c = tty->Wcm->cc_right;
else
p = Wcm.cm_left, c = Wcm.cc_left, deltax = -deltax;
p = tty->Wcm->cm_left, c = tty->Wcm->cc_left, deltax = -deltax;
dodelta:
if (c == BIG) { /* caint get thar from here */
......@@ -349,47 +349,47 @@ cmgoto (tty, row, col)
*dcm;
/* First the degenerate case */
if (row == curY && col == curX) /* already there */
if (row == curY (tty) && col == curX (tty)) /* already there */
return;
if (curY >= 0 && curX >= 0)
if (curY (tty) >= 0 && curX (tty) >= 0)
{
/* We may have quick ways to go to the upper-left, bottom-left,
* start-of-line, or start-of-next-line. Or it might be best to
* start where we are. Examine the options, and pick the cheapest.
*/
relcost = calccost (tty, curY, curX, row, col, 0);
relcost = calccost (tty, curY (tty), curX (tty), row, col, 0);
use = USEREL;
if ((homecost = Wcm.cc_home) < BIG)
if ((homecost = tty->Wcm->cc_home) < BIG)
homecost += calccost (tty, 0, 0, row, col, 0);
if (homecost < relcost)
relcost = homecost, use = USEHOME;
if ((llcost = Wcm.cc_ll) < BIG)
llcost += calccost (tty, Wcm.cm_rows - 1, 0, row, col, 0);
if ((llcost = tty->Wcm->cc_ll) < BIG)
llcost += calccost (tty, tty->Wcm->cm_rows - 1, 0, row, col, 0);
if (llcost < relcost)
relcost = llcost, use = USELL;
if ((crcost = Wcm.cc_cr) < BIG) {
if (Wcm.cm_autolf)
if (curY + 1 >= Wcm.cm_rows)
if ((crcost = tty->Wcm->cc_cr) < BIG) {
if (tty->Wcm->cm_autolf)
if (curY (tty) + 1 >= tty->Wcm->cm_rows)
crcost = BIG;
else
crcost += calccost (tty, curY + 1, 0, row, col, 0);
crcost += calccost (tty, curY (tty) + 1, 0, row, col, 0);
else
crcost += calccost (tty, curY, 0, row, col, 0);
crcost += calccost (tty, curY (tty), 0, row, col, 0);
}
if (crcost < relcost)
relcost = crcost, use = USECR;
directcost = Wcm.cc_abs, dcm = Wcm.cm_abs;
if (row == curY && Wcm.cc_habs < BIG)
directcost = Wcm.cc_habs, dcm = Wcm.cm_habs;
else if (col == curX && Wcm.cc_vabs < BIG)
directcost = Wcm.cc_vabs, dcm = Wcm.cm_vabs;
directcost = tty->Wcm->cc_abs, dcm = tty->Wcm->cm_abs;
if (row == curY (tty) && tty->Wcm->cc_habs < BIG)
directcost = tty->Wcm->cc_habs, dcm = tty->Wcm->cm_habs;
else if (col == curX (tty) && tty->Wcm->cc_vabs < BIG)
directcost = tty->Wcm->cc_vabs, dcm = tty->Wcm->cm_vabs;
}
else
{
directcost = 0, relcost = 100000;
dcm = Wcm.cm_abs;
dcm = tty->Wcm->cm_abs;
}
/*
......@@ -400,13 +400,14 @@ cmgoto (tty, row, col)
{
/* compute REAL direct cost */
cost = 0;
p = dcm == Wcm.cm_habs ? tgoto (dcm, row, col) :
tgoto (dcm, col, row);
p = dcm == tty->Wcm->cm_habs
? tgoto (dcm, row, col)
: tgoto (dcm, col, row);
emacs_tputs (tty, p, 1, evalcost);
if (cost <= relcost)
{ /* really is cheaper */
emacs_tputs (tty, p, 1, cmputc);
curY = row, curX = col;
curY (tty) = row, curX (tty) = col;
return;
}
}
......@@ -414,25 +415,25 @@ cmgoto (tty, row, col)
switch (use)
{
case USEHOME:
emacs_tputs (tty, Wcm.cm_home, 1, cmputc);
curY = 0, curX = 0;
emacs_tputs (tty, tty->Wcm->cm_home, 1, cmputc);
curY (tty) = 0, curX (tty) = 0;
break;
case USELL:
emacs_tputs (tty, Wcm.cm_ll, 1, cmputc);
curY = Wcm.cm_rows - 1, curX = 0;
emacs_tputs (tty, tty->Wcm->cm_ll, 1, cmputc);
curY (tty) = tty->Wcm->cm_rows - 1, curX (tty) = 0;
break;
case USECR:
emacs_tputs (tty, Wcm.cm_cr, 1, cmputc);
if (Wcm.cm_autolf)
curY++;
curX = 0;
emacs_tputs (tty, tty->Wcm->cm_cr, 1, cmputc);
if (tty->Wcm->cm_autolf)
curY (tty)++;
curX (tty) = 0;
break;
}
(void) calccost (tty, curY, curX, row, col, 1);
curY = row, curX = col;
(void) calccost (tty, curY (tty), curX (tty), row, col, 1);
curY (tty) = row, curX (tty) = col;
}
/* Clear out all terminal info.
......@@ -440,9 +441,9 @@ cmgoto (tty, row, col)
*/
void
Wcm_clear ()
Wcm_clear (struct tty_output *tty)
{
bzero (&Wcm, sizeof Wcm);
bzero (tty->Wcm, sizeof (struct cm));
UP = 0;
BC = 0;
}
......@@ -455,21 +456,21 @@ Wcm_clear ()
*/
int
Wcm_init ()
Wcm_init (struct tty_output *tty)
{
#if 0
if (Wcm.cm_abs && !Wcm.cm_ds)
if (tty->Wcm->cm_abs && !tty->Wcm->cm_ds)
return 0;
#endif
if (Wcm.cm_abs)
if (tty->Wcm->cm_abs)
return 0;
/* Require up and left, and, if no absolute, down and right */
if (!Wcm.cm_up || !Wcm.cm_left)
if (!tty->Wcm->cm_up || !tty->Wcm->cm_left)
return - 1;
if (!Wcm.cm_abs && (!Wcm.cm_down || !Wcm.cm_right))
if (!tty->Wcm->cm_abs && (!tty->Wcm->cm_down || !tty->Wcm->cm_right))
return - 1;
/* Check that we know the size of the screen.... */
if (Wcm.cm_rows <= 0 || Wcm.cm_cols <= 0)
if (tty->Wcm->cm_rows <= 0 || tty->Wcm->cm_cols <= 0)
return - 2;
return 0;
}
......
......@@ -98,66 +98,65 @@ struct cm
int cc_vabs;
};
extern struct cm Wcm; /* Terminal capabilities */
extern char PC; /* Pad character */
/* Shorthand */
#ifndef NoCMShortHand
#define curY Wcm.cm_curY
#define curX Wcm.cm_curX
#define Up Wcm.cm_up
#define Down Wcm.cm_down
#define Left Wcm.cm_left
#define Right Wcm.cm_right
#define Tab Wcm.cm_tab
#define BackTab Wcm.cm_backtab
#define TabWidth Wcm.cm_tabwidth
#define CR Wcm.cm_cr
#define Home Wcm.cm_home
#define LastLine Wcm.cm_ll
#define AbsPosition Wcm.cm_abs
#define ColPosition Wcm.cm_habs