Utils: Fix hexump() of nevative values
[senf.git] / Utils / Termlib / Terminfo.cc
1 // $Id$
2 //
3 // Copyright (C) 2009 
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 //     Stefan Bund <g0dil@berlios.de>
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
23 /** \file
24     \brief Terminfo non-inline non-template implementation */
25
26 #include "Terminfo.hh"
27 //#include "Terminfo.ih"
28
29 // Custom includes
30 #include <fstream>
31 #include <iomanip>
32 #include <boost/filesystem/operations.hpp>
33 #include <senf/config.hh>
34 #include <senf/Utils/hexdump.hh>
35 #include <unistd.h>
36 #include <string.h>
37
38 //#include "Terminfo.mpp"
39 #define prefix_
40 ///////////////////////////////cc.p////////////////////////////////////////
41
42 char const * const senf::term::Terminfo::properties::BooleanNames [] = {
43     "AutoLeftMargin", "AutoRightMargin", "NoEscCtlc", "CeolStandoutGlitch", "EatNewlineGlitch",
44     "EraseOverstrike", "GenericType", "HardCopy", "HasMetaKey", "HasStatusLine", "InsertNullGlitch",
45     "MemoryAbove", "MemoryBelow", "MoveInsertMode", "MoveStandoutMode", "OverStrike",
46     "StatusLineEscOk", "DestTabsMagicSmso", "TildeGlitch", "TransparentUnderline", "XonXoff",
47     "NeedsXonXoff", "PrtrSilent", "HardCursor", "NonRevRmcup", "NoPadChar", "NonDestScrollRegion",
48     "CanChange", "BackColorErase", "HueLightnessSaturation", "ColAddrGlitch", "CrCancelsMicroMode",
49     "HasPrintWheel", "RowAddrGlitch", "SemiAutoRightMargin", "CpiChangesRes", "LpiChangesRes",
50     "BackspacesWithBs", "CrtNoScrolling", "NoCorrectlyWorkingCr", "GnuHasMetaKey",
51     "LinefeedIsNewline", "HasHardwareTabs", "ReturnDoesClrEol" };
52
53 char const * const senf::term::Terminfo::properties::NumericNames[] = {
54     "Columns", "InitTabs", "Lines", "LinesOfMemory", "MagicCookieGlitch", "PaddingBaudRate",
55     "VirtualTerminal", "WidthStatusLine", "NumLabels", "LabelHeight", "LabelWidth", "MaxAttributes",
56     "MaximumWindows", "MaxColors", "MaxPairs", "NoColorVideo", "BufferCapacity", "DotVertSpacing",
57     "DotHorzSpacing", "MaxMicroAddress", "MaxMicroJump", "MicroColSize", "MicroLineSize",
58     "NumberOfPins", "OutputResChar", "OutputResLine", "OutputResHorzInch", "OutputResVertInch",
59     "PrintRate", "WideCharSize", "Buttons", "BitImageEntwining", "BitImageType",
60     "MagicCookieGlitchUl", "CarriageReturnDelay", "NewLineDelay", "BackspaceDelay",
61     "HorizontalTabDelay", "NumberOfFunctionKeys" };
62
63 char const * const senf::term::Terminfo::properties::StringNames[] = {
64      "BackTab", "Bell", "CarriageReturn", "ChangeScrollRegion", "ClearAllTabs", "ClearScreen",
65      "ClrEol", "ClrEos", "ColumnAddress", "CommandCharacter", "CursorAddress", "CursorDown",
66      "CursorHome", "CursorInvisible", "CursorLeft", "CursorMemAddress", "CursorNormal",
67      "CursorRight", "CursorToLl", "CursorUp", "CursorVisible", "DeleteCharacter", "DeleteLine",
68      "DisStatusLine", "DownHalfLine", "EnterAltCharsetMode", "EnterBlinkMode", "EnterBoldMode",
69      "EnterCaMode", "EnterDeleteMode", "EnterDimMode", "EnterInsertMode", "EnterSecureMode",
70      "EnterProtectedMode", "EnterReverseMode", "EnterStandoutMode", "EnterUnderlineMode",
71      "EraseChars", "ExitAltCharsetMode", "ExitAttributeMode", "ExitCaMode", "ExitDeleteMode",
72      "ExitInsertMode", "ExitStandoutMode", "ExitUnderlineMode", "FlashScreen", "FormFeed",
73      "FromStatusLine", "Init1string", "Init2string", "Init3string", "InitFile", "InsertCharacter",
74      "InsertLine", "InsertPadding", "KeyBackspace", "KeyCatab", "KeyClear", "KeyCtab", "KeyDc",
75      "KeyDl", "KeyDown", "KeyEic", "KeyEol", "KeyEos", "KeyF0", "KeyF1", "KeyF10", "KeyF2", "KeyF3",
76      "KeyF4", "KeyF5", "KeyF6", "KeyF7", "KeyF8", "KeyF9", "KeyHome", "KeyIc", "KeyIl", "KeyLeft",
77      "KeyLl", "KeyNpage", "KeyPpage", "KeyRight", "KeySf", "KeySr", "KeyStab", "KeyUp",
78      "KeypadLocal", "KeypadXmit", "LabF0", "LabF1", "LabF10", "LabF2", "LabF3", "LabF4", "LabF5",
79      "LabF6", "LabF7", "LabF8", "LabF9", "MetaOff", "MetaOn", "Newline", "PadChar", "ParmDch",
80      "ParmDeleteLine", "ParmDownCursor", "ParmIch", "ParmIndex", "ParmInsertLine", "ParmLeftCursor",
81      "ParmRightCursor", "ParmRindex", "ParmUpCursor", "PkeyKey", "PkeyLocal", "PkeyXmit",
82      "PrintScreen", "PrtrOff", "PrtrOn", "RepeatChar", "Reset1string", "Reset2string",
83      "Reset3string", "ResetFile", "RestoreCursor", "RowAddress", "SaveCursor", "ScrollForward",
84      "ScrollReverse", "SetAttributes", "SetTab", "SetWindow", "Tab", "ToStatusLine", "UnderlineChar",
85      "UpHalfLine", "InitProg", "KeyA1", "KeyA3", "KeyB2", "KeyC1", "KeyC3", "PrtrNon", "CharPadding",
86      "AcsChars", "PlabNorm", "KeyBtab", "EnterXonMode", "ExitXonMode", "EnterAmMode", "ExitAmMode",
87      "XonCharacter", "XoffCharacter", "EnaAcs", "LabelOn", "LabelOff", "KeyBeg", "KeyCancel",
88      "KeyClose", "KeyCommand", "KeyCopy", "KeyCreate", "KeyEnd", "KeyEnter", "KeyExit", "KeyFind",
89      "KeyHelp", "KeyMark", "KeyMessage", "KeyMove", "KeyNext", "KeyOpen", "KeyOptions",
90      "KeyPrevious", "KeyPrint", "KeyRedo", "KeyReference", "KeyRefresh", "KeyReplace", "KeyRestart",
91      "KeyResume", "KeySave", "KeySuspend", "KeyUndo", "KeySbeg", "KeyScancel", "KeyScommand",
92      "KeyScopy", "KeyScreate", "KeySdc", "KeySdl", "KeySelect", "KeySend", "KeySeol", "KeySexit",
93      "KeySfind", "KeyShelp", "KeyShome", "KeySic", "KeySleft", "KeySmessage", "KeySmove", "KeySnext",
94      "KeySoptions", "KeySprevious", "KeySprint", "KeySredo", "KeySreplace", "KeySright", "KeySrsume",
95      "KeySsave", "KeySsuspend", "KeySundo", "ReqForInput", "KeyF11", "KeyF12", "KeyF13", "KeyF14",
96      "KeyF15", "KeyF16", "KeyF17", "KeyF18", "KeyF19", "KeyF20", "KeyF21", "KeyF22", "KeyF23",
97      "KeyF24", "KeyF25", "KeyF26", "KeyF27", "KeyF28", "KeyF29", "KeyF30", "KeyF31", "KeyF32",
98      "KeyF33", "KeyF34", "KeyF35", "KeyF36", "KeyF37", "KeyF38", "KeyF39", "KeyF40", "KeyF41",
99      "KeyF42", "KeyF43", "KeyF44", "KeyF45", "KeyF46", "KeyF47", "KeyF48", "KeyF49", "KeyF50",
100      "KeyF51", "KeyF52", "KeyF53", "KeyF54", "KeyF55", "KeyF56", "KeyF57", "KeyF58", "KeyF59",
101      "KeyF60", "KeyF61", "KeyF62", "KeyF63", "ClrBol", "ClearMargins", "SetLeftMargin",
102      "SetRightMargin", "LabelFormat", "SetClock", "DisplayClock", "RemoveClock", "CreateWindow",
103      "GotoWindow", "Hangup", "DialPhone", "QuickDial", "Tone", "Pulse", "FlashHook", "FixedPause",
104      "WaitTone", "User0", "User1", "User2", "User3", "User4", "User5", "User6", "User7", "User8",
105      "User9", "OrigPair", "OrigColors", "InitializeColor", "InitializePair", "SetColorPair",
106      "SetForeground", "SetBackground", "ChangeCharPitch", "ChangeLinePitch", "ChangeResHorz",
107      "ChangeResVert", "DefineChar", "EnterDoublewideMode", "EnterDraftQuality", "EnterItalicsMode",
108      "EnterLeftwardMode", "EnterMicroMode", "EnterNearLetterQuality", "EnterNormalQuality",
109      "EnterShadowMode", "EnterSubscriptMode", "EnterSuperscriptMode", "EnterUpwardMode",
110      "ExitDoublewideMode", "ExitItalicsMode", "ExitLeftwardMode", "ExitMicroMode", "ExitShadowMode",
111      "ExitSubscriptMode", "ExitSuperscriptMode", "ExitUpwardMode", "MicroColumnAddress", "MicroDown",
112      "MicroLeft", "MicroRight", "MicroRowAddress", "MicroUp", "OrderOfPins", "ParmDownMicro",
113      "ParmLeftMicro", "ParmRightMicro", "ParmUpMicro", "SelectCharSet", "SetBottomMargin",
114      "SetBottomMarginParm", "SetLeftMarginParm", "SetRightMarginParm", "SetTopMargin",
115      "SetTopMarginParm", "StartBitImage", "StartCharSetDef", "StopBitImage", "StopCharSetDef",
116      "SubscriptCharacters", "SuperscriptCharacters", "TheseCauseCr", "ZeroMotion", "CharSetNames",
117      "KeyMouse", "MouseInfo", "ReqMousePos", "GetMouse", "SetAForeground", "SetABackground",
118      "PkeyPlab", "DeviceType", "CodeSetInit", "Set0DesSeq", "Set1DesSeq", "Set2DesSeq", "Set3DesSeq",
119      "SetLrMargin", "SetTbMargin", "BitImageRepeat", "BitImageNewline", "BitImageCarriageReturn",
120      "ColorNames", "DefineBitImageRegion", "EndBitImageRegion", "SetColorBand", "SetPageLength",
121      "DisplayPcChar", "EnterPcCharsetMode", "ExitPcCharsetMode", "EnterScancodeMode",
122      "ExitScancodeMode", "PcTermOptions", "ScancodeEscape", "AltScancodeEsc",
123      "EnterHorizontalHlMode", "EnterLeftHlMode", "EnterLowHlMode", "EnterRightHlMode",
124      "EnterTopHlMode", "EnterVerticalHlMode", "SetAAttributes", "SetPglenInch", "TermcapInit2",
125      "TermcapReset", "LinefeedIfNotLf", "BackspaceIfNotBs", "OtherNonFunctionKeys", "ArrowKeyMap",
126      "AcsUlcorner", "AcsLlcorner", "AcsUrcorner", "AcsLrcorner", "AcsLtee", "AcsRtee", "AcsBtee",
127      "AcsTtee", "AcsHline", "AcsVline", "AcsPlus", "MemoryLock", "MemoryUnlock", "BoxChars1" };
128
129 ///////////////////////////////////////////////////////////////////////////
130 // senf::term::Terminfo
131
132 prefix_ senf::term::Terminfo::Terminfo()
133 {}
134
135 prefix_ senf::term::Terminfo::Terminfo(std::string const & term)
136 {
137     load(term);
138 }
139
140 prefix_ void senf::term::Terminfo::load(std::string const & term)
141 {
142     std::string filename (findTerminfo(term));
143     std::ifstream is (filename.c_str());
144     if (!is)
145         throw InvalidTerminfoException();
146     load(is);
147 }
148
149 prefix_ bool senf::term::Terminfo::getFlag(properties::Boolean p)
150     const
151 {
152     if (BoolVec::size_type(p) >= booleans_.size())
153         return false;
154     return booleans_[p];
155 }
156
157 prefix_ senf::term::Terminfo::number_t senf::term::Terminfo::getNumber(properties::Numeric p)
158     const
159 {
160     if (NumberVec::size_type(p) >= numbers_.size())
161         return NoValue;
162     return numbers_[p];
163 }
164
165 prefix_ senf::term::Terminfo::string_t senf::term::Terminfo::getString(properties::String p)
166     const
167 {
168     if (StringVec::size_type(p) >= strings_.size())
169         return 0;
170     return strings_[p];
171 }
172
173  prefix_ void senf::term::Terminfo::dump(std::ostream & os)
174      const
175  {
176      os << "Terminfo entry: " << name_ << "\n";
177      os << "Booleans: " << booleans_.size() << "\n";
178      os << "Numbers: " << numbers_.size() << "\n";
179      os << "Strings: " << strings_.size() << "\n";
180      os << "String pool size: " << stringPool_.size() << "\n";
181
182      {
183          os << "Flags:\n";
184          unsigned n (0);
185          BoolVec::const_iterator i (booleans_.begin());
186          BoolVec::const_iterator const i_end (booleans_.end());
187          for (; i != i_end; ++i, ++n)
188              if (*i && n < sizeof(properties::BooleanNames)/sizeof(properties::BooleanNames[0]))
189                  os << "    " << properties::BooleanNames[n] << "\n";
190      }
191
192      {
193          os << "Numbers:\n";
194          unsigned n (0);
195          NumberVec::const_iterator i (numbers_.begin());
196          NumberVec::const_iterator const i_end (numbers_.end());
197          for (; i != i_end; ++i, ++n)
198              if (*i != NoValue 
199                  && n < sizeof(properties::NumericNames)/sizeof(properties::NumericNames[0]))
200                  os << "    " << properties::NumericNames[n] << " = " << *i << "\n";
201      }
202
203      {
204          os << "Strings:\n";
205          unsigned n (0);
206          StringVec::const_iterator i (strings_.begin());
207          StringVec::const_iterator const i_end (strings_.end());
208          for (; i != i_end; ++i, ++n)
209              if (*i && n < sizeof(properties::StringNames)/sizeof(properties::StringNames[0])) {
210                  os << "    " << std::setw(32) << properties::StringNames[n] << " = ";
211                  hexdump(*i, *i + strlen(*i), os, 32);
212              }
213      }
214
215 }
216
217 prefix_ std::string senf::term::Terminfo::findTerminfo(std::string const & name)
218 {
219     boost::filesystem::path subdir (name.substr(0,1)); subdir /= name;
220     boost::filesystem::path tientry, tipath;
221
222     {
223         char const * tivar (::getenv("TERMINFO"));
224         if (tivar) {
225             tipath = tivar;
226             tientry = tipath / subdir;
227             if (boost::filesystem::exists(tientry)) return tientry.native_file_string();
228         }
229     }
230
231     tipath = "/etc/terminfo";
232     tientry = tipath / subdir;
233     if (boost::filesystem::exists(tientry)) return tientry.native_file_string();
234
235     tipath = "/lib/terminfo";
236     tientry = tipath / subdir;
237     if (boost::filesystem::exists(tientry)) return tientry.native_file_string();
238
239     tipath = "/usr/share/terminfo";
240     tientry = tipath / subdir;
241     if (boost::filesystem::exists(tientry)) return tientry.native_file_string();
242
243     return "";
244 }
245
246 namespace {
247
248     boost::uint16_t const TerminfoMagic = 0x011A;
249
250     struct TerminfoHeader {
251         boost::uint16_t magic;
252         boost::uint16_t namesSz;
253         boost::uint16_t nBooleans;
254         boost::uint16_t nNumbers;
255         boost::uint16_t nStrings;
256         boost::uint16_t stringPoolSz;
257     };
258
259 }
260
261 prefix_ void senf::term::Terminfo::load(std::istream & is)
262 {
263     TerminfoHeader h;
264     is.read(static_cast<char*>(static_cast<void*>(&h)), sizeof(h));
265     if (h.magic != TerminfoMagic)
266         throw InvalidTerminfoException();
267
268     name_.resize(h.namesSz);
269     is.read(&(name_[0]), name_.size());
270     {
271         std::string::size_type n (name_.find('\0'));
272         if (n != std::string::npos)
273             name_.erase(n);
274     }
275
276     booleans_.resize(h.nBooleans);
277     for (BoolVec::iterator i (booleans_.begin()); i != booleans_.end(); ++i) {
278         char v;
279         is.read(&v, sizeof(v));
280         *i = v;
281     }
282     if (booleans_.size() & 1)
283         is.ignore(1u);
284     
285     numbers_.resize(h.nNumbers);
286     for (NumberVec::iterator i (numbers_.begin()); i != numbers_.end(); ++i) {
287         number_t v;
288         is.read(static_cast<char*>(static_cast<void*>(&v)), sizeof(v));
289         *i = v;
290     }
291
292     typedef std::vector<number_t> OffsetVec;
293     OffsetVec offsets;
294     offsets.resize (h.nStrings);
295     for (OffsetVec::iterator i (offsets.begin()); i != offsets.end(); ++i) {
296         number_t v;
297         is.read(static_cast<char*>(static_cast<void*>(&v)), sizeof(v));
298         *i = v;
299     }
300     
301     stringPool_.resize(h.stringPoolSz);
302     is.read(&(stringPool_[0]), stringPool_.size());
303
304     strings_.resize(offsets.size());
305     StringVec::iterator j (strings_.begin());
306     for (OffsetVec::iterator i (offsets.begin()); i != offsets.end(); ++i, ++j)
307         if (*i != NoValue)
308             *j = &(stringPool_[0]) + *i;
309 }
310
311 ///////////////////////////////////////////////////////////////////////////
312 // senf::term::KeyParser
313
314 char const * const senf::term::KeyParser::KeyNames[] = {
315     "Esc", "Backspace", "Backtab", "Begin", "CATab", "CTab", "Cancel", "Center", "Clear",
316     "ClearToEOL", "ClearToEOS", "Close", "Command", "Copy", "Create", "Delete", "DeleteLine",
317     "Down", "DownLeft", "DownRight", "End", "Enter", "Exit", "F0", "F1", "F2", "F3", "F4", "F5",
318     "F6", "F7", "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", "F16", "F17", "F18", "F19",
319     "F20", "F21", "F22", "F23", "F24", "F25", "F26", "F27", "F28", "F29", "F30", "F31", "F32",
320     "F33", "F34", "F35", "F36", "F37", "F38", "F39", "F40", "F41", "F42", "F43", "F44", "F45",
321     "F46", "F47", "F48", "F49", "F50", "F51", "F52", "F53", "F54", "F55", "F56", "F57", "F58",
322     "F59", "F60", "F61", "F62", "F63", "Find", "Help", "Home", "Insert", "InsertLine", "Left",
323     "Mark", "Message", "Mouse", "Move", "Next", "Open", "Options", "PageDown", "PageUp", "Previous",
324     "Print", "Redo", "Reference", "Refresh", "Replace", "Restart", "Resume", "Right", "Save",
325     "Select", "ShiftBegin", "ShiftCancel", "ShiftCommand", "ShiftCopy", "ShiftCreate",
326     "ShiftDelete", "ShiftDeleteLine", "ShiftEnd", "ShiftClearToEOL", "ShiftExit", "ShiftFind",
327     "ShiftHelp", "ShiftHome", "ShiftInsert", "ShiftLeft", "ShiftMessage", "ShiftMove", "ShiftNext",
328     "ShiftOptions", "ShiftPrevious", "ShiftPrint", "ShiftRedo", "ShiftReplace", "ShiftResume",
329     "ShiftRight", "ShiftSave", "ShiftSuspend", "ShiftTab", "ShiftUndo", "Suspend", "Undo", "Up",
330     "UpLeft", "UpRight" };
331
332 prefix_ senf::term::KeyParser::KeyParser()
333 {}
334
335 prefix_ senf::term::KeyParser::KeyParser(Terminfo const & ti)
336 {
337     load(ti);
338 }
339
340 prefix_ void senf::term::KeyParser::load(Terminfo const & ti)
341 {
342     static Terminfo::properties::String keyStrings [] = {
343         Terminfo::properties::KeyCommand, Terminfo::properties::KeyBackspace,
344         Terminfo::properties::KeyBtab, Terminfo::properties::KeyBeg, Terminfo::properties::KeyCatab,
345         Terminfo::properties::KeyCtab, Terminfo::properties::KeyCancel, Terminfo::properties::KeyB2,
346         Terminfo::properties::KeyClear, Terminfo::properties::KeyEol, Terminfo::properties::KeyEos,
347         Terminfo::properties::KeyClose, Terminfo::properties::KeyCommand,
348         Terminfo::properties::KeyCopy, Terminfo::properties::KeyCreate, Terminfo::properties::KeyDc,
349         Terminfo::properties::KeyDl, Terminfo::properties::KeyDown, Terminfo::properties::KeyC1,
350         Terminfo::properties::KeyC3, Terminfo::properties::KeyEnd, Terminfo::properties::KeyEnter,
351         Terminfo::properties::KeyExit, Terminfo::properties::KeyF0, Terminfo::properties::KeyF1,
352         Terminfo::properties::KeyF2, Terminfo::properties::KeyF3, Terminfo::properties::KeyF4,
353         Terminfo::properties::KeyF5, Terminfo::properties::KeyF6, Terminfo::properties::KeyF7,
354         Terminfo::properties::KeyF8, Terminfo::properties::KeyF9, Terminfo::properties::KeyF10,
355         Terminfo::properties::KeyF11, Terminfo::properties::KeyF12, Terminfo::properties::KeyF13,
356         Terminfo::properties::KeyF14, Terminfo::properties::KeyF15, Terminfo::properties::KeyF16,
357         Terminfo::properties::KeyF17, Terminfo::properties::KeyF18, Terminfo::properties::KeyF19,
358         Terminfo::properties::KeyF20, Terminfo::properties::KeyF21, Terminfo::properties::KeyF22,
359         Terminfo::properties::KeyF23, Terminfo::properties::KeyF24, Terminfo::properties::KeyF25,
360         Terminfo::properties::KeyF26, Terminfo::properties::KeyF27, Terminfo::properties::KeyF28,
361         Terminfo::properties::KeyF29, Terminfo::properties::KeyF30, Terminfo::properties::KeyF31,
362         Terminfo::properties::KeyF32, Terminfo::properties::KeyF33, Terminfo::properties::KeyF34,
363         Terminfo::properties::KeyF35, Terminfo::properties::KeyF36, Terminfo::properties::KeyF37,
364         Terminfo::properties::KeyF38, Terminfo::properties::KeyF39, Terminfo::properties::KeyF40,
365         Terminfo::properties::KeyF41, Terminfo::properties::KeyF42, Terminfo::properties::KeyF43,
366         Terminfo::properties::KeyF44, Terminfo::properties::KeyF45, Terminfo::properties::KeyF46,
367         Terminfo::properties::KeyF47, Terminfo::properties::KeyF48, Terminfo::properties::KeyF49,
368         Terminfo::properties::KeyF50, Terminfo::properties::KeyF51, Terminfo::properties::KeyF52,
369         Terminfo::properties::KeyF53, Terminfo::properties::KeyF54, Terminfo::properties::KeyF55,
370         Terminfo::properties::KeyF56, Terminfo::properties::KeyF57, Terminfo::properties::KeyF58,
371         Terminfo::properties::KeyF59, Terminfo::properties::KeyF60, Terminfo::properties::KeyF61,
372         Terminfo::properties::KeyF62, Terminfo::properties::KeyF63, Terminfo::properties::KeyFind,
373         Terminfo::properties::KeyHelp, Terminfo::properties::KeyHome, Terminfo::properties::KeyIc,
374         Terminfo::properties::KeyIl, Terminfo::properties::KeyLeft, Terminfo::properties::KeyMark,
375         Terminfo::properties::KeyMessage, Terminfo::properties::KeyMouse,
376         Terminfo::properties::KeyMove, Terminfo::properties::KeyNext, Terminfo::properties::KeyOpen,
377         Terminfo::properties::KeyOptions, Terminfo::properties::KeyNpage,
378         Terminfo::properties::KeyPpage, Terminfo::properties::KeyPrevious,
379         Terminfo::properties::KeyPrint, Terminfo::properties::KeyRedo,
380         Terminfo::properties::KeyReference, Terminfo::properties::KeyRefresh,
381         Terminfo::properties::KeyReplace, Terminfo::properties::KeyRestart,
382         Terminfo::properties::KeyResume, Terminfo::properties::KeyRight,
383         Terminfo::properties::KeySave, Terminfo::properties::KeySelect,
384         Terminfo::properties::KeySbeg, Terminfo::properties::KeyScancel,
385         Terminfo::properties::KeyScommand, Terminfo::properties::KeyScopy,
386         Terminfo::properties::KeyScreate, Terminfo::properties::KeySdc,
387         Terminfo::properties::KeySdl, Terminfo::properties::KeySend, Terminfo::properties::KeySeol,
388         Terminfo::properties::KeySexit, Terminfo::properties::KeySfind,
389         Terminfo::properties::KeyShelp, Terminfo::properties::KeyShome,
390         Terminfo::properties::KeySic, Terminfo::properties::KeySleft,
391         Terminfo::properties::KeySmessage, Terminfo::properties::KeySmove,
392         Terminfo::properties::KeySnext, Terminfo::properties::KeySoptions,
393         Terminfo::properties::KeySprevious, Terminfo::properties::KeySprint,
394         Terminfo::properties::KeySredo, Terminfo::properties::KeySreplace,
395         Terminfo::properties::KeySrsume, Terminfo::properties::KeySright,
396         Terminfo::properties::KeySsave, Terminfo::properties::KeySsuspend,
397         Terminfo::properties::KeyStab, Terminfo::properties::KeySundo,
398         Terminfo::properties::KeySuspend, Terminfo::properties::KeyUndo,
399         Terminfo::properties::KeyUp, Terminfo::properties::KeyA1, Terminfo::properties::KeyA3 };
400
401     table_.clear();
402     for (unsigned i (0); i < sizeof(keyStrings)/sizeof(keyStrings[0]); ++i) {
403         char const * key (ti.getString(keyStrings[i]));
404         if (key)
405             table_.insert(std::make_pair(key, KeyCode(i+First)));
406     }
407 }
408
409 prefix_ std::pair<senf::term::KeyParser::keycode_t, std::string::size_type>
410 senf::term::KeyParser::lookup(std::string const & key)
411     const
412 {
413     if (key.empty())
414         return std::make_pair(KeyCode(0), 0);
415
416     // There are several cases: 
417     // a) 'key' is an incomplete key sequence. In this case, 'key' will precede all completions in
418     //    the key table. The first possible completion is found by 'upper_bound'
419     // b) 'key' is a complete key sequence. This is the key sequence *preceding* the 'upper_bound'
420     // c) 'key' is a complete key sequence with additional trailing characters. In this case, 'key'
421     //    will follow the correct entry in the key table. Again, the correct key sequence is
422     //    the one preceding the 'upper_bound'
423
424     Keytable::const_iterator i (table_.upper_bound(key));
425     if (i != table_.end() && i->first.substr(0, key.size()) == key)
426         return std::make_pair(Incomplete, key.size());
427     if (i == table_.begin())
428         return std::make_pair(keycode_t(key[0]), 1);
429     --i;
430     if (key.substr(0, i->first.size()) == i->first)
431         return std::make_pair(i->second, i->first.size());
432     return std::make_pair(keycode_t(key[0]), 1);
433 }
434
435 prefix_ std::string senf::term::KeyParser::describe(keycode_t key)
436 {
437     if (key < keycode_t(' '))
438         return "^" + std::string(1, '@' + key);
439     if (key < 256)
440         return std::string(1, char(key));
441     if (key >= keycode_t(First) && key < keycode_t(First + sizeof(KeyNames) / sizeof(KeyNames[0])))
442         return std::string(KeyNames[key-First]);
443     else
444         return "<" + boost::lexical_cast<std::string>(unsigned(key)) + ">";
445 }
446
447 prefix_ void senf::term::KeyParser::dump(std::ostream & os)
448     const
449 {
450     os << "Keytable:\n";
451     for (Keytable::const_iterator i (table_.begin()); i != table_.end(); ++i) {
452         unsigned index (i->second - First);
453         if (index < sizeof(KeyNames)/sizeof(KeyNames[0])) {
454             std::cout << "    " << std::setw(32) << KeyNames[index] << ": ";
455             hexdump(i->first.begin(), i->first.end(), os);
456         }
457     }
458 }
459
460 ///////////////////////////////cc.e////////////////////////////////////////
461 #undef prefix_
462 //#include "Terminfo.mpp"
463
464 \f
465 // Local Variables:
466 // mode: c++
467 // fill-column: 100
468 // comment-column: 40
469 // c-file-style: "senf"
470 // indent-tabs-mode: nil
471 // ispell-local-dictionary: "american"
472 // compile-command: "scons -u test"
473 // End: