mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-11-26 20:12:44 +00:00
ncurses: readd 2 html files in the doc (fix MK_HTML=yes)
Reported by: Michael Butler <imb@protected-networks.net>
This commit is contained in:
parent
35e941ce55
commit
8d9900a313
962
contrib/ncurses/doc/html/hackguide.html
Normal file
962
contrib/ncurses/doc/html/hackguide.html
Normal file
@ -0,0 +1,962 @@
|
||||
<!--
|
||||
$Id: hackguide.html,v 1.36 2022/11/26 19:31:56 tom Exp $
|
||||
****************************************************************************
|
||||
* Copyright 2019-2020,2022 Thomas E. Dickey *
|
||||
* Copyright 2000-2013,2017 Free Software Foundation, Inc. *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a *
|
||||
* copy of this software and associated documentation files (the *
|
||||
* "Software"), to deal in the Software without restriction, including *
|
||||
* without limitation the rights to use, copy, modify, merge, publish, *
|
||||
* distribute, distribute with modifications, sublicense, and/or sell *
|
||||
* copies of the Software, and to permit persons to whom the Software is *
|
||||
* furnished to do so, subject to the following conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included *
|
||||
* in all copies or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
|
||||
* IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
|
||||
* THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
* *
|
||||
* Except as contained in this notice, the name(s) of the above copyright *
|
||||
* holders shall not be used in advertising or otherwise to promote the *
|
||||
* sale, use or other dealings in this Software without prior written *
|
||||
* authorization. *
|
||||
****************************************************************************
|
||||
-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
|
||||
<html>
|
||||
<head>
|
||||
<meta name="generator" content=
|
||||
"HTML Tidy for HTML5 for Linux version 5.6.0">
|
||||
<title>A Hacker's Guide to Ncurses Internals</title>
|
||||
<link rel="author" href="mailto:bugs-ncurses@gnu.org">
|
||||
<meta http-equiv="Content-Type" content=
|
||||
"text/html; charset=us-ascii"><!--
|
||||
This document is self-contained, *except* that there is one relative link to
|
||||
the ncurses-intro.html document, expected to be in the same directory with
|
||||
this one.
|
||||
-->
|
||||
</head>
|
||||
<body>
|
||||
<h1 class="no-header">A Hacker's Guide to NCURSES</h1>
|
||||
|
||||
<h2>A Hacker's Guide to NCURSES</h2>
|
||||
|
||||
<div class="nav">
|
||||
<h2>Contents</h2>
|
||||
|
||||
<ul>
|
||||
<li><a href="#abstract">Abstract</a></li>
|
||||
|
||||
<li>
|
||||
<a href="#objective">Objective of the Package</a>
|
||||
<ul>
|
||||
<li><a href="#whysvr4">Why System V Curses?</a></li>
|
||||
|
||||
<li><a href="#extensions">How to Design Extensions</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li><a href="#portability">Portability and Configuration</a></li>
|
||||
|
||||
<li><a href="#documentation">Documentation Conventions</a></li>
|
||||
|
||||
<li><a href="#bugtrack">How to Report Bugs</a></li>
|
||||
|
||||
<li>
|
||||
<a href="#ncurslib">A Tour of the Ncurses Library</a>
|
||||
<ul>
|
||||
<li><a href="#loverview">Library Overview</a></li>
|
||||
|
||||
<li><a href="#engine">The Engine Room</a></li>
|
||||
|
||||
<li><a href="#input">Keyboard Input</a></li>
|
||||
|
||||
<li><a href="#mouse">Mouse Events</a></li>
|
||||
|
||||
<li><a href="#output">Output and Screen Updating</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li><a href="#fmnote">The Forms and Menu Libraries</a></li>
|
||||
|
||||
<li>
|
||||
<a href="#tic">A Tour of the Terminfo Compiler</a>
|
||||
<ul>
|
||||
<li><a href="#nonuse">Translation of
|
||||
Non-<strong>use</strong> Capabilities</a></li>
|
||||
|
||||
<li><a href="#uses">Use Capability Resolution</a></li>
|
||||
|
||||
<li><a href="#translation">Source-Form Translation</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li><a href="#utils">Other Utilities</a></li>
|
||||
|
||||
<li><a href="#style">Style Tips for Developers</a></li>
|
||||
|
||||
<li><a href="#port">Porting Hints</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<h2><a name="abstract" id="abstract">Abstract</a></h2>
|
||||
|
||||
<p>This document is a hacker's tour of the
|
||||
<strong>ncurses</strong> library and utilities. It discusses
|
||||
design philosophy, implementation methods, and the conventions
|
||||
used for coding and documentation. It is recommended reading for
|
||||
anyone who is interested in porting, extending or improving the
|
||||
package.</p>
|
||||
|
||||
<h2><a name="objective" id="objective">Objective of the
|
||||
Package</a></h2>
|
||||
|
||||
<p>The objective of the <strong>ncurses</strong> package is to
|
||||
provide a free software API for character-cell terminals and
|
||||
terminal emulators with the following characteristics:</p>
|
||||
|
||||
<ul>
|
||||
<li>Source-compatible with historical curses implementations
|
||||
(including the original BSD curses and System V curses.</li>
|
||||
|
||||
<li>Conformant with the XSI Curses standard issued as part of
|
||||
XPG4 by X/Open.</li>
|
||||
|
||||
<li>High-quality — stable and reliable code, wide
|
||||
portability, good packaging, superior documentation.</li>
|
||||
|
||||
<li>Featureful — should eliminate as much of the drudgery
|
||||
of C interface programming as possible, freeing programmers to
|
||||
think at a higher level of design.</li>
|
||||
</ul>
|
||||
|
||||
<p>These objectives are in priority order. So, for example,
|
||||
source compatibility with older version must trump featurefulness
|
||||
— we cannot add features if it means breaking the portion
|
||||
of the API corresponding to historical curses versions.</p>
|
||||
|
||||
<h3><a name="whysvr4" id="whysvr4">Why System V Curses?</a></h3>
|
||||
|
||||
<p>We used System V curses as a model, reverse-engineering their
|
||||
API, in order to fulfill the first two objectives.</p>
|
||||
|
||||
<p>System V curses implementations can support BSD curses
|
||||
programs with just a recompilation, so by capturing the System V
|
||||
API we also capture BSD's.</p>
|
||||
|
||||
<p>More importantly for the future, the XSI Curses standard
|
||||
issued by X/Open is explicitly and closely modeled on System V.
|
||||
So conformance with System V took us most of the way to
|
||||
base-level XSI conformance.</p>
|
||||
|
||||
<h3><a name="extensions" id="extensions">How to Design
|
||||
Extensions</a></h3>
|
||||
|
||||
<p>The third objective (standards conformance) requires that it
|
||||
be easy to condition source code using <strong>ncurses</strong>
|
||||
so that the absence of nonstandard extensions does not break the
|
||||
code.</p>
|
||||
|
||||
<p>Accordingly, we have a policy of associating with each
|
||||
nonstandard extension a feature macro, so that ncurses client
|
||||
code can use this macro to condition in or out the code that
|
||||
requires the <strong>ncurses</strong> extension.</p>
|
||||
|
||||
<p>For example, there is a macro
|
||||
<code>NCURSES_MOUSE_VERSION</code> which XSI Curses does not
|
||||
define, but which is defined in the <strong>ncurses</strong>
|
||||
library header. You can use this to condition the calls to the
|
||||
mouse API calls.</p>
|
||||
|
||||
<h2><a name="portability" id="portability">Portability and
|
||||
Configuration</a></h2>
|
||||
|
||||
<p>Code written for <strong>ncurses</strong> may assume an
|
||||
ANSI-standard C compiler and POSIX-compatible OS interface. It
|
||||
may also assume the presence of a System-V-compatible
|
||||
<em>select(2)</em> call.</p>
|
||||
|
||||
<p>We encourage (but do not require) developers to make the code
|
||||
friendly to less-capable UNIX environments wherever possible.</p>
|
||||
|
||||
<p>We encourage developers to support OS-specific optimizations
|
||||
and methods not available under POSIX/ANSI, provided only
|
||||
that:</p>
|
||||
|
||||
<ul>
|
||||
<li>All such code is properly conditioned so the build process
|
||||
does not attempt to compile it under a plain ANSI/POSIX
|
||||
environment.</li>
|
||||
|
||||
<li>Adding such implementation methods does not introduce
|
||||
incompatibilities in the <strong>ncurses</strong> API between
|
||||
platforms.</li>
|
||||
</ul>
|
||||
|
||||
<p>We use GNU <code>autoconf(1)</code> as a tool to deal with
|
||||
portability issues. The right way to leverage an OS-specific
|
||||
feature is to modify the autoconf specification files
|
||||
(configure.in and aclocal.m4) to set up a new feature macro,
|
||||
which you then use to condition your code.</p>
|
||||
|
||||
<h2><a name="documentation" id="documentation">Documentation
|
||||
Conventions</a></h2>
|
||||
|
||||
<p>There are three kinds of documentation associated with this
|
||||
package. Each has a different preferred format:</p>
|
||||
|
||||
<ul>
|
||||
<li>Package-internal files (README, INSTALL, TO-DO etc.)</li>
|
||||
|
||||
<li>Manual pages.</li>
|
||||
|
||||
<li>Everything else (i.e., narrative documentation).</li>
|
||||
</ul>
|
||||
|
||||
<p>Our conventions are simple:</p>
|
||||
|
||||
<ol>
|
||||
<li><strong>Maintain package-internal files in plain
|
||||
text.</strong> The expected viewer for them is <em>more(1)</em> or
|
||||
an editor window; there is no point in elaborate mark-up.</li>
|
||||
|
||||
<li><strong>Mark up manual pages in the man macros.</strong>
|
||||
These have to be viewable through traditional <em>man(1)</em>
|
||||
programs.</li>
|
||||
|
||||
<li><strong>Write everything else in HTML.</strong>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<p>When in doubt, HTMLize a master and use <em>lynx(1)</em> to
|
||||
generate plain ASCII (as we do for the announcement
|
||||
document).</p>
|
||||
|
||||
<p>The reason for choosing HTML is that it is (a) well-adapted
|
||||
for on-line browsing through viewers that are everywhere; (b)
|
||||
more easily readable as plain text than most other mark-ups, if
|
||||
you do not have a viewer; and (c) carries enough information that
|
||||
you can generate a nice-looking printed version from it. Also, of
|
||||
course, it make exporting things like the announcement document
|
||||
to WWW pretty trivial.</p>
|
||||
|
||||
<h2><a name="bugtrack" id="bugtrack">How to Report Bugs</a></h2>
|
||||
|
||||
<p>The <a name="bugreport" id="bugreport">reporting address for
|
||||
bugs</a> is <a href=
|
||||
"mailto:bug-ncurses@gnu.org">bug-ncurses@gnu.org</a>. This is a
|
||||
majordomo list; to join, write to
|
||||
<code>bug-ncurses-request@gnu.org</code> with a message
|
||||
containing the line:</p>
|
||||
|
||||
<pre class="code-block">
|
||||
subscribe <name>@<host.domain>
|
||||
</pre>
|
||||
<p>The <code>ncurses</code> code is maintained by a small group
|
||||
of volunteers. While we try our best to fix bugs promptly, we
|
||||
simply do not have a lot of hours to spend on elementary
|
||||
hand-holding. We rely on intelligent cooperation from our users.
|
||||
If you think you have found a bug in <code>ncurses</code>, there
|
||||
are some steps you can take before contacting us that will help
|
||||
get the bug fixed quickly.</p>
|
||||
|
||||
<p>In order to use our bug-fixing time efficiently, we put people
|
||||
who show us they have taken these steps at the head of our queue.
|
||||
This means that if you do not, you will probably end up at the
|
||||
tail end and have to wait a while.</p>
|
||||
|
||||
<ol>
|
||||
<li><p>Develop a recipe to reproduce the bug.
|
||||
<p>Bugs we can reproduce are likely to be fixed very quickly,
|
||||
often within days. The most effective single thing you can do
|
||||
to get a quick fix is develop a way we can duplicate the bad
|
||||
behavior — ideally, by giving us source for a small,
|
||||
portable test program that breaks the library. (Even better
|
||||
is a keystroke recipe using one of the test programs provided
|
||||
with the distribution.)</p>
|
||||
</li>
|
||||
|
||||
<li><p>Try to reproduce the bug on a different terminal type.
|
||||
<p>In our experience, most of the behaviors people report as
|
||||
library bugs are actually due to subtle problems in terminal
|
||||
descriptions. This is especially likely to be true if you are
|
||||
using a traditional asynchronous terminal or PC-based
|
||||
terminal emulator, rather than xterm or a UNIX console
|
||||
entry.</p>
|
||||
|
||||
<p>It is therefore extremely helpful if you can tell us
|
||||
whether or not your problem reproduces on other terminal
|
||||
types. Usually you will have both a console type and xterm
|
||||
available; please tell us whether or not your bug reproduces
|
||||
on both.</p>
|
||||
|
||||
<p>If you have xterm available, it is also good to collect
|
||||
xterm reports for different window sizes. This is especially
|
||||
true if you normally use an unusual xterm window size —
|
||||
a surprising number of the bugs we have seen are either
|
||||
triggered or masked by these.</p>
|
||||
</li>
|
||||
|
||||
<li><p>Generate and examine a trace file for the broken behavior.
|
||||
<p>Recompile your program with the debugging versions of the
|
||||
libraries. Insert a <code>trace()</code> call with the
|
||||
argument set to <code>TRACE_UPDATE</code>. (See <a href=
|
||||
"ncurses-intro.html#debugging">"Writing Programs with
|
||||
NCURSES"</a> for details on trace levels.) Reproduce your
|
||||
bug, then look at the trace file to see what the library was
|
||||
actually doing.</p>
|
||||
|
||||
<p>Another frequent cause of apparent bugs is application
|
||||
coding errors that cause the wrong things to be put on the
|
||||
virtual screen. Looking at the virtual-screen dumps in the
|
||||
trace file will tell you immediately if this is happening,
|
||||
and save you from the possible embarrassment of being told
|
||||
that the bug is in your code and is your problem rather than
|
||||
ours.</p>
|
||||
|
||||
<p>If the virtual-screen dumps look correct but the bug
|
||||
persists, it is possible to crank up the trace level to give
|
||||
more and more information about the library's update actions
|
||||
and the control sequences it issues to perform them. The test
|
||||
directory of the distribution contains a tool for digesting
|
||||
these logs to make them less tedious to wade through.</p>
|
||||
|
||||
<p>Often you will find terminfo problems at this stage by
|
||||
noticing that the escape sequences put out for various
|
||||
capabilities are wrong. If not, you are likely to learn
|
||||
enough to be able to characterize any bug in the
|
||||
screen-update logic quite exactly.</p>
|
||||
</li>
|
||||
|
||||
<li><p>Report details and symptoms, not just interpretations.
|
||||
<p>If you do the preceding two steps, it is very likely that
|
||||
you will discover the nature of the problem yourself and be
|
||||
able to send us a fix. This will create happy feelings all
|
||||
around and earn you good karma for the first time you run
|
||||
into a bug you really cannot characterize and fix
|
||||
yourself.</p>
|
||||
|
||||
<p>If you are still stuck, at least you will know what to
|
||||
tell us. Remember, we need details. If you guess about what
|
||||
is safe to leave out, you are too likely to be wrong.</p>
|
||||
|
||||
<p>If your bug produces a bad update, include a trace file.
|
||||
Try to make the trace at the <em>least</em> voluminous level
|
||||
that pins down the bug. Logs that have been through
|
||||
tracemunch are OK, it does not throw away any information
|
||||
(actually they are better than un-munched ones because they
|
||||
are easier to read).</p>
|
||||
|
||||
<p>If your bug produces a core-dump, please include a
|
||||
symbolic stack trace generated by gdb(1) or your local
|
||||
equivalent.</p>
|
||||
|
||||
<p>Tell us about every terminal on which you have reproduced
|
||||
the bug — and every terminal on which you cannot.
|
||||
Ideally, send us terminfo sources for all of these (yours
|
||||
might differ from ours).</p>
|
||||
|
||||
<p>Include your ncurses version and your OS/machine type, of
|
||||
course! You can find your ncurses version in the
|
||||
<code>curses.h</code> file.</p>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<p>If your problem smells like a logic error or in cursor
|
||||
movement or scrolling or a bad capability, there are a couple of
|
||||
tiny test frames for the library algorithms in the progs
|
||||
directory that may help you isolate it. These are not part of the
|
||||
normal build, but do have their own make productions.</p>
|
||||
|
||||
<p>The most important of these is <code>mvcur</code>, a test
|
||||
frame for the cursor-movement optimization code. With this
|
||||
program, you can see directly what control sequences will be
|
||||
emitted for any given cursor movement or scroll/insert/delete
|
||||
operations. If you think you have got a bad capability
|
||||
identified, you can disable it and test again. The program is
|
||||
command-driven and has on-line help.</p>
|
||||
|
||||
<p>If you think the vertical-scroll optimization is broken, or
|
||||
just want to understand how it works better, build
|
||||
<code>hashmap</code> and read the header comments of
|
||||
<code>hardscroll.c</code> and <code>hashmap.c</code>; then try it
|
||||
out. You can also test the hardware-scrolling optimization
|
||||
separately with <code>hardscroll</code>.</p>
|
||||
|
||||
<h2><a name="ncurslib" id="ncurslib">A Tour of the Ncurses
|
||||
Library</a></h2>
|
||||
|
||||
<h3><a name="loverview" id="loverview">Library Overview</a></h3>
|
||||
|
||||
<p>Most of the library is superstructure — fairly trivial
|
||||
convenience interfaces to a small set of basic functions and data
|
||||
structures used to manipulate the virtual screen (in particular,
|
||||
none of this code does any I/O except through calls to more
|
||||
fundamental modules described below). The files</p>
|
||||
|
||||
<blockquote>
|
||||
<code>lib_addch.c lib_bkgd.c lib_box.c lib_chgat.c lib_clear.c
|
||||
lib_clearok.c lib_clrbot.c lib_clreol.c lib_colorset.c
|
||||
lib_data.c lib_delch.c lib_delwin.c lib_echo.c lib_erase.c
|
||||
lib_gen.c lib_getstr.c lib_hline.c lib_immedok.c lib_inchstr.c
|
||||
lib_insch.c lib_insdel.c lib_insstr.c lib_instr.c
|
||||
lib_isendwin.c lib_keyname.c lib_leaveok.c lib_move.c
|
||||
lib_mvwin.c lib_overlay.c lib_pad.c lib_printw.c lib_redrawln.c
|
||||
lib_scanw.c lib_screen.c lib_scroll.c lib_scrollok.c
|
||||
lib_scrreg.c lib_set_term.c lib_slk.c lib_slkatr_set.c
|
||||
lib_slkatrof.c lib_slkatron.c lib_slkatrset.c lib_slkattr.c
|
||||
lib_slkclear.c lib_slkcolor.c lib_slkinit.c lib_slklab.c
|
||||
lib_slkrefr.c lib_slkset.c lib_slktouch.c lib_touch.c
|
||||
lib_unctrl.c lib_vline.c lib_wattroff.c lib_wattron.c
|
||||
lib_window.c</code>
|
||||
</blockquote>
|
||||
|
||||
<p>are all in this category. They are very unlikely to need
|
||||
change, barring bugs or some fundamental reorganization in the
|
||||
underlying data structures.</p>
|
||||
|
||||
<p>These files are used only for debugging support:</p>
|
||||
|
||||
<blockquote>
|
||||
<code>lib_trace.c lib_traceatr.c lib_tracebits.c lib_tracechr.c
|
||||
lib_tracedmp.c lib_tracemse.c trace_buf.c</code>
|
||||
</blockquote>
|
||||
|
||||
<p>It is rather unlikely you will ever need to change these,
|
||||
unless you want to introduce a new debug trace level for some
|
||||
reason.</p>
|
||||
|
||||
<p>There is another group of files that do direct I/O via
|
||||
<em>tputs()</em>, computations on the terminal capabilities, or
|
||||
queries to the OS environment, but nevertheless have only fairly
|
||||
low complexity. These include:</p>
|
||||
|
||||
<blockquote>
|
||||
<code>lib_acs.c lib_beep.c lib_color.c lib_endwin.c
|
||||
lib_initscr.c lib_longname.c lib_newterm.c lib_options.c
|
||||
lib_termcap.c lib_ti.c lib_tparm.c lib_tputs.c lib_vidattr.c
|
||||
read_entry.c.</code>
|
||||
</blockquote>
|
||||
|
||||
<p>They are likely to need revision only if ncurses is being
|
||||
ported to an environment without an underlying terminfo
|
||||
capability representation.</p>
|
||||
|
||||
<p>These files have serious hooks into the tty driver and signal
|
||||
facilities:</p>
|
||||
|
||||
<blockquote>
|
||||
<code>lib_kernel.c lib_baudrate.c lib_raw.c lib_tstp.c
|
||||
lib_twait.c</code>
|
||||
</blockquote>
|
||||
|
||||
<p>If you run into porting snafus moving the package to another
|
||||
UNIX, the problem is likely to be in one of these files. The file
|
||||
<code>lib_print.c</code> uses sleep(2) and also falls in this
|
||||
category.</p>
|
||||
|
||||
<p>Almost all of the real work is done in the files</p>
|
||||
|
||||
<blockquote>
|
||||
<code>hardscroll.c hashmap.c lib_addch.c lib_doupdate.c
|
||||
lib_getch.c lib_mouse.c lib_mvcur.c lib_refresh.c lib_setup.c
|
||||
lib_vidattr.c</code>
|
||||
</blockquote>
|
||||
|
||||
<p>Most of the algorithmic complexity in the library lives in
|
||||
these files. If there is a real bug in <strong>ncurses</strong>
|
||||
itself, it is probably here. We will tour some of these files in
|
||||
detail below (see <a href="#engine">The Engine Room</a>).</p>
|
||||
|
||||
<p>Finally, there is a group of files that is actually most of
|
||||
the terminfo compiler. The reason this code lives in the
|
||||
<strong>ncurses</strong> library is to support fallback to
|
||||
/etc/termcap. These files include</p>
|
||||
|
||||
<blockquote>
|
||||
<code>alloc_entry.c captoinfo.c comp_captab.c comp_error.c
|
||||
comp_hash.c comp_parse.c comp_scan.c parse_entry.c
|
||||
read_termcap.c write_entry.c</code>
|
||||
</blockquote>
|
||||
|
||||
<p>We will discuss these in the compiler tour.</p>
|
||||
|
||||
<h3><a name="engine" id="engine">The Engine Room</a></h3>
|
||||
|
||||
<h4><a name="input" id="input">Keyboard Input</a></h4>
|
||||
|
||||
<p>All <code>ncurses</code> input funnels through the function
|
||||
<code>wgetch()</code>, defined in <code>lib_getch.c</code>. This
|
||||
function is tricky; it has to poll for keyboard and mouse events
|
||||
and do a running match of incoming input against the set of
|
||||
defined special keys.</p>
|
||||
|
||||
<p>The central data structure in this module is a FIFO queue,
|
||||
used to match multiple-character input sequences against
|
||||
special-key capabilities; also to implement pushback via
|
||||
<code>ungetch()</code>.</p>
|
||||
|
||||
<p>The <code>wgetch()</code> code distinguishes between function
|
||||
key sequences and the same sequences typed manually by doing a
|
||||
timed wait after each input character that could lead a function
|
||||
key sequence. If the entire sequence takes less than 1 second, it
|
||||
is assumed to have been generated by a function key press.</p>
|
||||
|
||||
<p>Hackers bruised by previous encounters with variant
|
||||
<code>select(2)</code> calls may find the code in
|
||||
<code>lib_twait.c</code> interesting. It deals with the problem
|
||||
that some BSD selects do not return a reliable time-left value.
|
||||
The function <code>timed_wait()</code> effectively simulates a
|
||||
System V select.</p>
|
||||
|
||||
<h4><a name="mouse" id="mouse">Mouse Events</a></h4>
|
||||
|
||||
<p>If the mouse interface is active, <code>wgetch()</code> polls
|
||||
for mouse events each call, before it goes to the keyboard for
|
||||
input. It is up to <code>lib_mouse.c</code> how the polling is
|
||||
accomplished; it may vary for different devices.</p>
|
||||
|
||||
<p>Under xterm, however, mouse event notifications come in via
|
||||
the keyboard input stream. They are recognized by having the
|
||||
<strong>kmous</strong> capability as a prefix. This is kind of
|
||||
klugey, but trying to wire in recognition of a mouse key prefix
|
||||
without going through the function-key machinery would be just
|
||||
too painful, and this turns out to imply having the prefix
|
||||
somewhere in the function-key capabilities at terminal-type
|
||||
initialization.</p>
|
||||
|
||||
<p>This kluge only works because <strong>kmous</strong> is not
|
||||
actually used by any historic terminal type or curses
|
||||
implementation we know of. Best guess is it is a relic of some
|
||||
forgotten experiment in-house at Bell Labs that did not leave any
|
||||
traces in the publicly-distributed System V terminfo files. If
|
||||
System V or XPG4 ever gets serious about using it again, this
|
||||
kluge may have to change.</p>
|
||||
|
||||
<p>Here are some more details about mouse event handling:</p>
|
||||
|
||||
<p>The <code>lib_mouse()</code> code is logically split into a
|
||||
lower level that accepts event reports in a device-dependent
|
||||
format and an upper level that parses mouse gestures and filters
|
||||
events. The mediating data structure is a circular queue of event
|
||||
structures.</p>
|
||||
|
||||
<p>Functionally, the lower level's job is to pick up primitive
|
||||
events and put them on the circular queue. This can happen in one
|
||||
of two ways: either (a) <code>_nc_mouse_event()</code> detects a
|
||||
series of incoming mouse reports and queues them, or (b) code in
|
||||
<code>lib_getch.c</code> detects the <strong>kmous</strong>
|
||||
prefix in the keyboard input stream and calls _nc_mouse_inline to
|
||||
queue up a series of adjacent mouse reports.</p>
|
||||
|
||||
<p>In either case, <code>_nc_mouse_parse()</code> should be
|
||||
called after the series is accepted to parse the digested mouse
|
||||
reports (low-level events) into a gesture (a high-level or
|
||||
composite event).</p>
|
||||
|
||||
<h4><a name="output" id="output">Output and Screen Updating</a></h4>
|
||||
|
||||
<p>With the single exception of character echoes during a
|
||||
<code>wgetnstr()</code> call (which simulates cooked-mode line
|
||||
editing in an ncurses window), the library normally does all its
|
||||
output at refresh time.</p>
|
||||
|
||||
<p>The main job is to go from the current state of the screen (as
|
||||
represented in the <code>curscr</code> window structure) to the
|
||||
desired new state (as represented in the <code>newscr</code>
|
||||
window structure), while doing as little I/O as possible.</p>
|
||||
|
||||
<p>The brains of this operation are the modules
|
||||
<code>hashmap.c</code>, <code>hardscroll.c</code> and
|
||||
<code>lib_doupdate.c</code>; the latter two use
|
||||
<code>lib_mvcur.c</code>. Essentially, what happens looks like
|
||||
this:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>The <code>hashmap.c</code> module tries to detect vertical
|
||||
motion changes between the real and virtual screens. This
|
||||
information is represented by the oldindex members in the
|
||||
newscr structure. These are modified by vertical-motion and
|
||||
clear operations, and both are re-initialized after each
|
||||
update. To this change-journalling information, the hashmap
|
||||
code adds deductions made using a modified Heckel algorithm
|
||||
on hash values generated from the line contents.</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<p>The <code>hardscroll.c</code> module computes an optimum
|
||||
set of scroll, insertion, and deletion operations to make the
|
||||
indices match. It calls <code>_nc_mvcur_scrolln()</code> in
|
||||
<code>lib_mvcur.c</code> to do those motions.</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<p>Then <code>lib_doupdate.c</code> goes to work. Its job is
|
||||
to do line-by-line transformations of <code>curscr</code>
|
||||
lines to <code>newscr</code> lines. Its main tool is the
|
||||
routine <code>mvcur()</code> in <code>lib_mvcur.c</code>.
|
||||
This routine does cursor-movement optimization, attempting to
|
||||
get from given screen location A to given location B in the
|
||||
fewest output characters possible.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>If you want to work on screen optimizations, you should use
|
||||
the fact that (in the trace-enabled version of the library)
|
||||
enabling the <code>TRACE_TIMES</code> trace level causes a report
|
||||
to be emitted after each screen update giving the elapsed time
|
||||
and a count of characters emitted during the update. You can use
|
||||
this to tell when an update optimization improves efficiency.</p>
|
||||
|
||||
<p>In the trace-enabled version of the library, it is also
|
||||
possible to disable and re-enable various optimizations at
|
||||
runtime by tweaking the variable
|
||||
<code>_nc_optimize_enable</code>. See the file
|
||||
<code>include/curses.h.in</code> for mask values, near the
|
||||
end.</p>
|
||||
|
||||
<h2><a name="fmnote" id="fmnote">The Forms and Menu Libraries</a></h2>
|
||||
|
||||
<p>The forms and menu libraries should work reliably in any
|
||||
environment you can port ncurses to. The only portability issue
|
||||
anywhere in them is what flavor of regular expressions the
|
||||
built-in form field type TYPE_REGEXP will recognize.</p>
|
||||
|
||||
<p>The configuration code prefers the POSIX regex facility,
|
||||
modeled on System V's, but will settle for BSD regexps if the
|
||||
former is not available.</p>
|
||||
|
||||
<p>Historical note: the panels code was written primarily to
|
||||
assist in porting u386mon 2.0 (comp.sources.misc v14i001-4) to
|
||||
systems lacking panels support; u386mon 2.10 and beyond use it.
|
||||
This version has been slightly cleaned up for
|
||||
<code>ncurses</code>.</p>
|
||||
|
||||
<h2><a name="tic" id="tic">A Tour of the Terminfo Compiler</a></h2>
|
||||
|
||||
<p>The <strong>ncurses</strong> implementation of
|
||||
<strong>tic</strong> is rather complex internally; it has to do a
|
||||
trying combination of missions. This starts with the fact that,
|
||||
in addition to its normal duty of compiling terminfo sources into
|
||||
loadable terminfo binaries, it has to be able to handle termcap
|
||||
syntax and compile that too into terminfo entries.</p>
|
||||
|
||||
<p>The implementation therefore starts with a table-driven,
|
||||
dual-mode lexical analyzer (in <code>comp_scan.c</code>). The
|
||||
lexer chooses its mode (termcap or terminfo) based on the first
|
||||
“,” or “:” it finds in each entry. The
|
||||
lexer does all the work of recognizing capability names and
|
||||
values; the grammar above it is trivial, just "parse entries till
|
||||
you run out of file".</p>
|
||||
|
||||
<h3><a name="nonuse" id="nonuse">Translation of
|
||||
Non-<strong>use</strong> Capabilities</a></h3>
|
||||
|
||||
<p>Translation of most things besides <strong>use</strong>
|
||||
capabilities is pretty straightforward. The lexical analyzer's
|
||||
tokenizer hands each capability name to a hash function, which
|
||||
drives a table lookup. The table entry yields an index which is
|
||||
used to look up the token type in another table, and controls
|
||||
interpretation of the value.</p>
|
||||
|
||||
<p>One possibly interesting aspect of the implementation is the
|
||||
way the compiler tables are initialized. All the tables are
|
||||
generated by various awk/sed/sh scripts from a master table
|
||||
<code>include/Caps</code>; these scripts actually write C
|
||||
initializers which are linked to the compiler. Furthermore, the
|
||||
hash table is generated in the same way, so it doesn't have to be
|
||||
generated at compiler startup time (another benefit of this
|
||||
organization is that the hash table can be in shareable text
|
||||
space).</p>
|
||||
|
||||
<p>Thus, adding a new capability is usually pretty trivial, just
|
||||
a matter of adding one line to the <code>include/Caps</code>
|
||||
file. We will have more to say about this in the section on
|
||||
<a href="#translation">Source-Form Translation</a>.</p>
|
||||
|
||||
<h3><a name="uses" id="uses">Use Capability Resolution</a></h3>
|
||||
|
||||
<p>The background problem that makes <strong>tic</strong> tricky
|
||||
is not the capability translation itself, it is the resolution of
|
||||
<strong>use</strong> capabilities. Older versions would not
|
||||
handle forward <strong>use</strong> references for this reason
|
||||
(that is, a using terminal always had to follow its use target in
|
||||
the source file). By doing this, they got away with a simple
|
||||
implementation tactic; compile everything as it blows by, then
|
||||
resolve uses from compiled entries.</p>
|
||||
|
||||
<p>This will not do for <strong>ncurses</strong>. The problem is
|
||||
that that the whole compilation process has to be embeddable in
|
||||
the <strong>ncurses</strong> library so that it can be called by
|
||||
the startup code to translate termcap entries on the fly. The
|
||||
embedded version cannot go promiscuously writing everything it
|
||||
translates out to disk — for one thing, it will typically
|
||||
be running with non-root permissions.</p>
|
||||
|
||||
<p>So our <strong>tic</strong> is designed to parse an entire
|
||||
terminfo file into a doubly-linked circular list of entry
|
||||
structures in-core, and then do <strong>use</strong> resolution
|
||||
in-memory before writing everything out. This design has other
|
||||
advantages: it makes forward and back use-references equally easy
|
||||
(so we get the latter for free), and it makes checking for name
|
||||
collisions before they are written out easy to do.</p>
|
||||
|
||||
<p>And this is exactly how the embedded version works. But the
|
||||
stand-alone user-accessible version of <strong>tic</strong>
|
||||
partly reverts to the historical strategy; it writes to disk (not
|
||||
keeping in core) any entry with no <strong>use</strong>
|
||||
references.</p>
|
||||
|
||||
<p>This is strictly a core-economy kluge, implemented because the
|
||||
terminfo master file is large enough that some core-poor systems
|
||||
swap like crazy when you compile it all in memory...there have
|
||||
been reports of this process taking <strong>three hours</strong>,
|
||||
rather than the twenty seconds or less typical on the author's
|
||||
development box.</p>
|
||||
|
||||
<p>So. The executable <strong>tic</strong> passes the
|
||||
entry-parser a hook that <em>immediately</em> writes out the
|
||||
referenced entry if it has no use capabilities. The compiler main
|
||||
loop refrains from adding the entry to the in-core list when this
|
||||
hook fires. If some other entry later needs to reference an entry
|
||||
that got written immediately, that is OK; the resolution code
|
||||
will fetch it off disk when it cannot find it in core.</p>
|
||||
|
||||
<p>Name collisions will still be detected, just not as cleanly.
|
||||
The <code>write_entry()</code> code complains before overwriting
|
||||
an entry that postdates the time of <strong>tic</strong>'s first
|
||||
call to <code>write_entry()</code>, Thus it will complain about
|
||||
overwriting entries newly made during the <strong>tic</strong>
|
||||
run, but not about overwriting ones that predate it.</p>
|
||||
|
||||
<h3><a name="translation" id="translation">Source-Form
|
||||
Translation</a></h3>
|
||||
|
||||
<p>Another use of <strong>tic</strong> is to do source
|
||||
translation between various termcap and terminfo formats. There
|
||||
are more variants out there than you might think; the ones we
|
||||
know about are described in the <strong>captoinfo(1)</strong>
|
||||
manual page.</p>
|
||||
|
||||
<p>The translation output code (<code>dump_entry()</code> in
|
||||
<code>ncurses/dump_entry.c</code>) is shared with the
|
||||
<strong>infocmp(1)</strong> utility. It takes the same internal
|
||||
representation used to generate the binary form and dumps it to
|
||||
standard output in a specified format.</p>
|
||||
|
||||
<p>The <code>include/Caps</code> file has a header comment
|
||||
describing ways you can specify source translations for
|
||||
nonstandard capabilities just by altering the master table. It is
|
||||
possible to set up capability aliasing or tell the compiler to
|
||||
plain ignore a given capability without writing any C code at
|
||||
all.</p>
|
||||
|
||||
<p>For circumstances where you need to do algorithmic
|
||||
translation, there are functions in <code>parse_entry.c</code>
|
||||
called after the parse of each entry that are specifically
|
||||
intended to encapsulate such translations. This, for example, is
|
||||
where the AIX <strong>box1</strong> capability get translated to
|
||||
an <strong>acsc</strong> string.</p>
|
||||
|
||||
<h2><a name="utils" id="utils">Other Utilities</a></h2>
|
||||
|
||||
<p>The <strong>infocmp</strong> utility is just a wrapper around
|
||||
the same entry-dumping code used by <strong>tic</strong> for
|
||||
source translation. Perhaps the one interesting aspect of the
|
||||
code is the use of a predicate function passed in to
|
||||
<code>dump_entry()</code> to control which capabilities are
|
||||
dumped. This is necessary in order to handle both the ordinary
|
||||
De-compilation case and entry difference reporting.</p>
|
||||
|
||||
<p>The <strong>tput</strong> and <strong>clear</strong> utilities
|
||||
just do an entry load followed by a <code>tputs()</code> of a
|
||||
selected capability.</p>
|
||||
|
||||
<h2><a name="style" id="style">Style Tips for Developers</a></h2>
|
||||
|
||||
<p>See the TO-DO file in the top-level directory of the source
|
||||
distribution for additions that would be particularly useful.</p>
|
||||
|
||||
<p>The prefix <code>_nc_</code> should be used on library public
|
||||
functions that are not part of the curses API in order to prevent
|
||||
pollution of the application namespace. If you have to add to or
|
||||
modify the function prototypes in curses.h.in, read
|
||||
ncurses/MKlib_gen.sh first so you can avoid breaking XSI
|
||||
conformance. Please join the ncurses mailing list. See the
|
||||
INSTALL file in the top level of the distribution for details on
|
||||
the list.</p>
|
||||
|
||||
<p>Look for the string <code>FIXME</code> in source files to tag
|
||||
minor bugs and potential problems that could use fixing.</p>
|
||||
|
||||
<p>Do not try to auto-detect OS features in the main body of the
|
||||
C code. That is the job of the configuration system.</p>
|
||||
|
||||
<p>To hold down complexity, do make your code data-driven.
|
||||
Especially, if you can drive logic from a table filtered out of
|
||||
<code>include/Caps</code>, do it. If you find you need to augment
|
||||
the data in that file in order to generate the proper table, that
|
||||
is still preferable to ad-hoc code — that is why the fifth
|
||||
field (flags) is there.</p>
|
||||
|
||||
<p>Have fun!</p>
|
||||
|
||||
<h2><a name="port" id="port">Porting Hints</a></h2>
|
||||
|
||||
<p>The following notes are intended to be a first step towards
|
||||
DOS and Macintosh ports of the ncurses libraries.</p>
|
||||
|
||||
<p>The following library modules are “pure curses”;
|
||||
they operate only on the curses internal structures, do all
|
||||
output through other curses calls (not including
|
||||
<code>tputs()</code> and <code>putp()</code>) and do not call any
|
||||
other UNIX routines such as signal(2) or the stdio library. Thus,
|
||||
they should not need to be modified for single-terminal
|
||||
ports.</p>
|
||||
|
||||
<blockquote>
|
||||
<code>lib_addch.c lib_addstr.c lib_bkgd.c lib_box.c lib_clear.c
|
||||
lib_clrbot.c lib_clreol.c lib_delch.c lib_delwin.c lib_erase.c
|
||||
lib_inchstr.c lib_insch.c lib_insdel.c lib_insstr.c
|
||||
lib_keyname.c lib_move.c lib_mvwin.c lib_newwin.c lib_overlay.c
|
||||
lib_pad.c lib_printw.c lib_refresh.c lib_scanw.c lib_scroll.c
|
||||
lib_scrreg.c lib_set_term.c lib_touch.c lib_tparm.c lib_tputs.c
|
||||
lib_unctrl.c lib_window.c panel.c</code>
|
||||
</blockquote>
|
||||
|
||||
<p>This module is pure curses, but calls outstr():</p>
|
||||
|
||||
<blockquote>
|
||||
<code>lib_getstr.c</code>
|
||||
</blockquote>
|
||||
|
||||
<p>These modules are pure curses, except that they use
|
||||
<code>tputs()</code> and <code>putp()</code>:</p>
|
||||
|
||||
<blockquote>
|
||||
<code>lib_beep.c lib_color.c lib_endwin.c lib_options.c
|
||||
lib_slk.c lib_vidattr.c</code>
|
||||
</blockquote>
|
||||
|
||||
<p>This modules assist in POSIX emulation on non-POSIX
|
||||
systems:</p>
|
||||
|
||||
<dl>
|
||||
<dt>sigaction.c</dt>
|
||||
|
||||
<dd>signal calls</dd>
|
||||
</dl>
|
||||
|
||||
<p>The following source files will not be needed for a
|
||||
single-terminal-type port.</p>
|
||||
|
||||
<blockquote>
|
||||
<code>alloc_entry.c captoinfo.c clear.c comp_captab.c
|
||||
comp_error.c comp_hash.c comp_main.c comp_parse.c comp_scan.c
|
||||
dump_entry.c infocmp.c parse_entry.c read_entry.c tput.c
|
||||
write_entry.c</code>
|
||||
</blockquote>
|
||||
|
||||
<p>The following modules will use
|
||||
open()/read()/write()/close()/lseek() on files, but no other OS
|
||||
calls.</p>
|
||||
|
||||
<dl>
|
||||
<dt>lib_screen.c</dt>
|
||||
|
||||
<dd>used to read/write screen dumps</dd>
|
||||
|
||||
<dt>lib_trace.c</dt>
|
||||
|
||||
<dd>used to write trace data to the logfile</dd>
|
||||
</dl>
|
||||
|
||||
<p>Modules that would have to be modified for a port start
|
||||
here:</p>
|
||||
|
||||
<p>The following modules are “pure curses” but
|
||||
contain assumptions inappropriate for a memory-mapped port.</p>
|
||||
|
||||
<dl>
|
||||
<dt>lib_longname.c</dt>
|
||||
|
||||
<dd>assumes there may be multiple terminals</dd>
|
||||
|
||||
<dt>lib_acs.c</dt>
|
||||
|
||||
<dd>assumes acs_map as a double indirection</dd>
|
||||
|
||||
<dt>lib_mvcur.c</dt>
|
||||
|
||||
<dd>assumes cursor moves have variable cost</dd>
|
||||
|
||||
<dt>lib_termcap.c</dt>
|
||||
|
||||
<dd>assumes there may be multiple terminals</dd>
|
||||
|
||||
<dt>lib_ti.c</dt>
|
||||
|
||||
<dd>assumes there may be multiple terminals</dd>
|
||||
</dl>
|
||||
|
||||
<p>The following modules use UNIX-specific calls:</p>
|
||||
|
||||
<dl>
|
||||
<dt>lib_doupdate.c</dt>
|
||||
|
||||
<dd>input checking</dd>
|
||||
|
||||
<dt>lib_getch.c</dt>
|
||||
|
||||
<dd>read()</dd>
|
||||
|
||||
<dt>lib_initscr.c</dt>
|
||||
|
||||
<dd>getenv()</dd>
|
||||
|
||||
<dt>lib_newterm.c</dt>
|
||||
|
||||
<dt>lib_baudrate.c</dt>
|
||||
|
||||
<dt>lib_kernel.c</dt>
|
||||
|
||||
<dd>various tty-manipulation and system calls</dd>
|
||||
|
||||
<dt>lib_raw.c</dt>
|
||||
|
||||
<dd>various tty-manipulation calls</dd>
|
||||
|
||||
<dt>lib_setup.c</dt>
|
||||
|
||||
<dd>various tty-manipulation calls</dd>
|
||||
|
||||
<dt>lib_restart.c</dt>
|
||||
|
||||
<dd>various tty-manipulation calls</dd>
|
||||
|
||||
<dt>lib_tstp.c</dt>
|
||||
|
||||
<dd>signal-manipulation calls</dd>
|
||||
|
||||
<dt>lib_twait.c</dt>
|
||||
|
||||
<dd>gettimeofday(), select().</dd>
|
||||
</dl>
|
||||
|
||||
<hr>
|
||||
|
||||
<address>
|
||||
Eric S. Raymond <esr@snark.thyrsus.com>
|
||||
</address>
|
||||
(Note: This is <em>not</em> the <a href="#bugtrack">bug
|
||||
address</a>!)
|
||||
</body>
|
||||
</html>
|
3390
contrib/ncurses/doc/html/ncurses-intro.html
Normal file
3390
contrib/ncurses/doc/html/ncurses-intro.html
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user