1262685Sdelphij<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
262449Speter<!--
3262685Sdelphij  $Id: hackguide.html,v 1.29 2013/05/17 23:29:18 tom Exp $
4166124Srafan  ****************************************************************************
5262685Sdelphij  * Copyright (c) 1998-2010,2012 Free Software Foundation, Inc.              *
6166124Srafan  *                                                                          *
7166124Srafan  * Permission is hereby granted, free of charge, to any person obtaining a  *
8166124Srafan  * copy of this software and associated documentation files (the            *
9166124Srafan  * "Software"), to deal in the Software without restriction, including      *
10166124Srafan  * without limitation the rights to use, copy, modify, merge, publish,      *
11166124Srafan  * distribute, distribute with modifications, sublicense, and/or sell       *
12166124Srafan  * copies of the Software, and to permit persons to whom the Software is    *
13166124Srafan  * furnished to do so, subject to the following conditions:                 *
14166124Srafan  *                                                                          *
15166124Srafan  * The above copyright notice and this permission notice shall be included  *
16166124Srafan  * in all copies or substantial portions of the Software.                   *
17166124Srafan  *                                                                          *
18166124Srafan  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
19166124Srafan  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
20166124Srafan  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
21166124Srafan  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
22166124Srafan  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
23166124Srafan  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
24166124Srafan  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
25166124Srafan  *                                                                          *
26166124Srafan  * Except as contained in this notice, the name(s) of the above copyright   *
27166124Srafan  * holders shall not be used in advertising or otherwise to promote the     *
28166124Srafan  * sale, use or other dealings in this Software without prior written       *
29166124Srafan  * authorization.                                                           *
30166124Srafan  ****************************************************************************
3162449Speter-->
3262449Speter<HTML>
3362449Speter<HEAD>
3462449Speter<TITLE>A Hacker's Guide to Ncurses Internals</TITLE>
3562449Speter<link rev="made" href="mailto:bugs-ncurses@gnu.org">
36166124Srafan<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
3762449Speter<!--
3862449SpeterThis document is self-contained, *except* that there is one relative link to
3962449Speterthe ncurses-intro.html document, expected to be in the same directory with
4062449Speterthis one.
4162449Speter-->
4262449Speter</HEAD>
4362449Speter<BODY>
4462449Speter
4562449Speter<H1>A Hacker's Guide to NCURSES</H1>
4662449Speter
4762449Speter<H1>Contents</H1>
4862449Speter<UL>
4962449Speter<LI><A HREF="#abstract">Abstract</A>
5062449Speter<LI><A HREF="#objective">Objective of the Package</A>
5162449Speter<UL>
5262449Speter<LI><A HREF="#whysvr4">Why System V Curses?</A>
5362449Speter<LI><A HREF="#extensions">How to Design Extensions</A>
5462449Speter</UL>
5562449Speter<LI><A HREF="#portability">Portability and Configuration</A>
5662449Speter<LI><A HREF="#documentation">Documentation Conventions</A>
5762449Speter<LI><A HREF="#bugtrack">How to Report Bugs</A>
5862449Speter<LI><A HREF="#ncurslib">A Tour of the Ncurses Library</A>
5962449Speter<UL>
6062449Speter<LI><A HREF="#loverview">Library Overview</A>
6162449Speter<LI><A HREF="#engine">The Engine Room</A>
6262449Speter<LI><A HREF="#input">Keyboard Input</A>
6362449Speter<LI><A HREF="#mouse">Mouse Events</A>
6462449Speter<LI><A HREF="#output">Output and Screen Updating</A>
6562449Speter</UL>
6662449Speter<LI><A HREF="#fmnote">The Forms and Menu Libraries</A>
6762449Speter<LI><A HREF="#tic">A Tour of the Terminfo Compiler</A>
6862449Speter<UL>
6962449Speter<LI><A HREF="#nonuse">Translation of Non-<STRONG>use</STRONG> Capabilities</A>
7062449Speter<LI><A HREF="#uses">Use Capability Resolution</A>
7162449Speter<LI><A HREF="#translation">Source-Form Translation</A>
7262449Speter</UL>
7362449Speter<LI><A HREF="#utils">Other Utilities</A>
7462449Speter<LI><A HREF="#style">Style Tips for Developers</A>
7562449Speter<LI><A HREF="#port">Porting Hints</A>
7662449Speter</UL>
7762449Speter
7862449Speter<H1><A NAME="abstract">Abstract</A></H1>
7962449Speter
8062449SpeterThis document is a hacker's tour of the <STRONG>ncurses</STRONG> library and utilities.
8162449SpeterIt discusses design philosophy, implementation methods, and the
8262449Speterconventions used for coding and documentation.  It is recommended
8362449Speterreading for anyone who is interested in porting, extending or improving the
8462449Speterpackage.
8562449Speter
8662449Speter<H1><A NAME="objective">Objective of the Package</A></H1>
8762449Speter
8862449SpeterThe objective of the <STRONG>ncurses</STRONG> package is to provide a free software API for
8962449Spetercharacter-cell terminals and terminal emulators with the following
9062449Spetercharacteristics:
9162449Speter
9262449Speter<UL>
9362449Speter<LI>Source-compatible with historical curses implementations (including
9462449Speter     the original BSD curses and System V curses.
9562449Speter<LI>Conformant with the XSI Curses standard issued as part of XPG4 by
9662449Speter     X/Open.
9762449Speter<LI>High-quality -- stable and reliable code, wide portability, good
9862449Speter     packaging, superior documentation.
9962449Speter<LI>Featureful -- should eliminate as much of the drudgery of C interface
10062449Speter     programming as possible, freeing programmers to think at a higher
10162449Speter     level of design.
10262449Speter</UL>
10362449Speter
10462449SpeterThese objectives are in priority order.  So, for example, source
10562449Spetercompatibility with older version must trump featurefulness -- we cannot
10662449Speteradd features if it means breaking the portion of the API corresponding
10762449Speterto historical curses versions.
10862449Speter
10962449Speter<H2><A NAME="whysvr4">Why System V Curses?</A></H2>
11062449Speter
11162449SpeterWe used System V curses as a model, reverse-engineering their API, in
11262449Speterorder to fulfill the first two objectives. <P>
11362449Speter
11462449SpeterSystem V curses implementations can support BSD curses programs with
11562449Speterjust a recompilation, so by capturing the System V API we also
11662449Spetercapture BSD's. <P>
11762449Speter
11862449SpeterMore importantly for the future, the XSI Curses standard issued by X/Open
11962449Speteris explicitly and closely modeled on System V.  So conformance with
12062449SpeterSystem V took us most of the way to base-level XSI conformance.
12162449Speter
12262449Speter<H2><A NAME="extensions">How to Design Extensions</A></H2>
12362449Speter
12462449SpeterThe third objective (standards conformance) requires that it be easy to
12562449Spetercondition source code using <STRONG>ncurses</STRONG> so that the absence of nonstandard
12662449Speterextensions does not break the code. <P>
12762449Speter
12862449SpeterAccordingly, we have a policy of associating with each nonstandard extension
12962449Spetera feature macro, so that ncurses client code can use this macro to condition
13062449Speterin or out the code that requires the <STRONG>ncurses</STRONG> extension. <P>
13162449Speter
13262449SpeterFor example, there is a macro <CODE>NCURSES_MOUSE_VERSION</CODE> which XSI Curses
13362449Speterdoes not define, but which is defined in the <STRONG>ncurses</STRONG> library header.
13462449SpeterYou can use this to condition the calls to the mouse API calls.
13562449Speter
13662449Speter<H1><A NAME="portability">Portability and Configuration</A></H1>
13762449Speter
13862449SpeterCode written for <STRONG>ncurses</STRONG> may assume an ANSI-standard C compiler and
13962449SpeterPOSIX-compatible OS interface.  It may also assume the presence of a
14062449SpeterSystem-V-compatible <EM>select(2)</EM> call. <P>
14162449Speter
14262449SpeterWe encourage (but do not require) developers to make the code friendly
14362449Speterto less-capable UNIX environments wherever possible. <P>
14462449Speter
14562449SpeterWe encourage developers to support OS-specific optimizations and methods
14662449Speternot available under POSIX/ANSI, provided only that: 
14762449Speter
14862449Speter<UL>
14962449Speter<LI>All such code is properly conditioned so the build process does not
15062449Speter     attempt to compile it under a plain ANSI/POSIX environment.
15162449Speter<LI>Adding such implementation methods does not introduce incompatibilities
15262449Speter     in the <STRONG>ncurses</STRONG> API between platforms.
15362449Speter</UL>
15462449Speter
15562449SpeterWe use GNU <CODE>autoconf(1)</CODE> as a tool to deal with portability issues.
15662449SpeterThe right way to leverage an OS-specific feature is to modify the autoconf
15762449Speterspecification files (configure.in and aclocal.m4) to set up a new feature
15862449Spetermacro, which you then use to condition your code.
15962449Speter
16062449Speter<H1><A NAME="documentation">Documentation Conventions</A></H1>
16162449Speter
16262449SpeterThere are three kinds of documentation associated with this package.  Each
16362449Speterhas a different preferred format:
16462449Speter
16562449Speter<UL>
16662449Speter<LI>Package-internal files (README, INSTALL, TO-DO etc.)
16762449Speter<LI>Manual pages.
16862449Speter<LI>Everything else (i.e., narrative documentation).
16962449Speter</UL>
17062449Speter
17162449SpeterOur conventions are simple:
17262449Speter<OL>
17362449Speter<LI><STRONG>Maintain package-internal files in plain text.</STRONG>
17462449Speter     The expected viewer for them <EM>more(1)</EM> or an editor window; there's
17562449Speter     no point in elaborate mark-up.
17662449Speter
17762449Speter<LI><STRONG>Mark up manual pages in the man macros.</STRONG>  These have to be viewable
17862449Speter     through traditional <EM>man(1)</EM> programs.
17962449Speter
18062449Speter<LI><STRONG>Write everything else in HTML.</STRONG>
18162449Speter</OL>
18262449Speter
18362449SpeterWhen in doubt, HTMLize a master and use <EM>lynx(1)</EM> to generate
18462449Speterplain ASCII (as we do for the announcement document). <P>
18562449Speter
18662449SpeterThe reason for choosing HTML is that it's (a) well-adapted for on-line
18762449Speterbrowsing through viewers that are everywhere; (b) more easily readable
18862449Speteras plain text than most other mark-ups, if you don't have a viewer; and (c)
18962449Spetercarries enough information that you can generate a nice-looking printed
19062449Speterversion from it.  Also, of course, it make exporting things like the
19162449Speterannouncement document to WWW pretty trivial.
19262449Speter
19362449Speter<H1><A NAME="bugtrack">How to Report Bugs</A></H1>
19462449Speter
19562449SpeterThe <A NAME="bugreport">reporting address for bugs</A> is
19662449Speter<A HREF="mailto:bug-ncurses@gnu.org">bug-ncurses@gnu.org</A>.
19762449SpeterThis is a majordomo list; to join, write
19862449Speterto <CODE>bug-ncurses-request@gnu.org</CODE> with a message containing the line:
19962449Speter<PRE>
20062449Speter             subscribe &lt;name&gt;@&lt;host.domain&gt;
20162449Speter</PRE>
20262449Speter
20362449SpeterThe <CODE>ncurses</CODE> code is maintained by a small group of
20462449Spetervolunteers.  While we try our best to fix bugs promptly, we simply
20562449Speterdon't have a lot of hours to spend on elementary hand-holding.  We rely
20662449Speteron intelligent cooperation from our users.  If you think you have
20762449Speterfound a bug in <CODE>ncurses</CODE>, there are some steps you can take
20862449Speterbefore contacting us that will help get the bug fixed quickly. <P>
20962449Speter
21062449SpeterIn order to use our bug-fixing time efficiently, we put people who
21162449Spetershow us they've taken these steps at the head of our queue.  This
21262449Spetermeans that if you don't, you'll probably end up at the tail end and
21362449Speterhave to wait a while.
21462449Speter
21562449Speter<OL>
21662449Speter<LI>Develop a recipe to reproduce the bug.
21762449Speter<p>
21862449SpeterBugs we can reproduce are likely to be fixed very quickly, often
21962449Speterwithin days.  The most effective single thing you can do to get a
22062449Speterquick fix is develop a way we can duplicate the bad behavior --
22162449Speterideally, by giving us source for a small, portable test program that
22262449Speterbreaks the library. (Even better is a keystroke recipe using one of
22362449Speterthe test programs provided with the distribution.)
22462449Speter
22562449Speter<LI>Try to reproduce the bug on a different terminal type. <P>
22662449Speter
22762449SpeterIn our experience, most of the behaviors people report as library bugs
22862449Speterare actually due to subtle problems in terminal descriptions.  This is
22962449Speterespecially likely to be true if you're using a traditional
23062449Speterasynchronous terminal or PC-based terminal emulator, rather than xterm
23162449Speteror a UNIX console entry. <P>
23262449Speter
23362449SpeterIt's therefore extremely helpful if you can tell us whether or not your
23462449Speterproblem reproduces on other terminal types.  Usually you'll have both
23562449Spetera console type and xterm available; please tell us whether or not your
23662449Speterbug reproduces on both. <P>
23762449Speter
23862449SpeterIf you have xterm available, it is also good to collect xterm reports for
23962449Speterdifferent window sizes.  This is especially true if you normally use an
24062449Speterunusual xterm window size -- a surprising number of the bugs we've seen
24162449Speterare either triggered or masked by these. 
24262449Speter
24362449Speter<LI>Generate and examine a trace file for the broken behavior. <P>
24462449Speter
24562449SpeterRecompile your program with the debugging versions of the libraries.
24662449SpeterInsert a <CODE>trace()</CODE> call with the argument set to <CODE>TRACE_UPDATE</CODE>.
24762449Speter(See <A HREF="ncurses-intro.html#debugging">"Writing Programs with
24862449SpeterNCURSES"</A> for details on trace levels.)
24962449SpeterReproduce your bug, then look at the trace file to see what the library
25062449Speterwas actually doing. <P>
25162449Speter
25262449SpeterAnother frequent cause of apparent bugs is application coding errors
25362449Speterthat cause the wrong things to be put on the virtual screen.  Looking
25462449Speterat the virtual-screen dumps in the trace file will tell you immediately if
25562449Speterthis is happening, and save you from the possible embarrassment of being
25662449Spetertold that the bug is in your code and is your problem rather than ours. <P>
25762449Speter
25862449SpeterIf the virtual-screen dumps look correct but the bug persists, it's
25962449Speterpossible to crank up the trace level to give more and more information
26062449Speterabout the library's update actions and the control sequences it issues
26162449Speterto perform them.  The test directory of the distribution contains a
26262449Spetertool for digesting these logs to make them less tedious to wade
26362449Speterthrough. <P>
26462449Speter
26562449SpeterOften you'll find terminfo problems at this stage by noticing that the
26662449Speterescape sequences put out for various capabilities are wrong.  If not,
26762449Speteryou're likely to learn enough to be able to characterize any bug in
26862449Speterthe screen-update logic quite exactly.
26962449Speter
27062449Speter<LI>Report details and symptoms, not just interpretations. <P>
27162449Speter
27262449SpeterIf you do the preceding two steps, it is very likely that you'll discover
27362449Speterthe nature of the problem yourself and be able to send us a fix.  This
27462449Speterwill create happy feelings all around and earn you good karma for the first
27562449Spetertime you run into a bug you really can't characterize and fix yourself. <P>
27662449Speter
27762449SpeterIf you're still stuck, at least you'll know what to tell us.  Remember, we
27862449Speterneed details.  If you guess about what is safe to leave out, you are too
27962449Speterlikely to be wrong. <P>
28062449Speter
28162449SpeterIf your bug produces a bad update, include a trace file.  Try to make
28262449Speterthe trace at the <EM>least</EM> voluminous level that pins down the
28362449Speterbug.  Logs that have been through tracemunch are OK, it doesn't throw
28462449Speteraway any information (actually they're better than un-munched ones because
28562449Speterthey're easier to read). <P>
28662449Speter
28762449SpeterIf your bug produces a core-dump, please include a symbolic stack trace
28862449Spetergenerated by gdb(1) or your local equivalent. <P>
28962449Speter
29062449SpeterTell us about every terminal on which you've reproduced the bug -- and
29162449Speterevery terminal on which you can't.  Ideally, sent us terminfo sources
29262449Speterfor all of these (yours might differ from ours). <P>
29362449Speter
29462449SpeterInclude your ncurses version and your OS/machine type, of course!  You can
29562449Speterfind your ncurses version in the <CODE>curses.h</CODE> file.
29662449Speter</OL>
29762449Speter
29862449SpeterIf your problem smells like a logic error or in cursor movement or
29962449Speterscrolling or a bad capability, there are a couple of tiny test frames
30062449Speterfor the library algorithms in the progs directory that may help you
30162449Speterisolate it.  These are not part of the normal build, but do have their
30262449Speterown make productions.  <P>
30362449Speter
30462449SpeterThe most important of these is <CODE>mvcur</CODE>, a test frame for the
30562449Spetercursor-movement optimization code.  With this program, you can see
30662449Speterdirectly what control sequences will be emitted for any given cursor
30762449Spetermovement or scroll/insert/delete operations.  If you think you've got
30862449Spetera bad capability identified, you can disable it and test again. The
30962449Speterprogram is command-driven and has on-line help. <P>
31062449Speter
31162449SpeterIf you think the vertical-scroll optimization is broken, or just want to
31262449Speterunderstand how it works better, build <CODE>hashmap</CODE> and read the
31362449Speterheader comments of <CODE>hardscroll.c</CODE> and <CODE>hashmap.c</CODE>; then try
31462449Speterit out. You can also test the hardware-scrolling optimization separately
31562449Speterwith <CODE>hardscroll</CODE>. <P>
31662449Speter
31762449Speter<H1><A NAME="ncurslib">A Tour of the Ncurses Library</A></H1>
31862449Speter
31962449Speter<H2><A NAME="loverview">Library Overview</A></H2>
32062449Speter
32162449SpeterMost of the library is superstructure -- fairly trivial convenience
32262449Speterinterfaces to a small set of basic functions and data structures used
32362449Speterto manipulate the virtual screen (in particular, none of this code
32462449Speterdoes any I/O except through calls to more fundamental modules
32562449Speterdescribed below).  The files
32662449Speter<blockquote>
32762449Speter<CODE>
32862449Speterlib_addch.c
32962449Speterlib_bkgd.c
33062449Speterlib_box.c
33162449Speterlib_chgat.c
33262449Speterlib_clear.c
33362449Speterlib_clearok.c
33462449Speterlib_clrbot.c
33562449Speterlib_clreol.c
33662449Speterlib_colorset.c
33762449Speterlib_data.c
33862449Speterlib_delch.c
33962449Speterlib_delwin.c
34062449Speterlib_echo.c
34162449Speterlib_erase.c
34262449Speterlib_gen.c
34362449Speterlib_getstr.c
34462449Speterlib_hline.c
34562449Speterlib_immedok.c
34662449Speterlib_inchstr.c
34762449Speterlib_insch.c
34862449Speterlib_insdel.c
34962449Speterlib_insstr.c
35062449Speterlib_instr.c
35162449Speterlib_isendwin.c
35262449Speterlib_keyname.c
35362449Speterlib_leaveok.c
35462449Speterlib_move.c
35562449Speterlib_mvwin.c
35662449Speterlib_overlay.c
35762449Speterlib_pad.c
35862449Speterlib_printw.c
35962449Speterlib_redrawln.c
36062449Speterlib_scanw.c
36162449Speterlib_screen.c
36262449Speterlib_scroll.c
36362449Speterlib_scrollok.c
36462449Speterlib_scrreg.c
36562449Speterlib_set_term.c
36662449Speterlib_slk.c
36762449Speterlib_slkatr_set.c
36862449Speterlib_slkatrof.c
36962449Speterlib_slkatron.c
37062449Speterlib_slkatrset.c
37162449Speterlib_slkattr.c
37262449Speterlib_slkclear.c
37362449Speterlib_slkcolor.c
37462449Speterlib_slkinit.c
37562449Speterlib_slklab.c
37662449Speterlib_slkrefr.c
37762449Speterlib_slkset.c
37862449Speterlib_slktouch.c
37962449Speterlib_touch.c
38062449Speterlib_unctrl.c
38162449Speterlib_vline.c
38262449Speterlib_wattroff.c
38362449Speterlib_wattron.c
38462449Speterlib_window.c
38562449Speter</CODE>
38662449Speter</blockquote>
38762449Speterare all in this category.  They are very
38862449Speterunlikely to need change, barring bugs or some fundamental
38962449Speterreorganization in the underlying data structures. <P>
39062449Speter
39162449SpeterThese files are used only for debugging support:
39262449Speter<blockquote>
39362449Speter<code>
39462449Speterlib_trace.c
39562449Speterlib_traceatr.c
39662449Speterlib_tracebits.c
39762449Speterlib_tracechr.c
39862449Speterlib_tracedmp.c
39962449Speterlib_tracemse.c
40062449Spetertrace_buf.c
40162449Speter</code>
40262449Speter</blockquote>
40362449SpeterIt is rather unlikely you will ever need to change these, unless
404166124Srafanyou want to introduce a new debug trace level for some reason.<P>
40562449Speter
40662449SpeterThere is another group of files that do direct I/O via <EM>tputs()</EM>,
40762449Spetercomputations on the terminal capabilities, or queries to the OS
40862449Speterenvironment, but nevertheless have only fairly low complexity.  These
40962449Speterinclude:
41062449Speter<blockquote>
41162449Speter<code>
41262449Speterlib_acs.c
41362449Speterlib_beep.c
41462449Speterlib_color.c
41562449Speterlib_endwin.c
41662449Speterlib_initscr.c
41762449Speterlib_longname.c
41862449Speterlib_newterm.c
41962449Speterlib_options.c
42062449Speterlib_termcap.c
42162449Speterlib_ti.c
42262449Speterlib_tparm.c
42362449Speterlib_tputs.c
42462449Speterlib_vidattr.c
42562449Speterread_entry.c.
42662449Speter</code>
42762449Speter</blockquote>
42862449SpeterThey are likely to need revision only if
42962449Speterncurses is being ported to an environment without an underlying
43062449Speterterminfo capability representation. <P>
43162449Speter
43262449SpeterThese files
43362449Speterhave serious hooks into
43462449Speterthe tty driver and signal facilities:
43562449Speter<blockquote>
43662449Speter<code>
43762449Speterlib_kernel.c
43862449Speterlib_baudrate.c
43962449Speterlib_raw.c
44062449Speterlib_tstp.c
44162449Speterlib_twait.c
44262449Speter</code>
44362449Speter</blockquote>
44462449SpeterIf you run into porting snafus
44562449Spetermoving the package to another UNIX, the problem is likely to be in one
44662449Speterof these files.
44762449SpeterThe file <CODE>lib_print.c</CODE> uses sleep(2) and also
44862449Speterfalls in this category.<P>
44962449Speter
45062449SpeterAlmost all of the real work is done in the files
45162449Speter<blockquote>
45262449Speter<code>
45362449Speterhardscroll.c
45462449Speterhashmap.c
45562449Speterlib_addch.c
45662449Speterlib_doupdate.c
45762449Speterlib_getch.c
45862449Speterlib_mouse.c
45962449Speterlib_mvcur.c
46062449Speterlib_refresh.c
46162449Speterlib_setup.c
46262449Speterlib_vidattr.c
46362449Speter</code>
46462449Speter</blockquote>
46562449SpeterMost of the algorithmic complexity in the
46662449Speterlibrary lives in these files.
46762449SpeterIf there is a real bug in <STRONG>ncurses</STRONG> itself, it's probably here.
46862449SpeterWe'll tour some of these files in detail
46962449Speterbelow (see <A HREF="#engine">The Engine Room</A>). <P>
47062449Speter
47162449SpeterFinally, there is a group of files that is actually most of the
47262449Speterterminfo compiler.  The reason this code lives in the <STRONG>ncurses</STRONG>
47362449Speterlibrary is to support fallback to /etc/termcap.  These files include
47462449Speter<blockquote>
47562449Speter<code>
47662449Speteralloc_entry.c
47762449Spetercaptoinfo.c
47862449Spetercomp_captab.c
47962449Spetercomp_error.c
48062449Spetercomp_hash.c
48162449Spetercomp_parse.c
48262449Spetercomp_scan.c
48362449Speterparse_entry.c
48462449Speterread_termcap.c
48562449Speterwrite_entry.c
48662449Speter</code>
48762449Speter</blockquote>
48862449SpeterWe'll discuss these in the compiler tour.
48962449Speter
49062449Speter<H2><A NAME="engine">The Engine Room</A></H2>
49162449Speter
49262449Speter<H3><A NAME="input">Keyboard Input</A></H3>
49362449Speter
49462449SpeterAll <CODE>ncurses</CODE> input funnels through the function
49562449Speter<CODE>wgetch()</CODE>, defined in <CODE>lib_getch.c</CODE>.  This function is
49662449Spetertricky; it has to poll for keyboard and mouse events and do a running
49762449Spetermatch of incoming input against the set of defined special keys. <P>
49862449Speter
49962449SpeterThe central data structure in this module is a FIFO queue, used to
50062449Spetermatch multiple-character input sequences against special-key
50162449Spetercapabilities; also to implement pushback via <CODE>ungetch()</CODE>. <P>
50262449Speter
50362449SpeterThe <CODE>wgetch()</CODE> code distinguishes between function key
50462449Spetersequences and the same sequences typed manually by doing a timed wait
50562449Speterafter each input character that could lead a function key sequence.
50662449SpeterIf the entire sequence takes less than 1 second, it is assumed to have
50762449Speterbeen generated by a function key press. <P>
50862449Speter
50962449SpeterHackers bruised by previous encounters with variant <CODE>select(2)</CODE>
51062449Spetercalls may find the code in <CODE>lib_twait.c</CODE> interesting.  It deals
51162449Speterwith the problem that some BSD selects don't return a reliable
51262449Spetertime-left value.  The function <CODE>timed_wait()</CODE> effectively
51362449Spetersimulates a System V select.
51462449Speter
51562449Speter<H3><A NAME="mouse">Mouse Events</A></H3>
51662449Speter
51762449SpeterIf the mouse interface is active, <CODE>wgetch()</CODE> polls for mouse
51862449Speterevents each call, before it goes to the keyboard for input.  It is
51962449Speterup to <CODE>lib_mouse.c</CODE> how the polling is accomplished; it may vary
52062449Speterfor different devices. <P>
52162449Speter
52262449SpeterUnder xterm, however, mouse event notifications come in via the keyboard
52362449Speterinput stream.  They are recognized by having the <STRONG>kmous</STRONG> capability
52462449Speteras a prefix.  This is kind of klugey, but trying to wire in recognition of
52562449Spetera mouse key prefix without going through the function-key machinery would
52662449Speterbe just too painful, and this turns out to imply having the prefix somewhere
52762449Speterin the function-key capabilities at terminal-type initialization. <P>
52862449Speter
52962449SpeterThis kluge only works because <STRONG>kmous</STRONG> isn't actually used by any
53062449Speterhistoric terminal type or curses implementation we know of.  Best
53162449Speterguess is it's a relic of some forgotten experiment in-house at Bell
53262449SpeterLabs that didn't leave any traces in the publicly-distributed System V
53362449Speterterminfo files.  If System V or XPG4 ever gets serious about using it
53462449Speteragain, this kluge may have to change. <P>
53562449Speter
53662449SpeterHere are some more details about mouse event handling: <P>
53762449Speter
53862449SpeterThe <CODE>lib_mouse()</CODE>code is logically split into a lower level that
53962449Speteraccepts event reports in a device-dependent format and an upper level that
54062449Speterparses mouse gestures and filters events.  The mediating data structure is a
54162449Spetercircular queue of event structures. <P>
54262449Speter
54362449SpeterFunctionally, the lower level's job is to pick up primitive events and
54462449Speterput them on the circular queue.  This can happen in one of two ways:
54562449Spetereither (a) <CODE>_nc_mouse_event()</CODE> detects a series of incoming
54662449Spetermouse reports and queues them, or (b) code in <CODE>lib_getch.c</CODE> detects the
54762449Speter<STRONG>kmous</STRONG> prefix in the keyboard input stream and calls _nc_mouse_inline
54862449Speterto queue up a series of adjacent mouse reports. <P>
54962449Speter
55062449SpeterIn either case, <CODE>_nc_mouse_parse()</CODE> should be called after the
55162449Speterseries is accepted to parse the digested mouse reports (low-level
55262449Speterevents) into a gesture (a high-level or composite event).
55362449Speter
55462449Speter<H3><A NAME="output">Output and Screen Updating</A></H3>
55562449Speter
55662449SpeterWith the single exception of character echoes during a <CODE>wgetnstr()</CODE>
55762449Spetercall (which simulates cooked-mode line editing in an ncurses window),
55862449Speterthe library normally does all its output at refresh time. <P>
55962449Speter
56062449SpeterThe main job is to go from the current state of the screen (as represented
56162449Speterin the <CODE>curscr</CODE> window structure) to the desired new state (as
56262449Speterrepresented in the <CODE>newscr</CODE> window structure), while doing as
56362449Speterlittle I/O as possible. <P>
56462449Speter
56562449SpeterThe brains of this operation are the modules <CODE>hashmap.c</CODE>,
56662449Speter<CODE>hardscroll.c</CODE> and <CODE>lib_doupdate.c</CODE>; the latter two use
56762449Speter<CODE>lib_mvcur.c</CODE>.  Essentially, what happens looks like this: <P>
56862449Speter
56962449SpeterThe <CODE>hashmap.c</CODE> module tries to detect vertical motion
57062449Speterchanges between the real and virtual screens.  This information
57162449Speteris represented by the oldindex members in the newscr structure.
57262449SpeterThese are modified by vertical-motion and clear operations, and both are
57362449Speterre-initialized after each update. To this change-journalling
57462449Speterinformation, the hashmap code adds deductions made using a modified Heckel
57562449Speteralgorithm on hash values generated from the line contents. <P>
57662449Speter
57762449SpeterThe <CODE>hardscroll.c</CODE> module computes an optimum set of scroll,
57862449Speterinsertion, and deletion operations to make the indices match.  It calls
57962449Speter<CODE>_nc_mvcur_scrolln()</CODE> in <CODE>lib_mvcur.c</CODE> to do those motions. <P>
58062449Speter
58162449SpeterThen <CODE>lib_doupdate.c</CODE> goes to work.  Its job is to do line-by-line
58262449Spetertransformations of <CODE>curscr</CODE> lines to <CODE>newscr</CODE> lines.  Its main
58362449Spetertool is the routine <CODE>mvcur()</CODE> in <CODE>lib_mvcur.c</CODE>.  This routine
58462449Speterdoes cursor-movement optimization, attempting to get from given screen
585166124Srafanlocation A to given location B in the fewest output characters possible. <P>
58662449Speter
58762449SpeterIf you want to work on screen optimizations, you should use the fact
58862449Speterthat (in the trace-enabled version of the library) enabling the
58962449Speter<CODE>TRACE_TIMES</CODE> trace level causes a report to be emitted after
59062449Spetereach screen update giving the elapsed time and a count of characters
59162449Speteremitted during the update.  You can use this to tell when an update
59262449Speteroptimization improves efficiency. <P>
59362449Speter
59462449SpeterIn the trace-enabled version of the library, it is also possible to disable
59562449Speterand re-enable various optimizations at runtime by tweaking the variable
59662449Speter<CODE>_nc_optimize_enable</CODE>.  See the file <CODE>include/curses.h.in</CODE>
59762449Speterfor mask values, near the end.
59862449Speter
59962449Speter<H1><A NAME="fmnote">The Forms and Menu Libraries</A></H1>
60062449Speter
60162449SpeterThe forms and menu libraries should work reliably in any environment you
60262449Spetercan port ncurses to. The only portability issue anywhere in them is what
60362449Speterflavor of regular expressions the built-in form field type TYPE_REGEXP
60462449Speterwill recognize. <P>
60562449Speter
60662449SpeterThe configuration code prefers the POSIX regex facility, modeled on
60762449SpeterSystem V's, but will settle for BSD regexps if the former isn't available. <P>
60862449Speter
60962449SpeterHistorical note: the panels code was written primarily to assist in
61062449Speterporting u386mon 2.0 (comp.sources.misc v14i001-4) to systems lacking
61162449Speterpanels support; u386mon 2.10 and beyond use it.  This version has been
61262449Speterslightly cleaned up for <CODE>ncurses</CODE>.
61362449Speter
61462449Speter<H1><A NAME="tic">A Tour of the Terminfo Compiler</A></H1>
61562449Speter
61662449SpeterThe <STRONG>ncurses</STRONG> implementation of <STRONG>tic</STRONG> is rather complex
61762449Speterinternally; it has to do a trying combination of missions. This starts
61862449Speterwith the fact that, in addition to its normal duty of compiling
61962449Speterterminfo sources into loadable terminfo binaries, it has to be able to
62062449Speterhandle termcap syntax and compile that too into terminfo entries. <P>
62162449Speter
62262449SpeterThe implementation therefore starts with a table-driven, dual-mode
62362449Speterlexical analyzer (in <CODE>comp_scan.c</CODE>).  The lexer chooses its
62462449Spetermode (termcap or terminfo) based on the first `,' or `:' it finds in
62562449Spetereach entry.  The lexer does all the work of recognizing capability
62662449Speternames and values; the grammar above it is trivial, just "parse entries
62762449Spetertill you run out of file".
62862449Speter
62962449Speter<H2><A NAME="nonuse">Translation of Non-<STRONG>use</STRONG> Capabilities</A></H2>
63062449Speter
63162449SpeterTranslation of most things besides <STRONG>use</STRONG> capabilities is pretty
63262449Speterstraightforward.  The lexical analyzer's tokenizer hands each capability
63362449Spetername to a hash function, which drives a table lookup.  The table entry
63462449Speteryields an index which is used to look up the token type in another table,
63562449Speterand controls interpretation of the value. <P>
63662449Speter
63762449SpeterOne possibly interesting aspect of the implementation is the way the
63862449Spetercompiler tables are initialized.  All the tables are generated by various
63962449Speterawk/sed/sh scripts from a master table <CODE>include/Caps</CODE>; these
64062449Speterscripts actually write C initializers which are linked to the compiler.
64162449SpeterFurthermore, the hash table is generated in the same way, so it doesn't
64262449Speterhave to be generated at compiler startup time (another benefit of this
64362449Speterorganization is that the hash table can be in shareable text space). <P>
64462449Speter
64562449SpeterThus, adding a new capability is usually pretty trivial, just a matter
64662449Speterof adding one line to the <CODE>include/Caps</CODE> file.  We'll have more
64762449Speterto say about this in the section on <A HREF="#translation">Source-Form
64862449SpeterTranslation</A>.
64962449Speter
65062449Speter<H2><A NAME="uses">Use Capability Resolution</A></H2>
65162449Speter
65262449SpeterThe background problem that makes <STRONG>tic</STRONG> tricky isn't the capability
65362449Spetertranslation itself, it's the resolution of <STRONG>use</STRONG> capabilities.  Older
65462449Speterversions would not handle forward <STRONG>use</STRONG> references for this reason
65562449Speter(that is, a using terminal always had to follow its use target in the
65662449Spetersource file).  By doing this, they got away with a simple implementation
65762449Spetertactic; compile everything as it blows by, then resolve uses from compiled
65862449Speterentries. <P>
65962449Speter
66062449SpeterThis won't do for <STRONG>ncurses</STRONG>.  The problem is that that the whole
66162449Spetercompilation process has to be embeddable in the <STRONG>ncurses</STRONG> library
66262449Speterso that it can be called by the startup code to translate termcap
66362449Speterentries on the fly.  The embedded version can't go promiscuously writing
66462449Spetereverything it translates out to disk -- for one thing, it will typically
66562449Speterbe running with non-root permissions. <P>
66662449Speter
66762449SpeterSo our <STRONG>tic</STRONG> is designed to parse an entire terminfo file into a
66862449Speterdoubly-linked circular list of entry structures in-core, and then do
66962449Speter<STRONG>use</STRONG> resolution in-memory before writing everything out.  This
67062449Speterdesign has other advantages: it makes forward and back use-references
67162449Speterequally easy (so we get the latter for free), and it makes checking for
67262449Spetername collisions before they're written out easy to do. <P>
67362449Speter
67462449SpeterAnd this is exactly how the embedded version works.  But the stand-alone
67562449Speteruser-accessible version of <STRONG>tic</STRONG> partly reverts to the historical
67662449Speterstrategy; it writes to disk (not keeping in core) any entry with no
67762449Speter<STRONG>use</STRONG> references. <P>
67862449Speter
67962449SpeterThis is strictly a core-economy kluge, implemented because the
68062449Speterterminfo master file is large enough that some core-poor systems swap
68162449Speterlike crazy when you compile it all in memory...there have been reports of
68262449Speterthis process taking <STRONG>three hours</STRONG>, rather than the twenty seconds
68362449Speteror less typical on the author's development box. <P>
68462449Speter
68562449SpeterSo.  The executable <STRONG>tic</STRONG> passes the entry-parser a hook that
68662449Speter<EM>immediately</EM> writes out the referenced entry if it has no use
68762449Spetercapabilities.  The compiler main loop refrains from adding the entry
68862449Speterto the in-core list when this hook fires.  If some other entry later
68962449Speterneeds to reference an entry that got written immediately, that's OK;
69062449Speterthe resolution code will fetch it off disk when it can't find it in
69162449Spetercore. <P>
69262449Speter
69362449SpeterName collisions will still be detected, just not as cleanly.  The
69462449Speter<CODE>write_entry()</CODE> code complains before overwriting an entry that
69562449Speterpostdates the time of <STRONG>tic</STRONG>'s first call to
69662449Speter<CODE>write_entry()</CODE>, Thus it will complain about overwriting
69762449Speterentries newly made during the <STRONG>tic</STRONG> run, but not about
69862449Speteroverwriting ones that predate it.
69962449Speter
70062449Speter<H2><A NAME="translation">Source-Form Translation</A></H2>
70162449Speter
70262449SpeterAnother use of <STRONG>tic</STRONG> is to do source translation between various termcap
70362449Speterand terminfo formats.  There are more variants out there than you might
70462449Speterthink; the ones we know about are described in the <STRONG>captoinfo(1)</STRONG>
70562449Spetermanual page. <P>
70662449Speter
70762449SpeterThe translation output code (<CODE>dump_entry()</CODE> in
70862449Speter<CODE>ncurses/dump_entry.c</CODE>) is shared with the <STRONG>infocmp(1)</STRONG>
70962449Speterutility.  It takes the same internal representation used to generate
71062449Speterthe binary form and dumps it to standard output in a specified
71162449Speterformat. <P>
71262449Speter
71362449SpeterThe <CODE>include/Caps</CODE> file has a header comment describing ways you
71462449Spetercan specify source translations for nonstandard capabilities just by
71562449Speteraltering the master table.  It's possible to set up capability aliasing
71662449Speteror tell the compiler to plain ignore a given capability without writing
71762449Speterany C code at all. <P>
71862449Speter
71962449SpeterFor circumstances where you need to do algorithmic translation, there
72062449Speterare functions in <CODE>parse_entry.c</CODE> called after the parse of each
72162449Speterentry that are specifically intended to encapsulate such
72262449Spetertranslations.  This, for example, is where the AIX <STRONG>box1</STRONG> capability
72362449Speterget translated to an <STRONG>acsc</STRONG> string.
72462449Speter
72562449Speter<H1><A NAME="utils">Other Utilities</A></H1>
72662449Speter
72762449SpeterThe <STRONG>infocmp</STRONG> utility is just a wrapper around the same
72862449Speterentry-dumping code used by <STRONG>tic</STRONG> for source translation.  Perhaps
72962449Speterthe one interesting aspect of the code is the use of a predicate
73062449Speterfunction passed in to <CODE>dump_entry()</CODE> to control which
73162449Spetercapabilities are dumped.  This is necessary in order to handle both
73262449Speterthe ordinary De-compilation case and entry difference reporting. <P>
73362449Speter
73462449SpeterThe <STRONG>tput</STRONG> and <STRONG>clear</STRONG> utilities just do an entry load
73562449Speterfollowed by a <CODE>tputs()</CODE> of a selected capability.
73662449Speter
73762449Speter<H1><A NAME="style">Style Tips for Developers</A></H1>
73862449Speter
73962449SpeterSee the TO-DO file in the top-level directory of the source distribution
74062449Speterfor additions that would be particularly useful. <P>
74162449Speter
74262449SpeterThe prefix <CODE>_nc_</CODE> should be used on library public functions that are
74362449Speternot part of the curses API in order to prevent pollution of the
74462449Speterapplication namespace.
74562449Speter
74662449SpeterIf you have to add to or modify the function prototypes in curses.h.in,
74762449Speterread ncurses/MKlib_gen.sh first so you can avoid breaking XSI conformance.
74862449Speter
74962449SpeterPlease join the ncurses mailing list.  See the INSTALL file in the
75062449Spetertop level of the distribution for details on the list. <P>
75162449Speter
75262449SpeterLook for the string <CODE>FIXME</CODE> in source files to tag minor bugs
75362449Speterand potential problems that could use fixing. <P>
75462449Speter
75562449SpeterDon't try to auto-detect OS features in the main body of the C code.
75662449SpeterThat's the job of the configuration system. <P>
75762449Speter
75862449SpeterTo hold down complexity, do make your code data-driven.  Especially,
75962449Speterif you can drive logic from a table filtered out of
76062449Speter<CODE>include/Caps</CODE>, do it.  If you find you need to augment the
76162449Speterdata in that file in order to generate the proper table, that's still
76262449Speterpreferable to ad-hoc code -- that's why the fifth field (flags) is
76362449Speterthere. <P>
76462449Speter
76562449SpeterHave fun!
76662449Speter
76762449Speter<H1><A NAME="port">Porting Hints</A></H1>
76862449Speter
76962449SpeterThe following notes are intended to be a first step towards DOS and Macintosh
77062449Speterports of the ncurses libraries. <P>
77162449Speter
77262449SpeterThe following library modules are `pure curses'; they operate only on
77362449Speterthe curses internal structures, do all output through other curses
77462449Spetercalls (not including <CODE>tputs()</CODE> and <CODE>putp()</CODE>) and do not
77562449Spetercall any other UNIX routines such as signal(2) or the stdio library.
77662449SpeterThus, they should not need to be modified for single-terminal
77762449Speterports. 
77862449Speter
77962449Speter<blockquote>
78062449Speter<code>
78162449Speterlib_addch.c
78262449Speterlib_addstr.c
78362449Speterlib_bkgd.c
78462449Speterlib_box.c
78562449Speterlib_clear.c
78662449Speterlib_clrbot.c
78762449Speterlib_clreol.c
78862449Speterlib_delch.c
78962449Speterlib_delwin.c
79062449Speterlib_erase.c
79162449Speterlib_inchstr.c
79262449Speterlib_insch.c
79362449Speterlib_insdel.c
79462449Speterlib_insstr.c
79562449Speterlib_keyname.c
79662449Speterlib_move.c
79762449Speterlib_mvwin.c
79862449Speterlib_newwin.c
79962449Speterlib_overlay.c
80062449Speterlib_pad.c
80162449Speterlib_printw.c
80262449Speterlib_refresh.c
80362449Speterlib_scanw.c
80462449Speterlib_scroll.c
80562449Speterlib_scrreg.c
80662449Speterlib_set_term.c
80762449Speterlib_touch.c
80862449Speterlib_tparm.c
80962449Speterlib_tputs.c
81062449Speterlib_unctrl.c
81162449Speterlib_window.c
81262449Speterpanel.c
81362449Speter</code>
81462449Speter</blockquote>
81562449Speter<P>
81662449Speter
81762449SpeterThis module is pure curses, but calls outstr():
81862449Speter
81962449Speter<blockquote>
82062449Speter<code>
82162449Speterlib_getstr.c
82262449Speter</code>
82362449Speter</blockquote>
82462449Speter<P>
82562449Speter
82662449SpeterThese modules are pure curses, except that they use <CODE>tputs()</CODE>
82762449Speterand <CODE>putp()</CODE>:
82862449Speter
82962449Speter<blockquote>
83062449Speter<code>
83162449Speterlib_beep.c
83262449Speterlib_color.c
83362449Speterlib_endwin.c
83462449Speterlib_options.c
83562449Speterlib_slk.c
83662449Speterlib_vidattr.c
83762449Speter</code>
83862449Speter</blockquote>
83962449Speter<P>
84062449Speter
84162449SpeterThis modules assist in POSIX emulation on non-POSIX systems:
84262449Speter<DL>
84362449Speter<DT> sigaction.c
84462449Speter<DD> signal calls
84562449Speter</DL>
84662449Speter
84762449SpeterThe following source files will not be needed for a
84862449Spetersingle-terminal-type port.
84962449Speter
85062449Speter<blockquote>
85162449Speter<code>
85262449Speteralloc_entry.c
85362449Spetercaptoinfo.c
85462449Speterclear.c
85562449Spetercomp_captab.c
85662449Spetercomp_error.c
85762449Spetercomp_hash.c
85862449Spetercomp_main.c
85962449Spetercomp_parse.c
86062449Spetercomp_scan.c
86162449Speterdump_entry.c
86262449Speterinfocmp.c
86362449Speterparse_entry.c
86462449Speterread_entry.c
86562449Spetertput.c
86662449Speterwrite_entry.c
86762449Speter</code>
86862449Speter</blockquote>
86962449Speter<P>
87062449Speter
87162449SpeterThe following modules will use open()/read()/write()/close()/lseek() on files,
87262449Speterbut no other OS calls.
87362449Speter
87462449Speter<DL>
87562449Speter<DT>lib_screen.c
87662449Speter<DD>used to read/write screen dumps
87762449Speter<DT>lib_trace.c
87862449Speter<DD>used to write trace data to the logfile
87962449Speter</DL>
88062449Speter
88162449SpeterModules that would have to be modified for a port start here: <P>
88262449Speter
88362449SpeterThe following modules are `pure curses' but contain assumptions inappropriate
88462449Speterfor a memory-mapped port.
88562449Speter
88662449Speter<dl>
88762449Speter<dt>lib_longname.c<dd>assumes there may be multiple terminals
88862449Speter<dt>lib_acs.c<dd>assumes acs_map as a double indirection
88962449Speter<dt>lib_mvcur.c<dd>assumes cursor moves have variable cost
89062449Speter<dt>lib_termcap.c<dd>assumes there may be multiple terminals
89162449Speter<dt>lib_ti.c<dd>assumes there may be multiple terminals
89262449Speter</dl>
89362449Speter
89462449SpeterThe following modules use UNIX-specific calls:
89562449Speter
89662449Speter<dl>
89762449Speter<dt>lib_doupdate.c<dd>input checking
89862449Speter<dt>lib_getch.c<dd>read()
89962449Speter<dt>lib_initscr.c<dd>getenv()
90062449Speter<dt>lib_newterm.c
90162449Speter<dt>lib_baudrate.c
90262449Speter<dt>lib_kernel.c<dd>various tty-manipulation and system calls
90362449Speter<dt>lib_raw.c<dd>various tty-manipulation calls
90462449Speter<dt>lib_setup.c<dd>various tty-manipulation calls
90562449Speter<dt>lib_restart.c<dd>various tty-manipulation calls
90662449Speter<dt>lib_tstp.c<dd>signal-manipulation calls
90762449Speter<dt>lib_twait.c<dd>gettimeofday(), select().
90862449Speter</dl>
90962449Speter
91062449Speter<HR>
91162449Speter<ADDRESS>Eric S. Raymond &lt;esr@snark.thyrsus.com&gt;</ADDRESS>
91262449Speter(Note: This is <EM>not</EM> the <A HREF="#bugtrack">bug address</A>!)
91362449Speter</BODY>
91462449Speter</HTML>
915