📄 hackguide.html
字号:
handle termcap syntax and compile that too into terminfo entries. <P>The implementation therefore starts with a table-driven, dual-modelexical analyzer (in <CODE>comp_scan.c</CODE>). The lexer chooses itsmode (termcap or terminfo) based on the first `,' or `:' it finds ineach entry. The lexer does all the work of recognizing capabilitynames and values; the grammar above it is trivial, just "parse entriestill 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 prettystraightforward. The lexical analyzer's tokenizer hands each capabilityname to a hash function, which drives a table lookup. The table entryyields 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 thecompiler tables are initialized. All the tables are generated by variousawk/sed/sh scripts from a master table <CODE>include/Caps</CODE>; thesescripts actually write C initializers which are linked to the compiler.Furthermore, the hash table is generated in the same way, so it doesn'thave to be generated at compiler startup time (another benefit of thisorganization is that the hash table can be in shareable text space). <P>Thus, adding a new capability is usually pretty trivial, just a matterof adding one line to the <CODE>include/Caps</CODE> file. We'll have moreto say about this in the section on <A HREF="#translation">Source-FormTranslation</A>.<H2><A NAME="uses">Use Capability Resolution</A></H2>The background problem that makes <STRONG>tic</STRONG> tricky isn't the capabilitytranslation itself, it's the resolution of <STRONG>use</STRONG> capabilities. Olderversions would not handle forward <STRONG>use</STRONG> references for this reason(that is, a using terminal always had to follow its use target in thesource file). By doing this, they got away with a simple implementationtactic; compile everything as it blows by, then resolve uses from compiledentries. <P>This won't do for <STRONG>ncurses</STRONG>. The problem is that that the wholecompilation process has to be embeddable in the <STRONG>ncurses</STRONG> libraryso that it can be called by the startup code to translate termcapentries on the fly. The embedded version can't go promiscuously writingeverything it translates out to disk -- for one thing, it will typicallybe running with non-root permissions. <P>So our <STRONG>tic</STRONG> is designed to parse an entire terminfo file into adoubly-linked circular list of entry structures in-core, and then do<STRONG>use</STRONG> resolution in-memory before writing everything out. Thisdesign has other advantages: it makes forward and back use-referencesequally easy (so we get the latter for free), and it makes checking forname collisions before they're written out easy to do. <P>And this is exactly how the embedded version works. But the stand-aloneuser-accessible version of <STRONG>tic</STRONG> partly reverts to the historicalstrategy; 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 theterminfo master file is large enough that some core-poor systems swaplike crazy when you compile it all in memory...there have been reports ofthis process taking <STRONG>three hours</STRONG>, rather than the twenty secondsor 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 usecapabilities. The compiler main loop refrains from adding the entryto the in-core list when this hook fires. If some other entry laterneeds 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 incore. <P>Name collisions will still be detected, just not as cleanly. The<CODE>write_entry()</CODE> code complains before overwriting an entry thatpostdates the time of <STRONG>tic</STRONG>'s first call to<CODE>write_entry()</CODE>, Thus it will complain about overwritingentries newly made during the <STRONG>tic</STRONG> run, but not aboutoverwriting 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 termcapand terminfo formats. There are more variants out there than you mightthink; 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 generatethe binary form and dumps it to standard output in a specifiedformat. <P>The <CODE>include/Caps</CODE> file has a header comment describing ways youcan specify source translations for nonstandard capabilities just byaltering the master table. It's possible to set up capability aliasingor tell the compiler to plain ignore a given capability without writingany C code at all. <P>For circumstances where you need to do algorithmic translation, thereare functions in <CODE>parse_entry.c</CODE> called after the parse of eachentry that are specifically intended to encapsulate suchtranslations. This, for example, is where the AIX <STRONG>box1</STRONG> capabilityget 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 sameentry-dumping code used by <STRONG>tic</STRONG> for source translation. Perhapsthe one interesting aspect of the code is the use of a predicatefunction passed in to <CODE>dump_entry()</CODE> to control whichcapabilities are dumped. This is necessary in order to handle boththe ordinary De-compilation case and entry difference reporting. <P>The <STRONG>tput</STRONG> and <STRONG>clear</STRONG> utilities just do an entry loadfollowed 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 distributionfor additions that would be particularly useful. <P>The prefix <CODE>_nc_</CODE> should be used on library public functions that arenot part of the curses API in order to prevent pollution of theapplication 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 thetop level of the distribution for details on the list. <P>Look for the string <CODE>FIXME</CODE> in source files to tag minor bugsand 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 thedata in that file in order to generate the proper table, that's stillpreferable to ad-hoc code -- that's why the fifth field (flags) isthere. <P>Have fun!<H1><A NAME="port">Porting Hints</A></H1>The following notes are intended to be a first step towards DOS and Macintoshports of the ncurses libraries. <P>The following library modules are `pure curses'; they operate only onthe curses internal structures, do all output through other cursescalls (not including <CODE>tputs()</CODE> and <CODE>putp()</CODE>) and do notcall any other UNIX routines such as signal(2) or the stdio library.Thus, they should not need to be modified for single-terminalports. <blockquote><code>lib_addch.clib_addstr.clib_bkgd.clib_box.clib_clear.clib_clrbot.clib_clreol.clib_delch.clib_delwin.clib_erase.clib_inchstr.clib_insch.clib_insdel.clib_insstr.clib_keyname.clib_move.clib_mvwin.clib_newwin.clib_overlay.clib_pad.clib_printw.clib_refresh.clib_scanw.clib_scroll.clib_scrreg.clib_set_term.clib_touch.clib_tparm.clib_tputs.clib_unctrl.clib_window.cpanel.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.clib_color.clib_endwin.clib_options.clib_slk.clib_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 asingle-terminal-type port.<blockquote><code>alloc_entry.ccaptoinfo.cclear.ccomp_captab.ccomp_error.ccomp_hash.ccomp_main.ccomp_parse.ccomp_scan.cdump_entry.cinfocmp.cparse_entry.cread_entry.ctput.cwrite_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 inappropriatefor 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>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -