4.1cBSD/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