diff options
Diffstat (limited to 'doc/html/hackguide.html')
-rw-r--r-- | doc/html/hackguide.html | 1815 |
1 files changed, 935 insertions, 880 deletions
diff --git a/doc/html/hackguide.html b/doc/html/hackguide.html index 8437080..71312a5 100644 --- a/doc/html/hackguide.html +++ b/doc/html/hackguide.html @@ -1,8 +1,8 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"> <!-- - $Id: hackguide.html,v 1.29 2013/05/17 23:29:18 tom Exp $ + $Id: hackguide.html,v 1.33 2020/02/02 23:34:34 tom Exp $ **************************************************************************** - * Copyright (c) 1998-2010,2012 Free Software Foundation, Inc. * + * Copyright 2019,2020 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 * @@ -29,886 +29,941 @@ * authorization. * **************************************************************************** --> -<HTML> -<HEAD> -<TITLE>A Hacker's Guide to Ncurses Internals</TITLE> -<link rev="made" href="mailto:bugs-ncurses@gnu.org"> -<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> -<!-- +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"> + +<html> +<head> + <meta name="generator" content= + "HTML Tidy for HTML5 for Linux version 5.2.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>A Hacker's Guide to NCURSES</H1> - -<H1>Contents</H1> -<UL> -<LI><A HREF="#abstract">Abstract</A> -<LI><A HREF="#objective">Objective of the Package</A> -<UL> -<LI><A HREF="#whysvr4">Why System V Curses?</A> -<LI><A HREF="#extensions">How to Design Extensions</A> -</UL> -<LI><A HREF="#portability">Portability and Configuration</A> -<LI><A HREF="#documentation">Documentation Conventions</A> -<LI><A HREF="#bugtrack">How to Report Bugs</A> -<LI><A HREF="#ncurslib">A Tour of the Ncurses Library</A> -<UL> -<LI><A HREF="#loverview">Library Overview</A> -<LI><A HREF="#engine">The Engine Room</A> -<LI><A HREF="#input">Keyboard Input</A> -<LI><A HREF="#mouse">Mouse Events</A> -<LI><A HREF="#output">Output and Screen Updating</A> -</UL> -<LI><A HREF="#fmnote">The Forms and Menu Libraries</A> -<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><A HREF="#uses">Use Capability Resolution</A> -<LI><A HREF="#translation">Source-Form Translation</A> -</UL> -<LI><A HREF="#utils">Other Utilities</A> -<LI><A HREF="#style">Style Tips for Developers</A> -<LI><A HREF="#port">Porting Hints</A> -</UL> - -<H1><A NAME="abstract">Abstract</A></H1> - -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. - -<H1><A NAME="objective">Objective of the Package</A></H1> - -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: - -<UL> -<LI>Source-compatible with historical curses implementations (including - the original BSD curses and System V curses. -<LI>Conformant with the XSI Curses standard issued as part of XPG4 by - X/Open. -<LI>High-quality -- stable and reliable code, wide portability, good - packaging, superior documentation. -<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. -</UL> - -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. - -<H2><A NAME="whysvr4">Why System V Curses?</A></H2> - -We used System V curses as a model, reverse-engineering their API, in -order to fulfill the first two objectives. <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> - -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. - -<H2><A NAME="extensions">How to Design Extensions</A></H2> - -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> - -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> - -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. - -<H1><A NAME="portability">Portability and Configuration</A></H1> - -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> - -We encourage (but do not require) developers to make the code friendly -to less-capable UNIX environments wherever possible. <P> - -We encourage developers to support OS-specific optimizations and methods -not available under POSIX/ANSI, provided only that: - -<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>Adding such implementation methods does not introduce incompatibilities - in the <STRONG>ncurses</STRONG> API between platforms. -</UL> - -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. - -<H1><A NAME="documentation">Documentation Conventions</A></H1> - -There are three kinds of documentation associated with this package. Each -has a different preferred format: - -<UL> -<LI>Package-internal files (README, INSTALL, TO-DO etc.) -<LI>Manual pages. -<LI>Everything else (i.e., narrative documentation). -</UL> - -Our conventions are simple: -<OL> -<LI><STRONG>Maintain package-internal files in plain text.</STRONG> - The expected viewer for them <EM>more(1)</EM> or an editor window; there's - no point in elaborate mark-up. - -<LI><STRONG>Mark up manual pages in the man macros.</STRONG> These have to be viewable - through traditional <EM>man(1)</EM> programs. - -<LI><STRONG>Write everything else in HTML.</STRONG> -</OL> - -When in doubt, HTMLize a master and use <EM>lynx(1)</EM> to generate -plain ASCII (as we do for the announcement document). <P> +</head> + +<body> + <h1>A Hacker's Guide to NCURSES</h1> + + <h1>Contents</h1> + + <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> + + <h1><a name="abstract" id="abstract">Abstract</a></h1> + + <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> + + <h1><a name="objective" id="objective">Objective of the + Package</a></h1> + + <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> + + <h2><a name="whysvr4" id="whysvr4">Why System V Curses?</a></h2> + + <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> + + <h2><a name="extensions" id="extensions">How to Design + Extensions</a></h2> + + <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> + + <h1><a name="portability" id="portability">Portability and + Configuration</a></h1> + + <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> + + <h1><a name="documentation" id="documentation">Documentation + Conventions</a></h1> + + <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 <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> -The reason for choosing HTML is that it's (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 don't 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. - -<H1><A NAME="bugtrack">How to Report Bugs</A></H1> - -The <A NAME="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: -<PRE> + <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> + + <h1><a name="bugtrack" id="bugtrack">How to Report Bugs</a></h1> + + <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> subscribe <name>@<host.domain> -</PRE> - -The <CODE>ncurses</CODE> code is maintained by a small group of -volunteers. While we try our best to fix bugs promptly, we simply -don't 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> - -In order to use our bug-fixing time efficiently, we put people who -show us they've taken these steps at the head of our queue. This -means that if you don't, you'll probably end up at the tail end and -have to wait a while. - -<OL> -<LI>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.) - -<LI>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're using a traditional -asynchronous terminal or PC-based terminal emulator, rather than xterm -or a UNIX console entry. <P> - -It's therefore extremely helpful if you can tell us whether or not your -problem reproduces on other terminal types. Usually you'll have both -a console type and xterm available; please tell us whether or not your -bug reproduces on both. <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've seen -are either triggered or masked by these. - -<LI>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> - -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> - -If the virtual-screen dumps look correct but the bug persists, it's -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> - -Often you'll find terminfo problems at this stage by noticing that the -escape sequences put out for various capabilities are wrong. If not, -you're likely to learn enough to be able to characterize any bug in -the screen-update logic quite exactly. - -<LI>Report details and symptoms, not just interpretations. <P> - -If you do the preceding two steps, it is very likely that you'll 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 can't characterize and fix yourself. <P> - -If you're still stuck, at least you'll 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> - -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 doesn't throw -away any information (actually they're better than un-munched ones because -they're easier to read). <P> - -If your bug produces a core-dump, please include a symbolic stack trace -generated by gdb(1) or your local equivalent. <P> - -Tell us about every terminal on which you've reproduced the bug -- and -every terminal on which you can't. Ideally, sent us terminfo sources -for all of these (yours might differ from ours). <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. -</OL> - -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> - -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've got -a bad capability identified, you can disable it and test again. The -program is command-driven and has on-line help. <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> - -<H1><A NAME="ncurslib">A Tour of the Ncurses Library</A></H1> - -<H2><A NAME="loverview">Library Overview</A></H2> - -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 -<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> -are all in this category. They are very -unlikely to need change, barring bugs or some fundamental -reorganization in the underlying data structures. <P> - -These files are used only for debugging support: -<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> -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> - -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: -<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> -They are likely to need revision only if -ncurses is being ported to an environment without an underlying -terminfo capability representation. <P> - -These files -have serious hooks into -the tty driver and signal facilities: -<blockquote> -<code> -lib_kernel.c -lib_baudrate.c -lib_raw.c -lib_tstp.c -lib_twait.c -</code> -</blockquote> -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> - -Almost all of the real work is done in the files -<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> -Most of the algorithmic complexity in the -library lives in these files. -If there is a real bug in <STRONG>ncurses</STRONG> itself, it's probably here. -We'll tour some of these files in detail -below (see <A HREF="#engine">The Engine Room</A>). <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 -<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> -We'll discuss these in the compiler tour. - -<H2><A NAME="engine">The Engine Room</A></H2> - -<H3><A NAME="input">Keyboard Input</A></H3> - -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> - -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> - -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> - -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 don't return a reliable -time-left value. The function <CODE>timed_wait()</CODE> effectively -simulates a System V select. - -<H3><A NAME="mouse">Mouse Events</A></H3> - -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> - -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> - -This kluge only works because <STRONG>kmous</STRONG> isn't actually used by any -historic terminal type or curses implementation we know of. Best -guess is it's a relic of some forgotten experiment in-house at Bell -Labs that didn't 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> - -Here are some more details about mouse event handling: <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> - -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> - -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). - -<H3><A NAME="output">Output and Screen Updating</A></H3> - -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> - -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> - -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> - -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> - -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> - -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> - -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> - -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. - -<H1><A NAME="fmnote">The Forms and Menu Libraries</A></H1> - -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> - -The configuration code prefers the POSIX regex facility, modeled on -System V's, but will settle for BSD regexps if the former isn't available. <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>. - -<H1><A NAME="tic">A Tour of the Terminfo Compiler</A></H1> - -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> - -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". - -<H2><A NAME="nonuse">Translation of Non-<STRONG>use</STRONG> Capabilities</A></H2> - -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> - -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> - -Thus, adding a new capability is usually pretty trivial, just a matter -of adding one line to the <CODE>include/Caps</CODE> file. We'll have more -to say about this in the section on <A HREF="#translation">Source-Form -Translation</A>. - -<H2><A NAME="uses">Use Capability Resolution</A></H2> - -The background problem that makes <STRONG>tic</STRONG> tricky isn't the capability -translation itself, it's 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> - -This won't 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 can't go promiscuously writing -everything it translates out to disk -- for one thing, it will typically -be running with non-root permissions. <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're written out easy to do. <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> - -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> - -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's OK; -the resolution code will fetch it off disk when it can't find it in -core. <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. - -<H2><A NAME="translation">Source-Form Translation</A></H2> - -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> - -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> - -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's possible to set up capability aliasing -or tell the compiler to plain ignore a given capability without writing -any C code at all. <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. - -<H1><A NAME="utils">Other Utilities</A></H1> - -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> - -The <STRONG>tput</STRONG> and <STRONG>clear</STRONG> utilities just do an entry load -followed by a <CODE>tputs()</CODE> of a selected capability. - -<H1><A NAME="style">Style Tips for Developers</A></H1> - -See the TO-DO file in the top-level directory of the source distribution -for additions that would be particularly useful. <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> - -Look for the string <CODE>FIXME</CODE> in source files to tag minor bugs -and potential problems that could use fixing. <P> - -Don't try to auto-detect OS features in the main body of the C code. -That's the job of the configuration system. <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's still -preferable to ad-hoc code -- that's why the fifth field (flags) is -there. <P> - -Have fun! - -<H1><A NAME="port">Porting Hints</A></H1> - -The following notes are intended to be a first step towards DOS and Macintosh -ports of the ncurses libraries. <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. - -<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(): - -<blockquote> -<code> -lib_getstr.c -</code> -</blockquote> -<P> - -These modules are pure curses, except that they use <CODE>tputs()</CODE> -and <CODE>putp()</CODE>: - -<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: -<DL> -<DT> sigaction.c -<DD> signal calls -</DL> - -The following source files will not be needed for a -single-terminal-type port. - -<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. - -<DL> -<DT>lib_screen.c -<DD>used to read/write screen dumps -<DT>lib_trace.c -<DD>used to write trace data to the logfile -</DL> - -Modules that would have to be modified for a port start here: <P> - -The following modules are `pure curses' but contain assumptions inappropriate -for a memory-mapped port. - -<dl> -<dt>lib_longname.c<dd>assumes there may be multiple terminals -<dt>lib_acs.c<dd>assumes acs_map as a double indirection -<dt>lib_mvcur.c<dd>assumes cursor moves have variable cost -<dt>lib_termcap.c<dd>assumes there may be multiple terminals -<dt>lib_ti.c<dd>assumes there may be multiple terminals -</dl> - -The following modules use UNIX-specific calls: - -<dl> -<dt>lib_doupdate.c<dd>input checking -<dt>lib_getch.c<dd>read() -<dt>lib_initscr.c<dd>getenv() -<dt>lib_newterm.c -<dt>lib_baudrate.c -<dt>lib_kernel.c<dd>various tty-manipulation and system calls -<dt>lib_raw.c<dd>various tty-manipulation calls -<dt>lib_setup.c<dd>various tty-manipulation calls -<dt>lib_restart.c<dd>various tty-manipulation calls -<dt>lib_tstp.c<dd>signal-manipulation calls -<dt>lib_twait.c<dd>gettimeofday(), select(). -</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> +</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>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>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>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>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> + + <h1><a name="ncurslib" id="ncurslib">A Tour of the Ncurses + Library</a></h1> + + <h2><a name="loverview" id="loverview">Library Overview</a></h2> + + <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> + + <h2><a name="engine" id="engine">The Engine Room</a></h2> + + <h3><a name="input" id="input">Keyboard Input</a></h3> + + <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> + + <h3><a name="mouse" id="mouse">Mouse Events</a></h3> + + <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> + + <h3><a name="output" id="output">Output and Screen Updating</a></h3> + + <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> + + <h1><a name="fmnote" id="fmnote">The Forms and Menu Libraries</a></h1> + + <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> + + <h1><a name="tic" id="tic">A Tour of the Terminfo Compiler</a></h1> + + <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> + + <h2><a name="nonuse" id="nonuse">Translation of + Non-<strong>use</strong> Capabilities</a></h2> + + <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> + + <h2><a name="uses" id="uses">Use Capability Resolution</a></h2> + + <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> + + <h2><a name="translation" id="translation">Source-Form + Translation</a></h2> + + <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> + + <h1><a name="utils" id="utils">Other Utilities</a></h1> + + <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> + + <h1><a name="style" id="style">Style Tips for Developers</a></h1> + + <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> + + <h1><a name="port" id="port">Porting Hints</a></h1> + + <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> |