1<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.0//EN"> 2<!-- 3 $Id: hackguide.html,v 1.27 2005/12/24 15:37:13 tom Exp $ 4 **************************************************************************** 5 * Copyright (c) 1998-2003,2005 Free Software Foundation, Inc. * 6 * * 7 * Permission is hereby granted, free of charge, to any person obtaining a * 8 * copy of this software and associated documentation files (the * 9 * "Software"), to deal in the Software without restriction, including * 10 * without limitation the rights to use, copy, modify, merge, publish, * 11 * distribute, distribute with modifications, sublicense, and/or sell * 12 * copies of the Software, and to permit persons to whom the Software is * 13 * furnished to do so, subject to the following conditions: * 14 * * 15 * The above copyright notice and this permission notice shall be included * 16 * in all copies or substantial portions of the Software. * 17 * * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 21 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 24 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 25 * * 26 * Except as contained in this notice, the name(s) of the above copyright * 27 * holders shall not be used in advertising or otherwise to promote the * 28 * sale, use or other dealings in this Software without prior written * 29 * authorization. * 30 **************************************************************************** 31--> 32<HTML> 33<HEAD> 34<TITLE>A Hacker's Guide to Ncurses Internals</TITLE> 35<link rev="made" href="mailto:bugs-ncurses@gnu.org"> 36<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> 37<!-- 38This document is self-contained, *except* that there is one relative link to 39the ncurses-intro.html document, expected to be in the same directory with 40this one. 41--> 42</HEAD> 43<BODY> 44 45<H1>A Hacker's Guide to NCURSES</H1> 46 47<H1>Contents</H1> 48<UL> 49<LI><A HREF="#abstract">Abstract</A> 50<LI><A HREF="#objective">Objective of the Package</A> 51<UL> 52<LI><A HREF="#whysvr4">Why System V Curses?</A> 53<LI><A HREF="#extensions">How to Design Extensions</A> 54</UL> 55<LI><A HREF="#portability">Portability and Configuration</A> 56<LI><A HREF="#documentation">Documentation Conventions</A> 57<LI><A HREF="#bugtrack">How to Report Bugs</A> 58<LI><A HREF="#ncurslib">A Tour of the Ncurses Library</A> 59<UL> 60<LI><A HREF="#loverview">Library Overview</A> 61<LI><A HREF="#engine">The Engine Room</A> 62<LI><A HREF="#input">Keyboard Input</A> 63<LI><A HREF="#mouse">Mouse Events</A> 64<LI><A HREF="#output">Output and Screen Updating</A> 65</UL> 66<LI><A HREF="#fmnote">The Forms and Menu Libraries</A> 67<LI><A HREF="#tic">A Tour of the Terminfo Compiler</A> 68<UL> 69<LI><A HREF="#nonuse">Translation of Non-<STRONG>use</STRONG> Capabilities</A> 70<LI><A HREF="#uses">Use Capability Resolution</A> 71<LI><A HREF="#translation">Source-Form Translation</A> 72</UL> 73<LI><A HREF="#utils">Other Utilities</A> 74<LI><A HREF="#style">Style Tips for Developers</A> 75<LI><A HREF="#port">Porting Hints</A> 76</UL> 77 78<H1><A NAME="abstract">Abstract</A></H1> 79 80This document is a hacker's tour of the <STRONG>ncurses</STRONG> library and utilities. 81It discusses design philosophy, implementation methods, and the 82conventions used for coding and documentation. It is recommended 83reading for anyone who is interested in porting, extending or improving the 84package. 85 86<H1><A NAME="objective">Objective of the Package</A></H1> 87 88The objective of the <STRONG>ncurses</STRONG> package is to provide a free software API for 89character-cell terminals and terminal emulators with the following 90characteristics: 91 92<UL> 93<LI>Source-compatible with historical curses implementations (including 94 the original BSD curses and System V curses. 95<LI>Conformant with the XSI Curses standard issued as part of XPG4 by 96 X/Open. 97<LI>High-quality -- stable and reliable code, wide portability, good 98 packaging, superior documentation. 99<LI>Featureful -- should eliminate as much of the drudgery of C interface 100 programming as possible, freeing programmers to think at a higher 101 level of design. 102</UL> 103 104These objectives are in priority order. So, for example, source 105compatibility with older version must trump featurefulness -- we cannot 106add features if it means breaking the portion of the API corresponding 107to historical curses versions. 108 109<H2><A NAME="whysvr4">Why System V Curses?</A></H2> 110 111We used System V curses as a model, reverse-engineering their API, in 112order to fulfill the first two objectives. <P> 113 114System V curses implementations can support BSD curses programs with 115just a recompilation, so by capturing the System V API we also 116capture BSD's. <P> 117 118More importantly for the future, the XSI Curses standard issued by X/Open 119is explicitly and closely modeled on System V. So conformance with 120System V took us most of the way to base-level XSI conformance. 121 122<H2><A NAME="extensions">How to Design Extensions</A></H2> 123 124The third objective (standards conformance) requires that it be easy to 125condition source code using <STRONG>ncurses</STRONG> so that the absence of nonstandard 126extensions does not break the code. <P> 127 128Accordingly, we have a policy of associating with each nonstandard extension 129a feature macro, so that ncurses client code can use this macro to condition 130in or out the code that requires the <STRONG>ncurses</STRONG> extension. <P> 131 132For example, there is a macro <CODE>NCURSES_MOUSE_VERSION</CODE> which XSI Curses 133does not define, but which is defined in the <STRONG>ncurses</STRONG> library header. 134You can use this to condition the calls to the mouse API calls. 135 136<H1><A NAME="portability">Portability and Configuration</A></H1> 137 138Code written for <STRONG>ncurses</STRONG> may assume an ANSI-standard C compiler and 139POSIX-compatible OS interface. It may also assume the presence of a 140System-V-compatible <EM>select(2)</EM> call. <P> 141 142We encourage (but do not require) developers to make the code friendly 143to less-capable UNIX environments wherever possible. <P> 144 145We encourage developers to support OS-specific optimizations and methods 146not available under POSIX/ANSI, provided only that: 147 148<UL> 149<LI>All such code is properly conditioned so the build process does not 150 attempt to compile it under a plain ANSI/POSIX environment. 151<LI>Adding such implementation methods does not introduce incompatibilities 152 in the <STRONG>ncurses</STRONG> API between platforms. 153</UL> 154 155We use GNU <CODE>autoconf(1)</CODE> as a tool to deal with portability issues. 156The right way to leverage an OS-specific feature is to modify the autoconf 157specification files (configure.in and aclocal.m4) to set up a new feature 158macro, which you then use to condition your code. 159 160<H1><A NAME="documentation">Documentation Conventions</A></H1> 161 162There are three kinds of documentation associated with this package. Each 163has a different preferred format: 164 165<UL> 166<LI>Package-internal files (README, INSTALL, TO-DO etc.) 167<LI>Manual pages. 168<LI>Everything else (i.e., narrative documentation). 169</UL> 170 171Our conventions are simple: 172<OL> 173<LI><STRONG>Maintain package-internal files in plain text.</STRONG> 174 The expected viewer for them <EM>more(1)</EM> or an editor window; there's 175 no point in elaborate mark-up. 176 177<LI><STRONG>Mark up manual pages in the man macros.</STRONG> These have to be viewable 178 through traditional <EM>man(1)</EM> programs. 179 180<LI><STRONG>Write everything else in HTML.</STRONG> 181</OL> 182 183When in doubt, HTMLize a master and use <EM>lynx(1)</EM> to generate 184plain ASCII (as we do for the announcement document). <P> 185 186The reason for choosing HTML is that it's (a) well-adapted for on-line 187browsing through viewers that are everywhere; (b) more easily readable 188as plain text than most other mark-ups, if you don't have a viewer; and (c) 189carries enough information that you can generate a nice-looking printed 190version from it. Also, of course, it make exporting things like the 191announcement document to WWW pretty trivial. 192 193<H1><A NAME="bugtrack">How to Report Bugs</A></H1> 194 195The <A NAME="bugreport">reporting address for bugs</A> is 196<A HREF="mailto:bug-ncurses@gnu.org">bug-ncurses@gnu.org</A>. 197This is a majordomo list; to join, write 198to <CODE>bug-ncurses-request@gnu.org</CODE> with a message containing the line: 199<PRE> 200 subscribe <name>@<host.domain> 201</PRE> 202 203The <CODE>ncurses</CODE> code is maintained by a small group of 204volunteers. While we try our best to fix bugs promptly, we simply 205don't have a lot of hours to spend on elementary hand-holding. We rely 206on intelligent cooperation from our users. If you think you have 207found a bug in <CODE>ncurses</CODE>, there are some steps you can take 208before contacting us that will help get the bug fixed quickly. <P> 209 210In order to use our bug-fixing time efficiently, we put people who 211show us they've taken these steps at the head of our queue. This 212means that if you don't, you'll probably end up at the tail end and 213have to wait a while. 214 215<OL> 216<LI>Develop a recipe to reproduce the bug. 217<p> 218Bugs we can reproduce are likely to be fixed very quickly, often 219within days. The most effective single thing you can do to get a 220quick fix is develop a way we can duplicate the bad behavior -- 221ideally, by giving us source for a small, portable test program that 222breaks the library. (Even better is a keystroke recipe using one of 223the test programs provided with the distribution.) 224 225<LI>Try to reproduce the bug on a different terminal type. <P> 226 227In our experience, most of the behaviors people report as library bugs 228are actually due to subtle problems in terminal descriptions. This is 229especially likely to be true if you're using a traditional 230asynchronous terminal or PC-based terminal emulator, rather than xterm 231or a UNIX console entry. <P> 232 233It's therefore extremely helpful if you can tell us whether or not your 234problem reproduces on other terminal types. Usually you'll have both 235a console type and xterm available; please tell us whether or not your 236bug reproduces on both. <P> 237 238If you have xterm available, it is also good to collect xterm reports for 239different window sizes. This is especially true if you normally use an 240unusual xterm window size -- a surprising number of the bugs we've seen 241are either triggered or masked by these. 242 243<LI>Generate and examine a trace file for the broken behavior. <P> 244 245Recompile your program with the debugging versions of the libraries. 246Insert a <CODE>trace()</CODE> call with the argument set to <CODE>TRACE_UPDATE</CODE>. 247(See <A HREF="ncurses-intro.html#debugging">"Writing Programs with 248NCURSES"</A> for details on trace levels.) 249Reproduce your bug, then look at the trace file to see what the library 250was actually doing. <P> 251 252Another frequent cause of apparent bugs is application coding errors 253that cause the wrong things to be put on the virtual screen. Looking 254at the virtual-screen dumps in the trace file will tell you immediately if 255this is happening, and save you from the possible embarrassment of being 256told that the bug is in your code and is your problem rather than ours. <P> 257 258If the virtual-screen dumps look correct but the bug persists, it's 259possible to crank up the trace level to give more and more information 260about the library's update actions and the control sequences it issues 261to perform them. The test directory of the distribution contains a 262tool for digesting these logs to make them less tedious to wade 263through. <P> 264 265Often you'll find terminfo problems at this stage by noticing that the 266escape sequences put out for various capabilities are wrong. If not, 267you're likely to learn enough to be able to characterize any bug in 268the screen-update logic quite exactly. 269 270<LI>Report details and symptoms, not just interpretations. <P> 271 272If you do the preceding two steps, it is very likely that you'll discover 273the nature of the problem yourself and be able to send us a fix. This 274will create happy feelings all around and earn you good karma for the first 275time you run into a bug you really can't characterize and fix yourself. <P> 276 277If you're still stuck, at least you'll know what to tell us. Remember, we 278need details. If you guess about what is safe to leave out, you are too 279likely to be wrong. <P> 280 281If your bug produces a bad update, include a trace file. Try to make 282the trace at the <EM>least</EM> voluminous level that pins down the 283bug. Logs that have been through tracemunch are OK, it doesn't throw 284away any information (actually they're better than un-munched ones because 285they're easier to read). <P> 286 287If your bug produces a core-dump, please include a symbolic stack trace 288generated by gdb(1) or your local equivalent. <P> 289 290Tell us about every terminal on which you've reproduced the bug -- and 291every terminal on which you can't. Ideally, sent us terminfo sources 292for all of these (yours might differ from ours). <P> 293 294Include your ncurses version and your OS/machine type, of course! You can 295find your ncurses version in the <CODE>curses.h</CODE> file. 296</OL> 297 298If your problem smells like a logic error or in cursor movement or 299scrolling or a bad capability, there are a couple of tiny test frames 300for the library algorithms in the progs directory that may help you 301isolate it. These are not part of the normal build, but do have their 302own make productions. <P> 303 304The most important of these is <CODE>mvcur</CODE>, a test frame for the 305cursor-movement optimization code. With this program, you can see 306directly what control sequences will be emitted for any given cursor 307movement or scroll/insert/delete operations. If you think you've got 308a bad capability identified, you can disable it and test again. The 309program is command-driven and has on-line help. <P> 310 311If you think the vertical-scroll optimization is broken, or just want to 312understand how it works better, build <CODE>hashmap</CODE> and read the 313header comments of <CODE>hardscroll.c</CODE> and <CODE>hashmap.c</CODE>; then try 314it out. You can also test the hardware-scrolling optimization separately 315with <CODE>hardscroll</CODE>. <P> 316 317<H1><A NAME="ncurslib">A Tour of the Ncurses Library</A></H1> 318 319<H2><A NAME="loverview">Library Overview</A></H2> 320 321Most of the library is superstructure -- fairly trivial convenience 322interfaces to a small set of basic functions and data structures used 323to manipulate the virtual screen (in particular, none of this code 324does any I/O except through calls to more fundamental modules 325described below). The files 326<blockquote> 327<CODE> 328lib_addch.c 329lib_bkgd.c 330lib_box.c 331lib_chgat.c 332lib_clear.c 333lib_clearok.c 334lib_clrbot.c 335lib_clreol.c 336lib_colorset.c 337lib_data.c 338lib_delch.c 339lib_delwin.c 340lib_echo.c 341lib_erase.c 342lib_gen.c 343lib_getstr.c 344lib_hline.c 345lib_immedok.c 346lib_inchstr.c 347lib_insch.c 348lib_insdel.c 349lib_insstr.c 350lib_instr.c 351lib_isendwin.c 352lib_keyname.c 353lib_leaveok.c 354lib_move.c 355lib_mvwin.c 356lib_overlay.c 357lib_pad.c 358lib_printw.c 359lib_redrawln.c 360lib_scanw.c 361lib_screen.c 362lib_scroll.c 363lib_scrollok.c 364lib_scrreg.c 365lib_set_term.c 366lib_slk.c 367lib_slkatr_set.c 368lib_slkatrof.c 369lib_slkatron.c 370lib_slkatrset.c 371lib_slkattr.c 372lib_slkclear.c 373lib_slkcolor.c 374lib_slkinit.c 375lib_slklab.c 376lib_slkrefr.c 377lib_slkset.c 378lib_slktouch.c 379lib_touch.c 380lib_unctrl.c 381lib_vline.c 382lib_wattroff.c 383lib_wattron.c 384lib_window.c 385</CODE> 386</blockquote> 387are all in this category. They are very 388unlikely to need change, barring bugs or some fundamental 389reorganization in the underlying data structures. <P> 390 391These files are used only for debugging support: 392<blockquote> 393<code> 394lib_trace.c 395lib_traceatr.c 396lib_tracebits.c 397lib_tracechr.c 398lib_tracedmp.c 399lib_tracemse.c 400trace_buf.c 401</code> 402</blockquote> 403It is rather unlikely you will ever need to change these, unless 404you want to introduce a new debug trace level for some reason.<P> 405 406There is another group of files that do direct I/O via <EM>tputs()</EM>, 407computations on the terminal capabilities, or queries to the OS 408environment, but nevertheless have only fairly low complexity. These 409include: 410<blockquote> 411<code> 412lib_acs.c 413lib_beep.c 414lib_color.c 415lib_endwin.c 416lib_initscr.c 417lib_longname.c 418lib_newterm.c 419lib_options.c 420lib_termcap.c 421lib_ti.c 422lib_tparm.c 423lib_tputs.c 424lib_vidattr.c 425read_entry.c. 426</code> 427</blockquote> 428They are likely to need revision only if 429ncurses is being ported to an environment without an underlying 430terminfo capability representation. <P> 431 432These files 433have serious hooks into 434the tty driver and signal facilities: 435<blockquote> 436<code> 437lib_kernel.c 438lib_baudrate.c 439lib_raw.c 440lib_tstp.c 441lib_twait.c 442</code> 443</blockquote> 444If you run into porting snafus 445moving the package to another UNIX, the problem is likely to be in one 446of these files. 447The file <CODE>lib_print.c</CODE> uses sleep(2) and also 448falls in this category.<P> 449 450Almost all of the real work is done in the files 451<blockquote> 452<code> 453hardscroll.c 454hashmap.c 455lib_addch.c 456lib_doupdate.c 457lib_getch.c 458lib_mouse.c 459lib_mvcur.c 460lib_refresh.c 461lib_setup.c 462lib_vidattr.c 463</code> 464</blockquote> 465Most of the algorithmic complexity in the 466library lives in these files. 467If there is a real bug in <STRONG>ncurses</STRONG> itself, it's probably here. 468We'll tour some of these files in detail 469below (see <A HREF="#engine">The Engine Room</A>). <P> 470 471Finally, there is a group of files that is actually most of the 472terminfo compiler. The reason this code lives in the <STRONG>ncurses</STRONG> 473library is to support fallback to /etc/termcap. These files include 474<blockquote> 475<code> 476alloc_entry.c 477captoinfo.c 478comp_captab.c 479comp_error.c 480comp_hash.c 481comp_parse.c 482comp_scan.c 483parse_entry.c 484read_termcap.c 485write_entry.c 486</code> 487</blockquote> 488We'll discuss these in the compiler tour. 489 490<H2><A NAME="engine">The Engine Room</A></H2> 491 492<H3><A NAME="input">Keyboard Input</A></H3> 493 494All <CODE>ncurses</CODE> input funnels through the function 495<CODE>wgetch()</CODE>, defined in <CODE>lib_getch.c</CODE>. This function is 496tricky; it has to poll for keyboard and mouse events and do a running 497match of incoming input against the set of defined special keys. <P> 498 499The central data structure in this module is a FIFO queue, used to 500match multiple-character input sequences against special-key 501capabilities; also to implement pushback via <CODE>ungetch()</CODE>. <P> 502 503The <CODE>wgetch()</CODE> code distinguishes between function key 504sequences and the same sequences typed manually by doing a timed wait 505after each input character that could lead a function key sequence. 506If the entire sequence takes less than 1 second, it is assumed to have 507been generated by a function key press. <P> 508 509Hackers bruised by previous encounters with variant <CODE>select(2)</CODE> 510calls may find the code in <CODE>lib_twait.c</CODE> interesting. It deals 511with the problem that some BSD selects don't return a reliable 512time-left value. The function <CODE>timed_wait()</CODE> effectively 513simulates a System V select. 514 515<H3><A NAME="mouse">Mouse Events</A></H3> 516 517If the mouse interface is active, <CODE>wgetch()</CODE> polls for mouse 518events each call, before it goes to the keyboard for input. It is 519up to <CODE>lib_mouse.c</CODE> how the polling is accomplished; it may vary 520for different devices. <P> 521 522Under xterm, however, mouse event notifications come in via the keyboard 523input stream. They are recognized by having the <STRONG>kmous</STRONG> capability 524as a prefix. This is kind of klugey, but trying to wire in recognition of 525a mouse key prefix without going through the function-key machinery would 526be just too painful, and this turns out to imply having the prefix somewhere 527in the function-key capabilities at terminal-type initialization. <P> 528 529This kluge only works because <STRONG>kmous</STRONG> isn't actually used by any 530historic terminal type or curses implementation we know of. Best 531guess is it's a relic of some forgotten experiment in-house at Bell 532Labs that didn't leave any traces in the publicly-distributed System V 533terminfo files. If System V or XPG4 ever gets serious about using it 534again, this kluge may have to change. <P> 535 536Here are some more details about mouse event handling: <P> 537 538The <CODE>lib_mouse()</CODE>code is logically split into a lower level that 539accepts event reports in a device-dependent format and an upper level that 540parses mouse gestures and filters events. The mediating data structure is a 541circular queue of event structures. <P> 542 543Functionally, the lower level's job is to pick up primitive events and 544put them on the circular queue. This can happen in one of two ways: 545either (a) <CODE>_nc_mouse_event()</CODE> detects a series of incoming 546mouse reports and queues them, or (b) code in <CODE>lib_getch.c</CODE> detects the 547<STRONG>kmous</STRONG> prefix in the keyboard input stream and calls _nc_mouse_inline 548to queue up a series of adjacent mouse reports. <P> 549 550In either case, <CODE>_nc_mouse_parse()</CODE> should be called after the 551series is accepted to parse the digested mouse reports (low-level 552events) into a gesture (a high-level or composite event). 553 554<H3><A NAME="output">Output and Screen Updating</A></H3> 555 556With the single exception of character echoes during a <CODE>wgetnstr()</CODE> 557call (which simulates cooked-mode line editing in an ncurses window), 558the library normally does all its output at refresh time. <P> 559 560The main job is to go from the current state of the screen (as represented 561in the <CODE>curscr</CODE> window structure) to the desired new state (as 562represented in the <CODE>newscr</CODE> window structure), while doing as 563little I/O as possible. <P> 564 565The brains of this operation are the modules <CODE>hashmap.c</CODE>, 566<CODE>hardscroll.c</CODE> and <CODE>lib_doupdate.c</CODE>; the latter two use 567<CODE>lib_mvcur.c</CODE>. Essentially, what happens looks like this: <P> 568 569The <CODE>hashmap.c</CODE> module tries to detect vertical motion 570changes between the real and virtual screens. This information 571is represented by the oldindex members in the newscr structure. 572These are modified by vertical-motion and clear operations, and both are 573re-initialized after each update. To this change-journalling 574information, the hashmap code adds deductions made using a modified Heckel 575algorithm on hash values generated from the line contents. <P> 576 577The <CODE>hardscroll.c</CODE> module computes an optimum set of scroll, 578insertion, and deletion operations to make the indices match. It calls 579<CODE>_nc_mvcur_scrolln()</CODE> in <CODE>lib_mvcur.c</CODE> to do those motions. <P> 580 581Then <CODE>lib_doupdate.c</CODE> goes to work. Its job is to do line-by-line 582transformations of <CODE>curscr</CODE> lines to <CODE>newscr</CODE> lines. Its main 583tool is the routine <CODE>mvcur()</CODE> in <CODE>lib_mvcur.c</CODE>. This routine 584does cursor-movement optimization, attempting to get from given screen 585location A to given location B in the fewest output characters possible. <P> 586 587If you want to work on screen optimizations, you should use the fact 588that (in the trace-enabled version of the library) enabling the 589<CODE>TRACE_TIMES</CODE> trace level causes a report to be emitted after 590each screen update giving the elapsed time and a count of characters 591emitted during the update. You can use this to tell when an update 592optimization improves efficiency. <P> 593 594In the trace-enabled version of the library, it is also possible to disable 595and re-enable various optimizations at runtime by tweaking the variable 596<CODE>_nc_optimize_enable</CODE>. See the file <CODE>include/curses.h.in</CODE> 597for mask values, near the end. 598 599<H1><A NAME="fmnote">The Forms and Menu Libraries</A></H1> 600 601The forms and menu libraries should work reliably in any environment you 602can port ncurses to. The only portability issue anywhere in them is what 603flavor of regular expressions the built-in form field type TYPE_REGEXP 604will recognize. <P> 605 606The configuration code prefers the POSIX regex facility, modeled on 607System V's, but will settle for BSD regexps if the former isn't available. <P> 608 609Historical note: the panels code was written primarily to assist in 610porting u386mon 2.0 (comp.sources.misc v14i001-4) to systems lacking 611panels support; u386mon 2.10 and beyond use it. This version has been 612slightly cleaned up for <CODE>ncurses</CODE>. 613 614<H1><A NAME="tic">A Tour of the Terminfo Compiler</A></H1> 615 616The <STRONG>ncurses</STRONG> implementation of <STRONG>tic</STRONG> is rather complex 617internally; it has to do a trying combination of missions. This starts 618with the fact that, in addition to its normal duty of compiling 619terminfo sources into loadable terminfo binaries, it has to be able to 620handle termcap syntax and compile that too into terminfo entries. <P> 621 622The implementation therefore starts with a table-driven, dual-mode 623lexical analyzer (in <CODE>comp_scan.c</CODE>). The lexer chooses its 624mode (termcap or terminfo) based on the first `,' or `:' it finds in 625each entry. The lexer does all the work of recognizing capability 626names and values; the grammar above it is trivial, just "parse entries 627till you run out of file". 628 629<H2><A NAME="nonuse">Translation of Non-<STRONG>use</STRONG> Capabilities</A></H2> 630 631Translation of most things besides <STRONG>use</STRONG> capabilities is pretty 632straightforward. The lexical analyzer's tokenizer hands each capability 633name to a hash function, which drives a table lookup. The table entry 634yields an index which is used to look up the token type in another table, 635and controls interpretation of the value. <P> 636 637One possibly interesting aspect of the implementation is the way the 638compiler tables are initialized. All the tables are generated by various 639awk/sed/sh scripts from a master table <CODE>include/Caps</CODE>; these 640scripts actually write C initializers which are linked to the compiler. 641Furthermore, the hash table is generated in the same way, so it doesn't 642have to be generated at compiler startup time (another benefit of this 643organization is that the hash table can be in shareable text space). <P> 644 645Thus, adding a new capability is usually pretty trivial, just a matter 646of adding one line to the <CODE>include/Caps</CODE> file. We'll have more 647to say about this in the section on <A HREF="#translation">Source-Form 648Translation</A>. 649 650<H2><A NAME="uses">Use Capability Resolution</A></H2> 651 652The background problem that makes <STRONG>tic</STRONG> tricky isn't the capability 653translation itself, it's the resolution of <STRONG>use</STRONG> capabilities. Older 654versions would not handle forward <STRONG>use</STRONG> references for this reason 655(that is, a using terminal always had to follow its use target in the 656source file). By doing this, they got away with a simple implementation 657tactic; compile everything as it blows by, then resolve uses from compiled 658entries. <P> 659 660This won't do for <STRONG>ncurses</STRONG>. The problem is that that the whole 661compilation process has to be embeddable in the <STRONG>ncurses</STRONG> library 662so that it can be called by the startup code to translate termcap 663entries on the fly. The embedded version can't go promiscuously writing 664everything it translates out to disk -- for one thing, it will typically 665be running with non-root permissions. <P> 666 667So our <STRONG>tic</STRONG> is designed to parse an entire terminfo file into a 668doubly-linked circular list of entry structures in-core, and then do 669<STRONG>use</STRONG> resolution in-memory before writing everything out. This 670design has other advantages: it makes forward and back use-references 671equally easy (so we get the latter for free), and it makes checking for 672name collisions before they're written out easy to do. <P> 673 674And this is exactly how the embedded version works. But the stand-alone 675user-accessible version of <STRONG>tic</STRONG> partly reverts to the historical 676strategy; it writes to disk (not keeping in core) any entry with no 677<STRONG>use</STRONG> references. <P> 678 679This is strictly a core-economy kluge, implemented because the 680terminfo master file is large enough that some core-poor systems swap 681like crazy when you compile it all in memory...there have been reports of 682this process taking <STRONG>three hours</STRONG>, rather than the twenty seconds 683or less typical on the author's development box. <P> 684 685So. The executable <STRONG>tic</STRONG> passes the entry-parser a hook that 686<EM>immediately</EM> writes out the referenced entry if it has no use 687capabilities. The compiler main loop refrains from adding the entry 688to the in-core list when this hook fires. If some other entry later 689needs to reference an entry that got written immediately, that's OK; 690the resolution code will fetch it off disk when it can't find it in 691core. <P> 692 693Name collisions will still be detected, just not as cleanly. The 694<CODE>write_entry()</CODE> code complains before overwriting an entry that 695postdates the time of <STRONG>tic</STRONG>'s first call to 696<CODE>write_entry()</CODE>, Thus it will complain about overwriting 697entries newly made during the <STRONG>tic</STRONG> run, but not about 698overwriting ones that predate it. 699 700<H2><A NAME="translation">Source-Form Translation</A></H2> 701 702Another use of <STRONG>tic</STRONG> is to do source translation between various termcap 703and terminfo formats. There are more variants out there than you might 704think; the ones we know about are described in the <STRONG>captoinfo(1)</STRONG> 705manual page. <P> 706 707The translation output code (<CODE>dump_entry()</CODE> in 708<CODE>ncurses/dump_entry.c</CODE>) is shared with the <STRONG>infocmp(1)</STRONG> 709utility. It takes the same internal representation used to generate 710the binary form and dumps it to standard output in a specified 711format. <P> 712 713The <CODE>include/Caps</CODE> file has a header comment describing ways you 714can specify source translations for nonstandard capabilities just by 715altering the master table. It's possible to set up capability aliasing 716or tell the compiler to plain ignore a given capability without writing 717any C code at all. <P> 718 719For circumstances where you need to do algorithmic translation, there 720are functions in <CODE>parse_entry.c</CODE> called after the parse of each 721entry that are specifically intended to encapsulate such 722translations. This, for example, is where the AIX <STRONG>box1</STRONG> capability 723get translated to an <STRONG>acsc</STRONG> string. 724 725<H1><A NAME="utils">Other Utilities</A></H1> 726 727The <STRONG>infocmp</STRONG> utility is just a wrapper around the same 728entry-dumping code used by <STRONG>tic</STRONG> for source translation. Perhaps 729the one interesting aspect of the code is the use of a predicate 730function passed in to <CODE>dump_entry()</CODE> to control which 731capabilities are dumped. This is necessary in order to handle both 732the ordinary De-compilation case and entry difference reporting. <P> 733 734The <STRONG>tput</STRONG> and <STRONG>clear</STRONG> utilities just do an entry load 735followed by a <CODE>tputs()</CODE> of a selected capability. 736 737<H1><A NAME="style">Style Tips for Developers</A></H1> 738 739See the TO-DO file in the top-level directory of the source distribution 740for additions that would be particularly useful. <P> 741 742The prefix <CODE>_nc_</CODE> should be used on library public functions that are 743not part of the curses API in order to prevent pollution of the 744application namespace. 745 746If you have to add to or modify the function prototypes in curses.h.in, 747read ncurses/MKlib_gen.sh first so you can avoid breaking XSI conformance. 748 749Please join the ncurses mailing list. See the INSTALL file in the 750top level of the distribution for details on the list. <P> 751 752Look for the string <CODE>FIXME</CODE> in source files to tag minor bugs 753and potential problems that could use fixing. <P> 754 755Don't try to auto-detect OS features in the main body of the C code. 756That's the job of the configuration system. <P> 757 758To hold down complexity, do make your code data-driven. Especially, 759if you can drive logic from a table filtered out of 760<CODE>include/Caps</CODE>, do it. If you find you need to augment the 761data in that file in order to generate the proper table, that's still 762preferable to ad-hoc code -- that's why the fifth field (flags) is 763there. <P> 764 765Have fun! 766 767<H1><A NAME="port">Porting Hints</A></H1> 768 769The following notes are intended to be a first step towards DOS and Macintosh 770ports of the ncurses libraries. <P> 771 772The following library modules are `pure curses'; they operate only on 773the curses internal structures, do all output through other curses 774calls (not including <CODE>tputs()</CODE> and <CODE>putp()</CODE>) and do not 775call any other UNIX routines such as signal(2) or the stdio library. 776Thus, they should not need to be modified for single-terminal 777ports. 778 779<blockquote> 780<code> 781lib_addch.c 782lib_addstr.c 783lib_bkgd.c 784lib_box.c 785lib_clear.c 786lib_clrbot.c 787lib_clreol.c 788lib_delch.c 789lib_delwin.c 790lib_erase.c 791lib_inchstr.c 792lib_insch.c 793lib_insdel.c 794lib_insstr.c 795lib_keyname.c 796lib_move.c 797lib_mvwin.c 798lib_newwin.c 799lib_overlay.c 800lib_pad.c 801lib_printw.c 802lib_refresh.c 803lib_scanw.c 804lib_scroll.c 805lib_scrreg.c 806lib_set_term.c 807lib_touch.c 808lib_tparm.c 809lib_tputs.c 810lib_unctrl.c 811lib_window.c 812panel.c 813</code> 814</blockquote> 815<P> 816 817This module is pure curses, but calls outstr(): 818 819<blockquote> 820<code> 821lib_getstr.c 822</code> 823</blockquote> 824<P> 825 826These modules are pure curses, except that they use <CODE>tputs()</CODE> 827and <CODE>putp()</CODE>: 828 829<blockquote> 830<code> 831lib_beep.c 832lib_color.c 833lib_endwin.c 834lib_options.c 835lib_slk.c 836lib_vidattr.c 837</code> 838</blockquote> 839<P> 840 841This modules assist in POSIX emulation on non-POSIX systems: 842<DL> 843<DT> sigaction.c 844<DD> signal calls 845</DL> 846 847The following source files will not be needed for a 848single-terminal-type port. 849 850<blockquote> 851<code> 852alloc_entry.c 853captoinfo.c 854clear.c 855comp_captab.c 856comp_error.c 857comp_hash.c 858comp_main.c 859comp_parse.c 860comp_scan.c 861dump_entry.c 862infocmp.c 863parse_entry.c 864read_entry.c 865tput.c 866write_entry.c 867</code> 868</blockquote> 869<P> 870 871The following modules will use open()/read()/write()/close()/lseek() on files, 872but no other OS calls. 873 874<DL> 875<DT>lib_screen.c 876<DD>used to read/write screen dumps 877<DT>lib_trace.c 878<DD>used to write trace data to the logfile 879</DL> 880 881Modules that would have to be modified for a port start here: <P> 882 883The following modules are `pure curses' but contain assumptions inappropriate 884for a memory-mapped port. 885 886<dl> 887<dt>lib_longname.c<dd>assumes there may be multiple terminals 888<dt>lib_acs.c<dd>assumes acs_map as a double indirection 889<dt>lib_mvcur.c<dd>assumes cursor moves have variable cost 890<dt>lib_termcap.c<dd>assumes there may be multiple terminals 891<dt>lib_ti.c<dd>assumes there may be multiple terminals 892</dl> 893 894The following modules use UNIX-specific calls: 895 896<dl> 897<dt>lib_doupdate.c<dd>input checking 898<dt>lib_getch.c<dd>read() 899<dt>lib_initscr.c<dd>getenv() 900<dt>lib_newterm.c 901<dt>lib_baudrate.c 902<dt>lib_kernel.c<dd>various tty-manipulation and system calls 903<dt>lib_raw.c<dd>various tty-manipulation calls 904<dt>lib_setup.c<dd>various tty-manipulation calls 905<dt>lib_restart.c<dd>various tty-manipulation calls 906<dt>lib_tstp.c<dd>signal-manipulation calls 907<dt>lib_twait.c<dd>gettimeofday(), select(). 908</dl> 909 910<HR> 911<ADDRESS>Eric S. Raymond <esr@snark.thyrsus.com></ADDRESS> 912(Note: This is <EM>not</EM> the <A HREF="#bugtrack">bug address</A>!) 913</BODY> 914</HTML> 915