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