4.2BSD/usr/doc/curses/Curses.doc
.
Screen Updating and Cursor Movement Optimization:
A Library Package
_K_e_n_n_e_t_h _C. _R. _C. _A_r_n_o_l_d
Computer Science Division
Department of Electrical Engineering and Computer Science
University of California, Berkeley
Berkeley, California 94720
_A_B_S_T_R_A_C_T
This document describes a package of C library
functions which allow the user to:
1) update a screen with reasonable optimization,
2) get input from the terminal in a screen-oriented
fashion, and
3) independent from the above, move the cursor op-
timally from one point to another.
These routines all use the /_e_t_c/_t_e_r_m_c_a_p database to
describe the capabilities of the terminal.
_A_c_k_n_o_w_l_e_d_g_e_m_e_n_t_s
This package would not exist without the work of Bill
Joy, who, in writing his editor, created the capability to
generally describe terminals, wrote the routines which read
this database, and, most importantly, those which implement
optimal cursor movement, which routines I have simply lifted
nearly intact. Doug Merritt and Kurt Shoens also were ex-
tremely important, as were both willing to waste time
listening to me rant and rave. The help and/or support of
Ken Abrams, Alan Char, Mark Horton, and Joe Kalash, was, and
is, also greatly appreciated.
.
Screen Package
_1. _O_v_e_r_v_i_e_w
In making available the generalized terminal descrip-
tions in /_e_t_c/_t_e_r_m_c_a_p, much information was made available
to the programmer, but little work was taken out of one's
hands. The purpose of this package is to allow the C pro-
grammer to do the most common type of terminal dependent
functions, those of movement optimization and optimal screen
updating, without doing any of the dirty work, and (hopeful-
ly) with nearly as much ease as is necessary to simply print
or read things.
The package is split into three parts: (1) Screen up-
dating; (2) Screen updating with user input; and (3) Cursor
motion optimization.
It is possible to use the motion optimization without
using either of the other two, and screen updating and input
can be done without any programmer knowledge of the motion
optimization, or indeed the database itself.
_1._1. _T_e_r_m_i_n_o_l_o_g_y (_o_r, _W_o_r_d_s _Y_o_u _C_a_n _S_a_y _t_o _S_o_u_n_d _B_r_i_l_l_i_-
_a_n_t)
In this document, the following terminology is kept to
with reasonable consistency:
_w_i_n_d_o_w: An internal representation containing an image of
what a section of the terminal screen may look like at
some point in time. This subsection can either encom-
pass the entire terminal screen, or any smaller portion
down to a single character within that screen.
_t_e_r_m_i_n_a_l: Sometimes called _t_e_r_m_i_n_a_l _s_c_r_e_e_n. The package's
idea of what the terminal's screen currently looks
like, i.e., what the user sees now. This is a special
_s_c_r_e_e_n:
_s_c_r_e_e_n: This is a subset of windows which are as large as
the terminal screen, i.e., they start at the upper left
hand corner and encompass the lower right hand corner.
One of these, _s_t_d_s_c_r, is automatically provided for the
programmer.
_1._2. _C_o_m_p_i_l_i_n_g _T_h_i_n_g_s
In order to use the library, it is necessary to have
certain types and variables defined. Therefore, the pro-
grammer must have a line:
#_i_n_c_l_u_d_e <_c_u_r_s_e_s._h>
at the top of the program source. The header file
- 1 -
.
Screen Package
<_c_u_r_s_e_s._h> needs to include <_s_g_t_t_y._h>, so the one should not
do so oneself[1]. Also, compilations should have the fol-
lowing form:
_c_c [ flags ] file ... -_l_c_u_r_s_e_s -_l_t_e_r_m_l_i_b
_1._3. _S_c_r_e_e_n _U_p_d_a_t_i_n_g
In order to update the screen optimally, it is neces-
sary for the routines to know what the screen currently
looks like and what the programmer wants it to look like
next. For this purpose, a data type (structure) named _W_I_N_-
_D_O_W is defined which describes a window image to the rou-
tines, including its starting position on the screen (the
(y, x) co-ordinates of the upper left hand corner) and its
size. One of these (called _c_u_r_s_c_r for _c_u_r_r_e_n_t _s_c_r_e_e_n) is a
screen image of what the terminal currently looks like.
Another screen (called _s_t_d_s_c_r, for _s_t_a_n_d_a_r_d _s_c_r_e_e_n) is pro-
vided by default to make changes on.
A window is a purely internal representation. It is
used to build and store a potential image of a portion of
the terminal. It doesn't bear any necessary relation to
what is really on the terminal screen. It is more like an
array of characters on which to make changes.
When one has a window which describes what some part
the terminal should look like, the routine _r_e_f_r_e_s_h() (or
_w_r_e_f_r_e_s_h() if the window is not _s_t_d_s_c_r) is called. _r_e_-
_f_r_e_s_h() makes the terminal, in the area covered by the win-
dow, look like that window. Note, therefore, that changing
something on a window _d_o_e_s _n_o_t _c_h_a_n_g_e _t_h_e _t_e_r_m_i_n_a_l. Actual
updates to the terminal screen are made only by calling _r_e_-
_f_r_e_s_h() or _w_r_e_f_r_e_s_h(). This allows the programmer to main-
tain several different ideas of what a portion of the termi-
nal screen should look like. Also, changes can be made to
windows in any order, without regard to motion efficiency.
Then, at will, the programmer can effectively say "make it
look like this," and let the package worry about the best
way to do this.
_1._4. _N_a_m_i_n_g _C_o_n_v_e_n_t_i_o_n_s
As hinted above, the routines can use several windows,
but two are automatically given: _c_u_r_s_c_r, which knows what
the terminal looks like, and _s_t_d_s_c_r, which is what the pro-
____________________
[1] The screen package also uses the Standard I/O li-
brary, so <_c_u_r_s_e_s._h> includes <_s_t_d_i_o._h>. It is redundant
(but harmless) for the programmer to do it, too.
- 2 -
.
Screen Package
grammer wants the terminal to look like next. The user
should never really access _c_u_r_s_c_r directly. Changes should
be made to the appropriate screen, and then the routine _r_e_-
_f_r_e_s_h() (or _w_r_e_f_r_e_s_h()) should be called.
Many functions are set up to deal with _s_t_d_s_c_r as a de-
fault screen. For example, to add a character to _s_t_d_s_c_r,
one calls _a_d_d_c_h() with the desired character. If a dif-
ferent window is to be used, the routine _w_a_d_d_c_h() (for
_window-specific _a_d_d_c_h()) is provided[2]. This convention of
prepending function names with a "_w" when they are to be ap-
plied to specific windows is consistent. The only routines
which do _n_o_t do this are those to which a window must always
be specified.
In order to move the current (y, x) co-ordinates from
one point to another, the routines _m_o_v_e() and _w_m_o_v_e() are
provided. However, it is often desirable to first move and
then perform some I/O operation. In order to avoid clumsy-
ness, most I/O routines can be preceded by the prefix "_m_v"
and the desired (y, x) co-ordinates then can be added to the
arguments to the function. For example, the calls
move(y, x);
addch(ch);
can be replaced by
mvaddch(y, x, ch);
and
wmove(win, y, x);
waddch(win, ch);
can be replaced by
mvwaddch(win, y, x, ch);
Note that the window description pointer (_w_i_n) comes before
the added (y, x) co-ordinates. If such pointers are need,
they are always the first parameters passed.
_2. _V_a_r_i_a_b_l_e_s
Many variables which are used to describe the terminal
environment are available to the programmer. They are:
____________________
[2] Actually, _a_d_d_c_h() is really a "#define" macro with
arguments, as are most of the "functions" which deal with
_s_t_d_s_c_r as a default.
- 3 -
.
Screen Package
type name description
__________________________________________________________________
WINDOW *curscr
current version of the screen (terminal screen).
WINDOW *stdscr
standard screen. Most updates are usually done
here.
char * Def_term
default terminal type if type cannot be determined
bool My_term
use the terminal specification in _D_e_f__t_e_r_m as ter-
minal, irrelevant of real terminal type
char * ttytype
full name of the current terminal.
int LINES
number of lines on the terminal
int COLS
number of columns on the terminal
int ERR
error flag returned by routines on a fail.
int OK
error flag returned by routines when things go
right.
There are also several "#define" constants and types
which are of general usefulness:
reg storage class ``register'' (e.g., _r_e_g _i_n_t _i;)
bool boolean type, actually a ``char'' (e.g., _b_o_o_l _d_o_n_e_i_t;)
TRUE boolean ``true'' flag (1).
FALSE boolean ``false'' flag (0).
_3. _U_s_a_g_e
This is a description of how to actually use the screen
package. In it, we assume all updating, reading, etc. is
applied to _s_t_d_s_c_r. All instructions will work on any win-
dow, with changing the function name and parameters as men-
tioned above.
_3._1. _S_t_a_r_t_i_n_g _u_p
In order to use the screen package, the routines must
know about terminal characteristics, and the space for
_c_u_r_s_c_r and _s_t_d_s_c_r must be allocated. These functions are
performed by _i_n_i_t_s_c_r(). Since it must allocate space for
the windows, it can overflow core when attempting to do so.
On this rather rare occasion, _i_n_i_t_s_c_r() returns ERR. _i_n_-
_i_t_s_c_r() must _a_l_w_a_y_s be called before any of the routines
which affect windows are used. If it is not, the program
will core dump as soon as either _c_u_r_s_c_r or _s_t_d_s_c_r are refer-
enced. However, it is usually best to wait to call it until
after you are sure you will need it, like after checking for
startup errors. Terminal status changing routines like _n_l()
and _c_r_m_o_d_e() should be called after _i_n_i_t_s_c_r().
Now that the screen windows have been allocated, you
can set them up for the run. If you want to, say, allow the
window to scroll, use _s_c_r_o_l_l_o_k(). If you want the cursor to
- 4 -
.
Screen Package
be left after the last change, use _l_e_a_v_e_o_k(). If this isn't
done, _r_e_f_r_e_s_h() will move the cursor to the window's current
(y, x) co-ordinates after updating it. New windows of your
own can be created, too, by using the functions _n_e_w_w_i_n() and
_s_u_b_w_i_n(). _d_e_l_w_i_n() will allow you to get rid of old win-
dows. If you wish to change the official size of the termi-
nal by hand, just set the variables _L_I_N_E_S and _C_O_L_S to be
what you want, and then call _i_n_i_t_s_c_r(). This is best done
before, but can be done either before or after, the first
call to _i_n_i_t_s_c_r(), as it will always delete any existing
_s_t_d_s_c_r and/or _c_u_r_s_c_r before creating new ones.
_3._2. _T_h_e _N_i_t_t_y-_G_r_i_t_t_y
_3._2._1. _O_u_t_p_u_t
Now that we have set things up, we will want to actual-
ly update the terminal. The basic functions used to change
what will go on a window are _a_d_d_c_h() and _m_o_v_e(). _a_d_d_c_h()
adds a character at the current (y, x) co-ordinates, return-
ing ERR if it would cause the window to illegally scroll,
i.e., printing a character in the lower right-hand corner of
a terminal which automatically scrolls if scrolling is not
allowed. _m_o_v_e() changes the current (y, x) co-ordinates to
whatever you want them to be. It returns ERR if you try to
move off the window when scrolling is not allowed. As men-
tioned above, you can combine the two into _m_v_a_d_d_c_h() to do
both things in one fell swoop.
The other output functions, such as _a_d_d_s_t_r() and
_p_r_i_n_t_w(), all call _a_d_d_c_h() to add characters to the window.
After you have put on the window what you want there,
when you want the portion of the terminal covered by the
window to be made to look like it, you must call _r_e_f_r_e_s_h().
In order to optimize finding changes, _r_e_f_r_e_s_h() assumes that
any part of the window not changed since the last _r_e_f_r_e_s_h()
of that window has not been changed on the terminal, i.e.,
that you have not refreshed a portion of the terminal with
an overlapping window. If this is not the case, the routine
_t_o_u_c_h_w_i_n() is provided to make it look like the entire win-
dow has been changed, thus making _r_e_f_r_e_s_h() check the whole
subsection of the terminal for changes.
If you call _w_r_e_f_r_e_s_h() with _c_u_r_s_c_r, it will make the
screen look like _c_u_r_s_c_r thinks it looks like. This is use-
ful for implementing a command which would redraw the screen
in case it get messed up.
_3._2._2. _I_n_p_u_t
Input is essentially a mirror image of output. The
complementary function to _a_d_d_c_h() is _g_e_t_c_h() which, if echo
- 5 -
.
Screen Package
is set, will call _a_d_d_c_h() to echo the character. Since the
screen package needs to know what is on the terminal at all
times, if characters are to be echoed, the tty must be in
raw or cbreak mode. If it is not, _g_e_t_c_h() sets it to be
cbreak, and then reads in the character.
_3._2._3. _M_i_s_c_e_l_l_a_n_e_o_u_s
All sorts of fun functions exists for maintaining and
changing information about the windows. For the most part,
the descriptions in section 5.4. should suffice.
_3._3. _F_i_n_i_s_h_i_n_g _u_p
In order to do certain optimizations, and, on some ter-
minals, to work at all, some things must be done before the
screen routines start up. These functions are performed in
_g_e_t_t_t_m_o_d_e() and _s_e_t_t_e_r_m(), which are called by _i_n_i_t_s_c_r().
In order to clean up after the routines, the routine
_e_n_d_w_i_n() is provided. It restores tty modes to what they
were when _i_n_i_t_s_c_r() was first called. Thus, anytime after
the call to initscr, _e_n_d_w_i_n() should be called before exit-
ing.
_4. _C_u_r_s_o_r _M_o_t_i_o_n _O_p_t_i_m_i_z_a_t_i_o_n: _S_t_a_n_d_i_n_g _A_l_o_n_e
It is possible to use the cursor optimization functions
of this screen package without the overhead and additional
size of the screen updating functions. The screen updating
functions are designed for uses where parts of the screen
are changed, but the overall image remains the same. This
includes such programs as _e_y_e and _v_i[3]. Certain other pro-
grams will find it difficult to use these functions in this
manner without considerable unnecessary program overhead.
For such applications, such as some "_c_r_t _h_a_c_k_s"[4] and op-
timizing _c_a_t(1)-type programs, all that is needed is the mo-
tion optimizations. This, therefore, is a description of
what some of what goes on at the lower levels of this screen
package. The descriptions assume a certain amount of fami-
liarity with programming problems and some finer points of
C. None of it is terribly difficult, but you should be
forewarned.
____________________
[3] _E_y_e actually uses these functions, _v_i does not.
[4] Graphics programs designed to run on character-
oriented terminals. I could name many, but they come and
go, so the list would be quickly out of date. Recently,
there have been programs such as _r_o_c_k_e_t and _g_u_n.
- 6 -
.
Screen Package
_4._1. _T_e_r_m_i_n_a_l _I_n_f_o_r_m_a_t_i_o_n
In order to use a terminal's features to the best of a
program's abilities, it must first know what they are[5].
The /_e_t_c/_t_e_r_m_c_a_p database describes these, but a certain
amount of decoding is necessary, and there are, of course,
both efficient and inefficient ways of reading them in. The
algorithm that the uses is taken from _v_i and is hideously
efficient. It reads them in a tight loop into a set of
variables whose names are two uppercase letters with some
mnemonic value. For example, _H_O is a string which moves the
cursor to the "home" position[6]. As there are two types of
variables involving ttys, there are two routines. The
first, _g_e_t_t_m_o_d_e(), sets some variables based upon the tty
modes accessed by _g_t_t_y(2) and _s_t_t_y(2) The second, _s_e_t_t_e_r_m(),
a larger task by reading in the descriptions from the
/_e_t_c/_t_e_r_m_c_a_p database. This is the way these routines are
used by _i_n_i_t_s_c_r():
_i_f (isatty(0)) {
gettmode();
_i_f (sp=getenv("TERM"))
setterm(sp);
}
_e_l_s_e
setterm(Def_term);
_puts(TI);
_puts(VS);
_i_s_a_t_t_y() checks to see if file descriptor 0 is a termi-
nal[7]. If it is, _g_e_t_t_m_o_d_e() sets the terminal description
modes from a _g_t_t_y(2) _g_e_t_e_n_v() is then called to get the name
of the terminal, and that value (if there is one) is passed
to _s_e_t_t_e_r_m(), which reads in the variables from /_e_t_c/_t_e_r_m_c_a_p
associated with that terminal. (_g_e_t_e_n_v() returns a pointer
to a string containing the name of the terminal, which we
save in the character pointer _s_p.) If _i_s_a_t_t_y() returns
____________________
[5] If this comes as any surprise to you, there's this
tower in Paris they're thinking of junking that I can let
you have for a song.
[6] These names are identical to those variables used in
the /_e_t_c/_t_e_r_m_c_a_p database to describe each capability. See
Appendix A for a complete list of those read, and _t_e_r_m_c_a_p(5)
for a full description.
[7] _i_s_a_t_t_y() is defined in the default C library function
routines. It does a _g_t_t_y(2) on the descriptor and checks
the return value.
- 7 -
.
Screen Package
false, the default terminal _D_e_f__t_e_r_m is used. The _T_I and _V_S
sequences initialize the terminal (__p_u_t_s() is a macro which
uses _t_p_u_t_s() (see _t_e_r_m_c_a_p(3)) to put out a string). It is
these things which _e_n_d_w_i_n() undoes.
_4._2. _M_o_v_e_m_e_n_t _O_p_t_i_m_i_z_a_t_i_o_n_s, _o_r, _G_e_t_t_i_n_g _O_v_e_r _Y_o_n_d_e_r
Now that we have all this useful information, it would
be nice to do something with it[8]. The most difficult
thing to do properly is motion optimization. When you con-
sider how many different features various terminals have
(tabs, backtabs, non-destructive space, home sequences, ab-
solute tabs, .....) you can see that deciding how to get
from here to there can be a decidedly non-trivial task. The
editor _v_i uses many of these features, and the routines it
uses to do this take up many pages of code. Fortunately, I
was able to liberate them with the author's permission, and
use them here.
After using _g_e_t_t_m_o_d_e() and _s_e_t_t_e_r_m() to get the termi-
nal descriptions, the function _m_v_c_u_r() deals with this task.
It usage is simple: you simply tell it where you are now and
where you want to go. For example
mvcur(0, 0, LINES/2, COLS/2)
would move the cursor from the home position (0, 0) to the
middle of the screen. If you wish to force absolute ad-
dressing, you can use the function _t_g_o_t_o() from the _t_e_r_m_-
_l_i_b(7) routines, or you can tell _m_v_c_u_r() that you are impos-
sibly far away, like Cleveland. For example, to absolutely
address the lower left hand corner of the screen from any-
where just claim that you are in the upper right hand
corner:
mvcur(0, COLS-1, LINES-1, 0)
_5. _T_h_e _F_u_n_c_t_i_o_n_s
In the following definitions, "[*]" means that the
"function" is really a "#define" macro with arguments. This
means that it will not show up in stack traces in the de-
bugger, or, in the case of such functions as _a_d_d_c_h(), it
will show up as it's "_w" counterpart. The arguments are
given to show the order and type of each. Their names are
____________________
[8] Actually, it _c_a_n be emotionally fulfilling just to
get the information. This is usually only true, however, if
you have the social life of a kumquat.
- 8 -
.
Screen Package
not mandatory, just suggestive.
_5._1. _O_u_t_p_u_t _F_u_n_c_t_i_o_n_s
_a_d_d_c_h(_c_h) [*]
char ch;
_w_a_d_d_c_h(_w_i_n, _c_h)
_W_I_N_D_O_W *_w_i_n;
_c_h_a_r _c_h;
Add the character _c_h on the window at the current
(y, x) co-ordinates. If the character is a newline
('\n') the line will be cleared to the end, and the
current (y, x) co-ordinates will be changed to the be-
ginning off the next line if newline mapping is on, or
to the next line at the same x co-ordinate if it is
off. A return ('\r') will move to the beginning of the
line on the window. Tabs ('\t') will be expanded into
spaces in the normal tabstop positions of every eight
characters. This returns ERR if it would cause the
screen to scroll illegally.
_a_d_d_s_t_r(_s_t_r) [*]
_c_h_a_r *_s_t_r;
_w_a_d_d_s_t_r(_w_i_n, _s_t_r)
_W_I_N_D_O_W *_w_i_n;
_c_h_a_r *_s_t_r;
Add the string pointed to by _s_t_r on the window at the
current (y, x) co-ordinates. This returns ERR if it
would cause the screen to scroll illegally. In this
case, it will put on as much as it can.
_b_o_x(_w_i_n, _v_e_r_t, _h_o_r)
_W_I_N_D_O_W *_w_i_n;
_c_h_a_r _v_e_r_t, _h_o_r;
Draws a box around the window using _v_e_r_t as the charac-
ter for drawing the vertical sides, and _h_o_r for drawing
the horizontal lines. If scrolling is not allowed, and
the window encompasses the lower right-hand corner of
the terminal, the corners are left blank to avoid a
scroll.
- 9 -
.
Screen Package
_c_l_e_a_r() [*]
_w_c_l_e_a_r(_w_i_n)
_W_I_N_D_O_W *_w_i_n;
Resets the entire window to blanks. If _w_i_n is a
screen, this sets the clear flag, which will cause a
clear-screen sequence to be sent on the next _r_e_f_r_e_s_h()
call. This also moves the current (y, x) co-ordinates
to (0, 0).
_c_l_e_a_r_o_k(_s_c_r, _b_o_o_l_f) [*]
_W_I_N_D_O_W *_s_c_r;
_b_o_o_l _b_o_o_l_f;
Sets the clear flag for the screen _s_c_r. If _b_o_o_l_f is
TRUE, this will force a clear-screen to be printed on
the next _r_e_f_r_e_s_h(), or stop it from doing so if _b_o_o_l_f
is FALSE. This only works on screens, and, unlike
_c_l_e_a_r(), does not alter the contents of the screen. If
_s_c_r is _c_u_r_s_c_r, the next _r_e_f_r_e_s_h() call will cause a
clear-screen, even if the window passed to _r_e_f_r_e_s_h() is
not a screen.
_c_l_r_t_o_b_o_t() [*]
_w_c_l_r_t_o_b_o_t(_w_i_n)
_W_I_N_D_O_W *_w_i_n;
Wipes the window clear from the current (y, x) co-
ordinates to the bottom. This does not force a clear-
screen sequence on the next refresh under any cir-
cumstances. This has no associated "mv" command.
_c_l_r_t_o_e_o_l() [*]
_w_c_l_r_t_o_e_o_l(_w_i_n)
_W_I_N_D_O_W *_w_i_n;
Wipes the window clear from the current (y, x) co-
ordinates to the end of the line. This has no associ-
ated "mv" command.
_d_e_l_c_h()
- 10 -
.
Screen Package
_w_d_e_l_c_h(_w_i_n)
_W_I_N_D_O_W *_w_i_n;
Delete the character at the current (y, x) co-
ordinates. Each character after it on the line shifts
to the left, and the last character becomes blank.
_d_e_l_e_t_e_l_n()
_w_d_e_l_e_t_e_l_n(_w_i_n)
_W_I_N_D_O_W *_w_i_n;
Delete the current line. Every line below the current
one will move up, and the bottom line will become
blank. The current (y, x) co-ordinates will remain un-
changed.
_e_r_a_s_e() [*]
_w_e_r_a_s_e(_w_i_n)
_W_I_N_D_O_W *_w_i_n;
Erases the window to blanks without setting the clear
flag. This is analagous to _c_l_e_a_r(), except that it
never causes a clear-screen sequence to be generated on
a _r_e_f_r_e_s_h(). This has no associated "mv" command.
_i_n_s_c_h(_c)
_c_h_a_r _c;
_w_i_n_s_c_h(_w_i_n, _c)
_W_I_N_D_O_W *_w_i_n;
_c_h_a_r _c;
Insert _c at the current (y, x) co-ordinates Each char-
acter after it shifts to the right, and the last char-
acter disappears. This returns ERR if it would cause
the screen to scroll illegally.
_i_n_s_e_r_t_l_n()
_w_i_n_s_e_r_t_l_n(_w_i_n)
_W_I_N_D_O_W *_w_i_n;
- 11 -
.
Screen Package
Insert a line above the current one. Every line below
the current line will be shifted down, and the bottom
line will disappear. The current line will become
blank, and the current (y, x) co-ordinates will remain
unchanged. This returns ERR if it would cause the
screen to scroll illegally.
_m_o_v_e(_y, _x) [*]
_i_n_t _y, _x;
_w_m_o_v_e(_w_i_n, _y, _x)
_W_I_N_D_O_W *_w_i_n;
_i_n_t _y, _x;
Change the current (y, x) co-ordinates of the window to
(_y, _x). This returns ERR if it would cause the screen
to scroll illegally.
_o_v_e_r_l_a_y(_w_i_n_1, _w_i_n_2)
_W_I_N_D_O_W *_w_i_n_1, *_w_i_n_2;
Overlay _w_i_n_1 on _w_i_n_2. The contents of _w_i_n_1, insofar as
they fit, are placed on _w_i_n_2 at their starting (y, x)
co-ordinates. This is done non-destructively, i.e.,
blanks on _w_i_n_1 leave the contents of the space on _w_i_n_2
untouched.
_o_v_e_r_w_r_i_t_e(_w_i_n_1, _w_i_n_2)
_W_I_N_D_O_W *_w_i_n_1, *_w_i_n_2;
Overwrite _w_i_n_1 on _w_i_n_2. The contents of _w_i_n_1, insofar
as they fit, are placed on _w_i_n_2 at their starting
(y, x) co-ordinates. This is done destructively, i.e.,
blanks on _w_i_n_1 become blank on _w_i_n_2.
_p_r_i_n_t_w(_f_m_t, _a_r_g_1, _a_r_g_2, ...)
_c_h_a_r *_f_m_t;
_w_p_r_i_n_t_w(_w_i_n, _f_m_t, _a_r_g_1, _a_r_g_2, ...)
_W_I_N_D_O_W *_w_i_n;
_c_h_a_r *_f_m_t;
Performs a _p_r_i_n_t_f() on the window starting at the
current (y, x) co-ordinates. It uses _a_d_d_s_t_r() to add
the string on the window. It is often advisable to use
- 12 -
.
Screen Package
the field width options of _p_r_i_n_t_f() to avoid leaving
things on the window from earlier calls. This returns
ERR if it would cause the screen to scroll illegally.
_r_e_f_r_e_s_h() [*]
_w_r_e_f_r_e_s_h(_w_i_n)
_W_I_N_D_O_W *_w_i_n;
Synchronize the terminal screen with the desired win-
dow. If the window is not a screen, only that part
covered by it is updated. This returns ERR if it would
cause the screen to scroll illegally. In this case, it
will update whatever it can without causing the scroll.
_s_t_a_n_d_o_u_t() [*]
_w_s_t_a_n_d_o_u_t(_w_i_n)
_W_I_N_D_O_W *_w_i_n;
_s_t_a_n_d_e_n_d() [*]
_w_s_t_a_n_d_e_n_d(_w_i_n)
_W_I_N_D_O_W *_w_i_n;
Start and stop putting characters onto _w_i_n in standout
mode. _s_t_a_n_d_o_u_t() causes any characters added to the
window to be put in standout mode on the terminal (if
it has that capability). _s_t_a_n_d_e_n_d() stops this. The
sequences _S_O and _S_E (or _U_S and _U_E if they are not de-
fined) are used (see Appendix A).
_5._2. _I_n_p_u_t _F_u_n_c_t_i_o_n_s
_c_r_m_o_d_e() [*]
_n_o_c_r_m_o_d_e() [*]
Set or unset the terminal to/from cbreak mode.
_e_c_h_o() [*]
_n_o_e_c_h_o() [*]
- 13 -
.
Screen Package
Sets the terminal to echo or not echo characters.
_g_e_t_c_h() [*]
_w_g_e_t_c_h(_w_i_n)
_W_I_N_D_O_W *_w_i_n;
Gets a character from the terminal and (if necessary)
echos it on the window. This returns ERR if it would
cause the screen to scroll illegally. Otherwise, the
character gotten is returned. If _n_o_e_c_h_o has been set,
then the window is left unaltered. In order to retain
control of the terminal, it is necessary to have one of
_n_o_e_c_h_o, _c_b_r_e_a_k, or _r_a_w_m_o_d_e set. If you do not set one,
whatever routine you call to read characters will set
_c_b_r_e_a_k for you, and then reset to the original mode
when finished.
_g_e_t_s_t_r(_s_t_r) [*]
_c_h_a_r *_s_t_r;
_w_g_e_t_s_t_r(_w_i_n, _s_t_r)
_W_I_N_D_O_W *_w_i_n;
_c_h_a_r *_s_t_r;
Get a string through the window and put it in the loca-
tion pointed to by _s_t_r, which is assumed to be large
enough to handle it. It sets tty modes if necessary,
and then calls _g_e_t_c_h() (or _w_g_e_t_c_h(_w_i_n)) to get the
characters needed to fill in the string until a newline
or EOF is encountered. The newline stripped off the
string. This returns ERR if it would cause the screen
to scroll illegally.
_r_a_w() [*]
_n_o_r_a_w() [*]
Set or unset the terminal to/from raw mode. On version
7 _U_N_I_X[_9] this also turns of newline mapping (see
_n_l()).
____________________
[9] _U_N_I_X is a trademark of Bell Laboratories.
- 14 -
.
Screen Package
_s_c_a_n_w(_f_m_t, _a_r_g_1, _a_r_g_2, ...)
_c_h_a_r *_f_m_t;
_w_s_c_a_n_w(_w_i_n, _f_m_t, _a_r_g_1, _a_r_g_2, ...)
_W_I_N_D_O_W *_w_i_n;
_c_h_a_r *_f_m_t;
Perform a _s_c_a_n_f() through the window using _f_m_t. It
does this using consecutive _g_e_t_c_h()'s (or
_w_g_e_t_c_h(_w_i_n)'s). This returns ERR if it would cause the
screen to scroll illegally.
_5._3. _M_i_s_c_e_l_l_a_n_e_o_u_s _F_u_n_c_t_i_o_n_s
_d_e_l_w_i_n(_w_i_n)
_W_I_N_D_O_W *_w_i_n;
Deletes the window from existence. All resources are
freed for future use by _c_a_l_l_o_c(3). If a window has a
_s_u_b_w_i_n() allocated window inside of it, deleting the
outer window the subwindow is not affected, even though
this does invalidate it. Therefore, subwindows should
be deleted before their outer windows are.
_e_n_d_w_i_n()
Finish up window routines before exit. This restores
the terminal to the state it was before _i_n_i_t_s_c_r() (or
_g_e_t_t_m_o_d_e() and _s_e_t_t_e_r_m()) was called. It should always
be called before exiting. It does not exit. This is
especially useful for resetting tty stats when trapping
rubouts via _s_i_g_n_a_l(2).
_g_e_t_y_x(_w_i_n, _y, _x) [*]
_W_I_N_D_O_W *_w_i_n;
_i_n_t _y, _x;
Puts the current (y, x) co-ordinates of _w_i_n in the
variables _y and _x. Since it is a macro, not a func-
tion, you do not pass the address of _y and _x.
_i_n_c_h() [*]
_w_i_n_c_h(_w_i_n) [*]
- 15 -
.
Screen Package
_W_I_N_D_O_W *_w_i_n;
Returns the character at the current (y, x) co-
ordinates on the given window. This does not make any
changes to the window. This has no associated "mv"
command.
_i_n_i_t_s_c_r()
Initialize the screen routines. This must be called
before any of the screen routines are used. It ini-
tializes the terminal-type data and such, and without
it, none of the routines can operate. If standard in-
put is not a tty, it sets the specifications to the
terminal whose name is pointed to by _D_e_f__t_e_r_m (initialy
"dumb"). If the boolean _M_y__t_e_r_m is true, _D_e_f__t_e_r_m is
always used.
_l_e_a_v_e_o_k(_w_i_n, _b_o_o_l_f) [*]
_W_I_N_D_O_W *_w_i_n;
_b_o_o_l _b_o_o_l_f;
Sets the boolean flag for leaving the cursor after the
last change. If _b_o_o_l_f is TRUE, the cursor will be left
after the last update on the terminal, and the current
(y, x) co-ordinates for _w_i_n will be changed according-
ly. If it is FALSE, it will be moved to the current
(y, x) co-ordinates. This flag (initialy FALSE) re-
tains its value until changed by the user.
_l_o_n_g_n_a_m_e(_t_e_r_m_b_u_f, _n_a_m_e)
_c_h_a_r *_t_e_r_m_b_u_f, *_n_a_m_e;
Fills in _n_a_m_e with the long (full) name of the terminal
described by the termcap entry in _t_e_r_m_b_u_f. It is gen-
erally of little use, but is nice for telling the user
in a readable format what terminal we think he has.
This is available in the global variable _t_t_y_t_y_p_e.
_T_e_r_m_b_u_f is usually set via the termlib routine
_t_g_e_t_e_n_t().
_m_v_w_i_n(_w_i_n, _y, _x)
_W_I_N_D_O_W *_w_i_n;
_i_n_t _y, _x;
- 16 -
.
Screen Package
Move the home position of the window _w_i_n from its
current starting coordinates to (_y, _x). If that would
put part or all of the window off the edge of the ter-
minal screen, _m_v_w_i_n() returns ERR and does not change
anything.
_W_I_N_D_O_W *
_n_e_w_w_i_n(_l_i_n_e_s, _c_o_l_s, _b_e_g_i_n__y, _b_e_g_i_n__x)
_i_n_t _l_i_n_e_s, _c_o_l_s, _b_e_g_i_n__y, _b_e_g_i_n__x;
Create a new window with _l_i_n_e_s lines and _c_o_l_s columns
starting at position (_b_e_g_i_n__y, _b_e_g_i_n__x). If either
_l_i_n_e_s or _c_o_l_s is 0 (zero), that dimension will be set
to (_L_I_N_E_S - _b_e_g_i_n__y) or (_C_O_L_S - _b_e_g_i_n__x) respectively.
Thus, to get a new window of dimensions _L_I_N_E_S x _C_O_L_S,
use _n_e_w_w_i_n(_0, _0, _0, _0).
_n_l() [*]
_n_o_n_l() [*]
Set or unset the terminal to/from nl mode, i.e.,
start/stop the system from mapping <_R_E_T_U_R_N> to <_L_I_N_E-
_F_E_E_D>. If the mapping is not done, _r_e_f_r_e_s_h() can do
more optimization, so it is recommended, but not re-
quired, to turn it off.
_s_c_r_o_l_l_o_k(_w_i_n, _b_o_o_l_f) [*]
_W_I_N_D_O_W *_w_i_n;
_b_o_o_l _b_o_o_l_f;
Set the scroll flag for the given window. If _b_o_o_l_f is
FALSE, scrolling is not allowed. This is its default
setting.
_t_o_u_c_h_w_i_n(_w_i_n)
_W_I_N_D_O_W *_w_i_n;
Make it appear that the every location on the window
has been changed. This is usually only needed for re-
freshes with overlapping windows.
_W_I_N_D_O_W *
_s_u_b_w_i_n(_w_i_n, _l_i_n_e_s, _c_o_l_s, _b_e_g_i_n__y, _b_e_g_i_n__x)
_W_I_N_D_O_W *_w_i_n;
- 17 -
.
Screen Package
_i_n_t _l_i_n_e_s, _c_o_l_s, _b_e_g_i_n__y, _b_e_g_i_n__x;
Create a new window with _l_i_n_e_s lines and _c_o_l_s columns
starting at position (_b_e_g_i_n__y, _b_e_g_i_n__x) in the middle
of the window _w_i_n. This means that any change made to
either window in the area covered by the subwindow will
be made on both windows. _b_e_g_i_n__y, _b_e_g_i_n__x are speci-
fied relative to the overall screen, not the relative
(0, 0) of _w_i_n. If either _l_i_n_e_s or _c_o_l_s is 0 (zero),
that dimension will be set to (_L_I_N_E_S - _b_e_g_i_n__y) or
(_C_O_L_S - _b_e_g_i_n__x) respectively.
_u_n_c_t_r_l(_c_h) [*]
_c_h_a_r _c_h;
This is actually a debug function for the library, but
it is of general usefulness. It returns a string which
is a representation of _c_h. Control characters become
their upper-case equivalents preceded by a "^". Other
letters stay just as they are. To use _u_n_c_t_r_l(), you
must have #_i_n_c_l_u_d_e <_u_n_c_t_r_l._h> in your file.
_5._4. _D_e_t_a_i_l_s
_g_e_t_t_m_o_d_e()
Get the tty stats. This is normally called by _i_n_-
_i_t_s_c_r().
_m_v_c_u_r(_l_a_s_t_y, _l_a_s_t_x, _n_e_w_y, _n_e_w_x)
_i_n_t _l_a_s_t_y, _l_a_s_t_x, _n_e_w_y, _n_e_w_x;
Moves the terminal's cursor from (_l_a_s_t_y, _l_a_s_t_x) to
(_n_e_w_y, _n_e_w_x) in an approximation of optimal fashion.
This routine uses the functions borrowed from _e_x ver-
sion 2.6. It is possible to use this optimization
without the benefit of the screen routines. With the
screen routines, this should not be called by the user.
_m_o_v_e() and _r_e_f_r_e_s_h() should be used to move the cursor
position, so that the routines know what's going on.
_s_c_r_o_l_l(_w_i_n)
_W_I_N_D_O_W *_w_i_n;
- 18 -
.
Screen Package
Scroll the window upward one line. This is normally
not used by the user.
_s_a_v_e_t_t_y() [*]
_r_e_s_e_t_t_y() [*]
_s_a_v_e_t_t_y() saves the current tty characteristic flags.
_r_e_s_e_t_t_y() restores them to what _s_a_v_e_t_t_y() stored.
These functions are performed automatically by _i_n_-
_i_t_s_c_r() and _e_n_d_w_i_n().
_s_e_t_t_e_r_m(_n_a_m_e)
_c_h_a_r *_n_a_m_e;
Set the terminal characteristics to be those of the
terminal named _n_a_m_e. This is normally called by _i_n_-
_i_t_s_c_r().
_t_s_t_p()
If the new _t_t_y(4) driver is in use, this function will
save the current tty state and then put the process to
sleep. When the process gets restarted, it restores
the tty state and then calls _w_r_e_f_r_e_s_h(_c_u_r_s_c_r) to redraw
the screen. _i_n_i_t_s_c_r() sets the signal SIGTSTP to trap
to this routine.
- 19 -
.
_A_p_p_e_n_d_i_x _A
_1. _C_a_p_a_b_i_l_i_t_i_e_s _f_r_o_m _t_e_r_m_c_a_p
_1._1. _D_i_s_c_l_a_i_m_e_r
The description of terminals is a difficult business,
and we only attempt to summarize the capabilities here: for
a full description see the paper describing termcap.
_1._2. _O_v_e_r_v_i_e_w
Capabilities from termcap are of three kinds: string
valued options, numeric valued options, and boolean options.
The string valued options are the most complicated, since
they may include padding information, which we describe now.
Intelligent terminals often require padding on intelli-
gent operations at high (and sometimes even low) speed.
This is specified by a number before the string in the capa-
bility, and has meaning for the capabilities which have a _P
at the front of their comment. This normally is a number of
milliseconds to pad the operation. In the current system
which has no true programmable delays, we do this by sending
a sequence of pad characters (normally nulls, but can be
changed (specified by _P_C)). In some cases, the pad is
better computed as some number of milliseconds times the
number of affected lines (to the bottom of the screen usual-
ly, except when terminals have insert modes which will shift
several lines.) This is specified as, e.g., _1_2*. before the
capability, to say 12 milliseconds per affected whatever
(currently always line). Capabilities where this makes
sense say _P*.
_1._3. _V_a_r_i_a_b_l_e_s _S_e_t _B_y _s_e_t_t_e_r_m()
variables set by _s_e_t_t_e_r_m()
Type Name Pad Description
_____________________________________________________________
char * AL P* Add new blank Line
bool AM Automatic Margins
char * BC Back Cursor movement
bool BS BackSpace works
char * BT P Back Tab
bool CA Cursor Addressable
char * CD P* Clear to end of Display
char * CE P Clear to End of line
char * CL P* CLear screen
char * CM P Cursor Motion
char * DC P* Delete Character
char * DL P* Delete Line sequence
char * DM Delete Mode (enter)
- 20 -
.
_A_p_p_e_n_d_i_x _A
variables set by _s_e_t_t_e_r_m()
Type Name Pad Description
_____________________________________________________________
char * DO DOwn line sequence
char * ED End Delete mode
bool EO can Erase Overstrikes with ' '
char * EI End Insert mode
char * HO HOme cursor
bool HZ HaZeltine ~ braindamage
char * IC P Insert Character
bool IN Insert-Null blessing
char * IM enter Insert Mode (IC usually set, too)
char * IP P* Pad after char Inserted using IM+IE
char * LL quick to Last Line, column 0
char * MA ctrl character MAp for cmd mode
bool MI can Move in Insert mode
bool NC No Cr: \r sends \r\n then eats \n
char * ND Non-Destructive space
bool OS OverStrike works
char PC Pad Character
char * SE Standout End (may leave space)
char * SF P Scroll Forwards
char * SO Stand Out begin (may leave space)
char * SR P Scroll in Reverse
char * TA P TAb (not ^I or with padding)
char * TE Terminal address enable Ending sequence
char * TI Terminal address enable Initialization
char * UC Underline a single Character
char * UE Underline Ending sequence
bool UL UnderLining works even though !OS
char * UP UPline
char * US Underline Starting sequence[10]
char * VB Visible Bell
char * VE Visual End sequence
char * VS Visual Start sequence
bool XN a Newline gets eaten after wrap
Names starting with _X are reserved for severely nauseous
glitches
_1._4. _V_a_r_i_a_b_l_e_s _S_e_t _B_y _g_e_t_t_m_o_d_e()
variables set by _g_e_t_t_m_o_d_e()
type name description
____________________________________________________________
____________________
[10] US and UE, if they do not exist in the termcap en-
try, are copied from SO and SE in _s_e_t_t_e_r_m()
- 21 -
.
_A_p_p_e_n_d_i_x _A
variables set by _g_e_t_t_m_o_d_e()
type name description
____________________________________________________________
bool NONL Term can't hack linefeeds doing a CR
bool GT Gtty indicates Tabs
bool UPPERCASE Terminal generates only uppercase letters
- 22 -
.
_A_p_p_e_n_d_i_x _B
_1.
_T_h_e _W_I_N_D_O_W _s_t_r_u_c_t_u_r_e
The WINDOW structure is defined as follows:
# _d_e_f_i_n_e WINDOW _s_t_r_u_c_t _win_st
_s_t_r_u_c_t _win_st {
_s_h_o_r_t _cury, _curx;
_s_h_o_r_t _maxy, _maxx;
_s_h_o_r_t _begy, _begx;
_s_h_o_r_t _flags;
bool _clear;
bool _leave;
bool _scroll;
_c_h_a_r **_y;
_s_h_o_r_t *_firstch;
_s_h_o_r_t *_lastch;
};
# _d_e_f_i_n_e _SUBWIN 01
# _d_e_f_i_n_e _ENDLINE 02
# _d_e_f_i_n_e _FULLWIN 04
# _d_e_f_i_n_e _SCROLLWIN 010
# _d_e_f_i_n_e _STANDOUT 0200
__c_u_r_y and __c_u_r_x are the current (y, x) co-ordinates for
the window. New characters added to the screen are added at
this point. __m_a_x_y and __m_a_x_x are the maximum values allowed
for (__c_u_r_y, __c_u_r_x). __b_e_g_y and __b_e_g_x are the starting (y, x)
co-ordinates on the terminal for the window, i.e., the
window's home. __c_u_r_y, __c_u_r_x, __m_a_x_y, and __m_a_x_x are measured
relative to (__b_e_g_y, __b_e_g_x), not the terminal's home.
__c_l_e_a_r tells if a clear-screen sequence is to be gen-
erated on the next _r_e_f_r_e_s_h() call. This is only meaningful
for screens. The initial clear-screen for the first _r_e_-
_f_r_e_s_h() call is generated by initially setting clear to be
TRUE for _c_u_r_s_c_r, which always generates a clear-screen if
set, irrelevant of the dimensions of the window involved.
__l_e_a_v_e is TRUE if the current (y, x) co-ordinates and the
cursor are to be left after the last character changed on
the terminal, or not moved if there is no change. __s_c_r_o_l_l
is TRUE if scrolling is allowed.
__y is a pointer to an array of lines which describe the
terminal. Thus:
_y[i]
is a pointer to the _ith line, and
_y[i][j]
is the _jth character on the _ith line.
__f_l_a_g_s can have one or more values or'd into it.
__S_U_B_W_I_N means that the window is a subwindow, which indi-
cates to _d_e_l_w_i_n() that the space for the lines is not to be
freed. __E_N_D_L_I_N_E says that the end of the line for this win-
dow is also the end of a screen. __F_U_L_L_W_I_N says that this
window is a screen. __S_C_R_O_L_L_W_I_N indicates that the last
character of this screen is at the lower right-hand corner
of the terminal; _i._e., if a character was put there, the
terminal would scroll. __S_T_A_N_D_O_U_T says that all characters
added to the screen are in standout mode.
_1. _E_x_a_m_p_l_e_s
Here we present a few examples of how to use the pack-
age. They attempt to be representative, though not
comprehensive.
_2. _S_c_r_e_e_n _U_p_d_a_t_i_n_g
The following examples are intended to demonstrate the
basic structure of a program using the screen updating sec-
tions of the package. Several of the programs require cal-
culational sections which are irrelevant of to the example,
and are therefore usually not included. It is hoped that
the data structure definitions give enough of an idea to al-
low understanding of what the relevant portions do. The
rest is left as an exercise to the reader, and will not be
on the final.
_2._1. _T_w_i_n_k_l_e
This is a moderately simple program which prints pretty
patterns on the screen that might even hold your interest
for 30 seconds or more. It switches between patterns of as-
terisks, putting them on one by one in random order, and
then taking them off in the same fashion. It is more effi-
cient to write this using only the motion optimization, as
is demonstrated below.
# _i_n_c_l_u_d_e <curses.h>
# _i_n_c_l_u_d_e <signal.h>
/*
* _t_h_e _i_d_e_a _f_o_r _t_h_i_s _p_r_o_g_r_a_m _w_a_s _a _p_r_o_d_u_c_t _o_f _t_h_e _i_m_a_g_i_n_a_t_i_o_n _o_f
* _K_u_r_t _S_c_h_o_e_n_s. _N_o_t _r_e_s_p_o_n_s_i_b_l_e _f_o_r _m_i_n_d_s _l_o_s_t _o_r _s_t_o_l_e_n.
*/
# _d_e_f_i_n_e NCOLS 80
# _d_e_f_i_n_e NLINES 24
# _d_e_f_i_n_e MAXPATTERNS 4
_s_t_r_u_c_t locs {
_c_h_a_r y, x;
};
_t_y_p_e_d_e_f _s_t_r_u_c_t locs LOCS;
LOCS Layout[NCOLS * NLINES]; /* _c_u_r_r_e_n_t _b_o_a_r_d _l_a_y_o_u_t */
_i_n_t Pattern, /* _c_u_r_r_e_n_t _p_a_t_t_e_r_n _n_u_m_b_e_r */
Numstars; /* _n_u_m_b_e_r _o_f _s_t_a_r_s _i_n _p_a_t_t_e_r_n */
mainmain() {
_c_h_a_r *getenv();
_i_n_t die();
srand(getpid()); /* _i_n_i_t_i_a_l_i_z_e _r_a_n_d_o_m _s_e_q_u_e_n_c_e */
initscr();
signal(SIGINT, die);
noecho();
nonl();
leaveok(stdscr, TRUE);
scrollok(stdscr, FALSE);
_f_o_r (;;) {
makeboard(); /* _m_a_k_e _t_h_e _b_o_a_r_d _s_e_t_u_p */
puton('*'); /* _p_u_t _o_n '*'_s */
puton(' '); /* _c_o_v_e_r _u_p _w_i_t_h ' '_s */
}
}
/*
* _O_n _p_r_o_g_r_a_m _e_x_i_t, _m_o_v_e _t_h_e _c_u_r_s_o_r _t_o _t_h_e _l_o_w_e_r _l_e_f_t _c_o_r_n_e_r _b_y
* _d_i_r_e_c_t _a_d_d_r_e_s_s_i_n_g, _s_i_n_c_e _c_u_r_r_e_n_t _l_o_c_a_t_i_o_n _i_s _n_o_t _g_u_a_r_a_n_t_e_e_d.
* _W_e _l_i_e _a_n_d _s_a_y _w_e _u_s_e_d _t_o _b_e _a_t _t_h_e _u_p_p_e_r _r_i_g_h_t _c_o_r_n_e_r _t_o _g_u_a_r_a_n_t_e_e
* _a_b_s_o_l_u_t_e _a_d_d_r_e_s_s_i_n_g.
*/
diedie() {
signal(SIGINT, SIG_IGN);
mvcur(0, COLS-1, LINES-1, 0);
endwin();
exit(0);
}
/*
* _M_a_k_e _t_h_e _c_u_r_r_e_n_t _b_o_a_r_d _s_e_t_u_p. _I_t _p_i_c_k_s _a _r_a_n_d_o_m _p_a_t_t_e_r_n _a_n_d
* _c_a_l_l_s _i_s_o_n() _t_o _d_e_t_e_r_m_i_n_e _i_f _t_h_e _c_h_a_r_a_c_t_e_r _i_s _o_n _t_h_a_t _p_a_t_t_e_r_n
* _o_r _n_o_t.
*/
makeboardmakeboard() {
reg _i_n_t y, x;
reg LOCS *lp;
Pattern = rand() % MAXPATTERNS;
lp = Layout;
_f_o_r (y = 0; y < NLINES; y++)
_f_o_r (x = 0; x < NCOLS; x++)
_i_f (ison(y, x)) {
lp->y = y;
lp++->x = x;
}
Numstars = lp - Layout;
}
/*
* _R_e_t_u_r_n _T_R_U_E _i_f (_y, _x) _i_s _o_n _t_h_e _c_u_r_r_e_n_t _p_a_t_t_e_r_n.
*/
isonison(y, x)
reg _i_n_t y, x; {
_s_w_i_t_c_h (Pattern) {
_c_a_s_e 0: /* _a_l_t_e_r_n_a_t_i_n_g _l_i_n_e_s */
_r_e_t_u_r_n !(y & 01);
_c_a_s_e 1: /* _b_o_x */
_i_f (x >= LINES && y >= NCOLS)
_r_e_t_u_r_n FALSE;
_i_f (y < 3 || y >= NLINES - 3)
_r_e_t_u_r_n TRUE;
_r_e_t_u_r_n (x < 3 || x >= NCOLS - 3);
_c_a_s_e 2: /* _h_o_l_y _p_a_t_t_e_r_n! */
_r_e_t_u_r_n ((x + y) & 01);
_c_a_s_e 3: /* _b_a_r _a_c_r_o_s_s _c_e_n_t_e_r */
_r_e_t_u_r_n (y >= 9 && y <= 15);
}
/* _N_O_T_R_E_A_C_H_E_D */
}
putonputon(ch)
reg _c_h_a_r ch; {
reg LOCS *lp;
reg _i_n_t r;
reg LOCS *end;
LOCS temp;
end = &Layout[Numstars];
_f_o_r (lp = Layout; lp < end; lp++) {
r = rand() % Numstars;
temp = *lp;
*lp = Layout[r];
Layout[r] = temp;
}
_f_o_r (lp = Layout; lp < end; lp++) {
mvaddch(lp->y, lp->x, ch);
refresh();
}
}
_2._2. _L_i_f_e
This program plays the famous computer pattern game of
life (Scientific American, May, 1974). The calculational
routines create a linked list of structures defining where
each piece is. Nothing here claims to be optimal, merely
demonstrative. This program, however, is a very good place
to use the screen updating routines, as it allows them to
worry about what the last position looked like, so you don't
have to. It also demonstrates some of the input routines.
# _i_n_c_l_u_d_e <curses.h>
# _i_n_c_l_u_d_e <signal.h>
/*
* _R_u_n _a _l_i_f_e _g_a_m_e. _T_h_i_s _i_s _a _d_e_m_o_n_s_t_r_a_t_i_o_n _p_r_o_g_r_a_m _f_o_r
* _t_h_e _S_c_r_e_e_n _U_p_d_a_t_i_n_g _s_e_c_t_i_o_n _o_f _t_h_e -_l_c_u_r_s_e_s _c_u_r_s_o_r _p_a_c_k_a_g_e.
*/
_s_t_r_u_c_t lst_st { /* _l_i_n_k_e_d _l_i_s_t _e_l_e_m_e_n_t */
_i_n_t y, x; /* (_y, _x) _p_o_s_i_t_i_o_n _o_f _p_i_e_c_e */
_s_t_r_u_c_t lst_st *next, *last; /* _d_o_u_b_l_y _l_i_n_k_e_d */
};
_t_y_p_e_d_e_f _s_t_r_u_c_t lst_st LIST;
LIST *Head; /* _h_e_a_d _o_f _l_i_n_k_e_d _l_i_s_t */
mainmain(ac, av)
_i_n_t ac;
_c_h_a_r *av[]; {
_i_n_t die();
evalargs(ac, av); /* _e_v_a_l_u_a_t_e _a_r_g_u_m_e_n_t_s */
initscr(); /* _i_n_i_t_i_a_l_i_z_e _s_c_r_e_e_n _p_a_c_k_a_g_e */
signal(SIGINT, die); /* _s_e_t _t_o _r_e_s_t_o_r_e _t_t_y _s_t_a_t_s */
crmode(); /* _s_e_t _f_o_r _c_h_a_r-_b_y-_c_h_a_r */
noecho(); /* _i_n_p_u_t */
nonl(); /* _f_o_r _o_p_t_i_m_i_z_a_t_i_o_n */
getstart(); /* _g_e_t _s_t_a_r_t_i_n_g _p_o_s_i_t_i_o_n */
_f_o_r (;;) {
prboard(); /* _p_r_i_n_t _o_u_t _c_u_r_r_e_n_t _b_o_a_r_d */
update(); /* _u_p_d_a_t_e _b_o_a_r_d _p_o_s_i_t_i_o_n */
}
}
/*
* _T_h_i_s _i_s _t_h_e _r_o_u_t_i_n_e _w_h_i_c_h _i_s _c_a_l_l_e_d _w_h_e_n _r_u_b_o_u_t _i_s _h_i_t.
* _I_t _r_e_s_e_t_s _t_h_e _t_t_y _s_t_a_t_s _t_o _t_h_e_i_r _o_r_i_g_i_n_a_l _v_a_l_u_e_s. _T_h_i_s
* _i_s _t_h_e _n_o_r_m_a_l _w_a_y _o_f _l_e_a_v_i_n_g _t_h_e _p_r_o_g_r_a_m.
*/
diedie() {
signal(SIGINT, SIG_IGN); /* _i_g_n_o_r_e _r_u_b_o_u_t_s */
mvcur(0, COLS-1, LINES-1, 0); /* _g_o _t_o _b_o_t_t_o_m _o_f _s_c_r_e_e_n */
endwin(); /* _s_e_t _t_e_r_m_i_n_a_l _t_o _i_n_i_t_i_a_l _s_t_a_t_e */
exit(0);
}
/*
* _G_e_t _t_h_e _s_t_a_r_t_i_n_g _p_o_s_i_t_i_o_n _f_r_o_m _t_h_e _u_s_e_r. _T_h_e_y _k_e_y_s _u, _i, _o, _j, _l,
* _m, ,, _a_n_d . _a_r_e _u_s_e_d _f_o_r _m_o_v_i_n_g _t_h_e_i_r _r_e_l_a_t_i_v_e _d_i_r_e_c_t_i_o_n_s _f_r_o_m _t_h_e
* _k _k_e_y. _T_h_u_s, _u _m_o_v_e _d_i_a_g_o_n_a_l_l_y _u_p _t_o _t_h_e _l_e_f_t, , _m_o_v_e_s _d_i_r_e_c_t_l_y _d_o_w_n,
* _e_t_c. _x _p_l_a_c_e_s _a _p_i_e_c_e _a_t _t_h_e _c_u_r_r_e_n_t _p_o_s_i_t_i_o_n, " " _t_a_k_e_s _i_t _a_w_a_y.
* _T_h_e _i_n_p_u_t _c_a_n _a_l_s_o _b_e _f_r_o_m _a _f_i_l_e. _T_h_e _l_i_s_t _i_s _b_u_i_l_t _a_f_t_e_r _t_h_e
* _b_o_a_r_d _s_e_t_u_p _i_s _r_e_a_d_y.
*/
getstartgetstart() {
reg _c_h_a_r c;
reg _i_n_t x, y;
box(stdscr, '|', '_'); /* _b_o_x _i_n _t_h_e _s_c_r_e_e_n */
move(1, 1); /* _m_o_v_e _t_o _u_p_p_e_r _l_e_f_t _c_o_r_n_e_r */
_d_o {
refresh(); /* _p_r_i_n_t _c_u_r_r_e_n_t _p_o_s_i_t_i_o_n */
_i_f ((c=getch()) == 'q')
_b_r_e_a_k;
_s_w_i_t_c_h (c) {
_c_a_s_e 'u':
_c_a_s_e 'i':
_c_a_s_e 'o':
_c_a_s_e 'j':
_c_a_s_e 'l':
_c_a_s_e 'm':
_c_a_s_e ',':
_c_a_s_e '.':
adjustyx(c);
_b_r_e_a_k;
_c_a_s_e 'f':
mvaddstr(0, 0, "File name: ");
getstr(buf);
readfile(buf);
_b_r_e_a_k;
_c_a_s_e 'x':
addch('X');
_b_r_e_a_k;
_c_a_s_e ' ':
addch(' ');
_b_r_e_a_k;
}
}
_i_f (Head != NULL) /* _s_t_a_r_t _n_e_w _l_i_s_t */
dellist(Head);
Head = malloc(_s_i_z_e_o_f (LIST));
/*
* _l_o_o_p _t_h_r_o_u_g_h _t_h_e _s_c_r_e_e_n _l_o_o_k_i_n_g _f_o_r '_x'_s, _a_n_d _a_d_d _a _l_i_s_t
* _e_l_e_m_e_n_t _f_o_r _e_a_c_h _o_n_e
*/
_f_o_r (y = 1; y < LINES - 1; y++)
_f_o_r (x = 1; x < COLS - 1; x++) {
move(y, x);
_i_f (inch() == 'x')
addlist(y, x);
}
}
/*
* _P_r_i_n_t _o_u_t _t_h_e _c_u_r_r_e_n_t _b_o_a_r_d _p_o_s_i_t_i_o_n _f_r_o_m _t_h_e _l_i_n_k_e_d _l_i_s_t
*/
prboardprboard() {
reg LIST *hp;
erase(); /* _c_l_e_a_r _o_u_t _l_a_s_t _p_o_s_i_t_i_o_n */
box(stdscr, '|', '_'); /* _b_o_x _i_n _t_h_e _s_c_r_e_e_n */
/*
* _g_o _t_h_r_o_u_g_h _t_h_e _l_i_s_t _a_d_d_i_n_g _e_a_c_h _p_i_e_c_e _t_o _t_h_e _n_e_w_l_y
* _b_l_a_n_k _b_o_a_r_d
*/
_f_o_r (hp = Head; hp; hp = hp->next)
mvaddch(hp->y, hp->x, 'X');
refresh();
}
_3. _M_o_t_i_o_n _o_p_t_i_m_i_z_a_t_i_o_n
The following example shows how motion optimization is
written on its own. Programs which flit from one place to
another without regard for what is already there usually do
not need the overhead of both space and time associated with
screen updating. They should instead use motion optimiza-
tion.
_3._1. _T_w_i_n_k_l_e
The _t_w_i_n_k_l_e program is a good candidate for simple mo-
tion optimization. Here is how it could be written (only
the routines that have been changed are shown):
mainmain() {
reg _c_h_a_r *sp;
_c_h_a_r *getenv();
_i_n_t _putchar(), die();
srand(getpid()); /* _i_n_i_t_i_a_l_i_z_e _r_a_n_d_o_m _s_e_q_u_e_n_c_e */
_i_f (isatty(0)) {
gettmode();
_i_f (sp=getenv("TERM"))
setterm(sp);
signal(SIGINT, die);
}
_e_l_s_e {
printf("Need a terminal on %d\n", _tty_ch);
exit(1);
}
_puts(TI);
_puts(VS);
noecho();
nonl();
tputs(CL, NLINES, _putchar);
_f_o_r (;;) {
makeboard(); /* _m_a_k_e _t_h_e _b_o_a_r_d _s_e_t_u_p */
puton('*'); /* _p_u_t _o_n '*'_s */
puton(' '); /* _c_o_v_e_r _u_p _w_i_t_h ' '_s */
}
}
/*
* __p_u_t_c_h_a_r _d_e_f_i_n_e_d _f_o_r _t_p_u_t_s() (_a_n_d __p_u_t_s())
*/
_putchar_putchar(c)
reg _c_h_a_r c; {
putchar(c);
}
putonputon(ch)
_c_h_a_r ch; {
_s_t_a_t_i_c _i_n_t lasty, lastx;
reg LOCS *lp;
reg _i_n_t r;
reg LOCS *end;
LOCS temp;
end = &Layout[Numstars];
_f_o_r (lp = Layout; lp < end; lp++) {
r = rand() % Numstars;
temp = *lp;
*lp = Layout[r];
Layout[r] = temp;
}
_f_o_r (lp = Layout; lp < end; lp++)
/* _p_r_e_v_e_n_t _s_c_r_o_l_l_i_n_g */
_i_f (!AM || (lp->y < NLINES - 1 || lp->x < NCOLS - 1)) {
mvcur(lasty, lastx, lp->y, lp->x);
putchar(ch);
lasty = lp->y;
_i_f ((lastx = lp->x + 1) >= NCOLS)
_i_f (AM) {
lastx = 0;
lasty++;
}
_e_l_s_e
lastx = NCOLS - 1;
}
}
_C_o_n_t_e_n_t_s
1 Overview ............................................ 1
1.1 Terminology (or, Words You Can Say to Sound
Brilliant) ......................................... 1
1.2 Compiling Things ............................... 1
1.3 Screen Updating ................................ 2
1.4 Naming Conventions ............................. 2
2 Variables ........................................... 3
3 Usage ............................................... 4
3.1 Starting up .................................... 4
3.2 The Nitty-Gritty ............................... 5
3.2.1 Output .................................... 5
3.2.2 Input ..................................... 5
3.2.3 Miscellaneous ............................. 6
3.3 Finishing up ................................... 6
4 Cursor Motion Optimization: Standing Alone .......... 6
4.1 Terminal Information ........................... 7
4.2 Movement Optimizations, or, Getting Over
Yonder ............................................. 8
5 The Functions ....................................... 8
5.1 Output Functions ............................... 9
5.2 Input Functions ................................ 13
5.3 Miscellaneous Functions ........................ 15
5.4 Details ........................................ 18
_A_p_p_e_n_d_i_x_e_s
_A_p_p_e_n_d_i_x _A ............................................ 20
1 Capabilities from termcap ........................... 20
1.1 Disclaimer ..................................... 20
1.2 Overview ....................................... 20
1.3 Variables Set By setterm() ..................... 20
1.4 Variables Set By gettmode() .................... 21
_A_p_p_e_n_d_i_x _B ............................................ 23
1 The WINDOW structure ................................ 23
_A_p_p_e_n_d_i_x _C ............................................ 25
1 Examples ............................................ 25
2 Screen Updating ..................................... 25
2.1 Twinkle ........................................ 25
2.2 Life ........................................... 27
3 Motion optimization ................................. 29
3.1 Twinkle ........................................ 29