4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
6 // The contents of this file are subject to the Fraunhofer FOKUS Public License
7 // Version 1.0 (the "License"); you may not use this file except in compliance
8 // with the License. You may obtain a copy of the License at
9 // http://senf.berlios.de/license.html
11 // The Fraunhofer FOKUS Public License Version 1.0 is based on,
12 // but modifies the Mozilla Public License Version 1.1.
13 // See the full license text for the amendments.
15 // Software distributed under the License is distributed on an "AS IS" basis,
16 // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
17 // for the specific language governing rights and limitations under the License.
19 // The Original Code is Fraunhofer FOKUS code.
21 // The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V.
22 // (registered association), Hansastraße 27 c, 80686 Munich, Germany.
23 // All Rights Reserved.
26 // Stefan Bund <g0dil@berlios.de>
29 \brief Terminfo non-inline non-template implementation */
31 #include "Terminfo.hh"
32 //#include "Terminfo.ih"
37 #include <boost/filesystem/operations.hpp>
38 #include <senf/config.hh>
39 #include <senf/Utils/hexdump.hh>
43 //#include "Terminfo.mpp"
45 //-/////////////////////////////////////////////////////////////////////////////////////////////////
47 char const * const senf::term::Terminfo::properties::BooleanNames [] = {
48 "AutoLeftMargin", "AutoRightMargin", "NoEscCtlc", "CeolStandoutGlitch", "EatNewlineGlitch",
49 "EraseOverstrike", "GenericType", "HardCopy", "HasMetaKey", "HasStatusLine", "InsertNullGlitch",
50 "MemoryAbove", "MemoryBelow", "MoveInsertMode", "MoveStandoutMode", "OverStrike",
51 "StatusLineEscOk", "DestTabsMagicSmso", "TildeGlitch", "TransparentUnderline", "XonXoff",
52 "NeedsXonXoff", "PrtrSilent", "HardCursor", "NonRevRmcup", "NoPadChar", "NonDestScrollRegion",
53 "CanChange", "BackColorErase", "HueLightnessSaturation", "ColAddrGlitch", "CrCancelsMicroMode",
54 "HasPrintWheel", "RowAddrGlitch", "SemiAutoRightMargin", "CpiChangesRes", "LpiChangesRes",
55 "BackspacesWithBs", "CrtNoScrolling", "NoCorrectlyWorkingCr", "GnuHasMetaKey",
56 "LinefeedIsNewline", "HasHardwareTabs", "ReturnDoesClrEol" };
58 char const * const senf::term::Terminfo::properties::NumericNames[] = {
59 "Columns", "InitTabs", "Lines", "LinesOfMemory", "MagicCookieGlitch", "PaddingBaudRate",
60 "VirtualTerminal", "WidthStatusLine", "NumLabels", "LabelHeight", "LabelWidth", "MaxAttributes",
61 "MaximumWindows", "MaxColors", "MaxPairs", "NoColorVideo", "BufferCapacity", "DotVertSpacing",
62 "DotHorzSpacing", "MaxMicroAddress", "MaxMicroJump", "MicroColSize", "MicroLineSize",
63 "NumberOfPins", "OutputResChar", "OutputResLine", "OutputResHorzInch", "OutputResVertInch",
64 "PrintRate", "WideCharSize", "Buttons", "BitImageEntwining", "BitImageType",
65 "MagicCookieGlitchUl", "CarriageReturnDelay", "NewLineDelay", "BackspaceDelay",
66 "HorizontalTabDelay", "NumberOfFunctionKeys" };
68 char const * const senf::term::Terminfo::properties::StringNames[] = {
69 "BackTab", "Bell", "CarriageReturn", "ChangeScrollRegion", "ClearAllTabs", "ClearScreen",
70 "ClrEol", "ClrEos", "ColumnAddress", "CommandCharacter", "CursorAddress", "CursorDown",
71 "CursorHome", "CursorInvisible", "CursorLeft", "CursorMemAddress", "CursorNormal",
72 "CursorRight", "CursorToLl", "CursorUp", "CursorVisible", "DeleteCharacter", "DeleteLine",
73 "DisStatusLine", "DownHalfLine", "EnterAltCharsetMode", "EnterBlinkMode", "EnterBoldMode",
74 "EnterCaMode", "EnterDeleteMode", "EnterDimMode", "EnterInsertMode", "EnterSecureMode",
75 "EnterProtectedMode", "EnterReverseMode", "EnterStandoutMode", "EnterUnderlineMode",
76 "EraseChars", "ExitAltCharsetMode", "ExitAttributeMode", "ExitCaMode", "ExitDeleteMode",
77 "ExitInsertMode", "ExitStandoutMode", "ExitUnderlineMode", "FlashScreen", "FormFeed",
78 "FromStatusLine", "Init1string", "Init2string", "Init3string", "InitFile", "InsertCharacter",
79 "InsertLine", "InsertPadding", "KeyBackspace", "KeyCatab", "KeyClear", "KeyCtab", "KeyDc",
80 "KeyDl", "KeyDown", "KeyEic", "KeyEol", "KeyEos", "KeyF0", "KeyF1", "KeyF10", "KeyF2", "KeyF3",
81 "KeyF4", "KeyF5", "KeyF6", "KeyF7", "KeyF8", "KeyF9", "KeyHome", "KeyIc", "KeyIl", "KeyLeft",
82 "KeyLl", "KeyNpage", "KeyPpage", "KeyRight", "KeySf", "KeySr", "KeyStab", "KeyUp",
83 "KeypadLocal", "KeypadXmit", "LabF0", "LabF1", "LabF10", "LabF2", "LabF3", "LabF4", "LabF5",
84 "LabF6", "LabF7", "LabF8", "LabF9", "MetaOff", "MetaOn", "Newline", "PadChar", "ParmDch",
85 "ParmDeleteLine", "ParmDownCursor", "ParmIch", "ParmIndex", "ParmInsertLine", "ParmLeftCursor",
86 "ParmRightCursor", "ParmRindex", "ParmUpCursor", "PkeyKey", "PkeyLocal", "PkeyXmit",
87 "PrintScreen", "PrtrOff", "PrtrOn", "RepeatChar", "Reset1string", "Reset2string",
88 "Reset3string", "ResetFile", "RestoreCursor", "RowAddress", "SaveCursor", "ScrollForward",
89 "ScrollReverse", "SetAttributes", "SetTab", "SetWindow", "Tab", "ToStatusLine", "UnderlineChar",
90 "UpHalfLine", "InitProg", "KeyA1", "KeyA3", "KeyB2", "KeyC1", "KeyC3", "PrtrNon", "CharPadding",
91 "AcsChars", "PlabNorm", "KeyBtab", "EnterXonMode", "ExitXonMode", "EnterAmMode", "ExitAmMode",
92 "XonCharacter", "XoffCharacter", "EnaAcs", "LabelOn", "LabelOff", "KeyBeg", "KeyCancel",
93 "KeyClose", "KeyCommand", "KeyCopy", "KeyCreate", "KeyEnd", "KeyEnter", "KeyExit", "KeyFind",
94 "KeyHelp", "KeyMark", "KeyMessage", "KeyMove", "KeyNext", "KeyOpen", "KeyOptions",
95 "KeyPrevious", "KeyPrint", "KeyRedo", "KeyReference", "KeyRefresh", "KeyReplace", "KeyRestart",
96 "KeyResume", "KeySave", "KeySuspend", "KeyUndo", "KeySbeg", "KeyScancel", "KeyScommand",
97 "KeyScopy", "KeyScreate", "KeySdc", "KeySdl", "KeySelect", "KeySend", "KeySeol", "KeySexit",
98 "KeySfind", "KeyShelp", "KeyShome", "KeySic", "KeySleft", "KeySmessage", "KeySmove", "KeySnext",
99 "KeySoptions", "KeySprevious", "KeySprint", "KeySredo", "KeySreplace", "KeySright", "KeySrsume",
100 "KeySsave", "KeySsuspend", "KeySundo", "ReqForInput", "KeyF11", "KeyF12", "KeyF13", "KeyF14",
101 "KeyF15", "KeyF16", "KeyF17", "KeyF18", "KeyF19", "KeyF20", "KeyF21", "KeyF22", "KeyF23",
102 "KeyF24", "KeyF25", "KeyF26", "KeyF27", "KeyF28", "KeyF29", "KeyF30", "KeyF31", "KeyF32",
103 "KeyF33", "KeyF34", "KeyF35", "KeyF36", "KeyF37", "KeyF38", "KeyF39", "KeyF40", "KeyF41",
104 "KeyF42", "KeyF43", "KeyF44", "KeyF45", "KeyF46", "KeyF47", "KeyF48", "KeyF49", "KeyF50",
105 "KeyF51", "KeyF52", "KeyF53", "KeyF54", "KeyF55", "KeyF56", "KeyF57", "KeyF58", "KeyF59",
106 "KeyF60", "KeyF61", "KeyF62", "KeyF63", "ClrBol", "ClearMargins", "SetLeftMargin",
107 "SetRightMargin", "LabelFormat", "SetClock", "DisplayClock", "RemoveClock", "CreateWindow",
108 "GotoWindow", "Hangup", "DialPhone", "QuickDial", "Tone", "Pulse", "FlashHook", "FixedPause",
109 "WaitTone", "User0", "User1", "User2", "User3", "User4", "User5", "User6", "User7", "User8",
110 "User9", "OrigPair", "OrigColors", "InitializeColor", "InitializePair", "SetColorPair",
111 "SetForeground", "SetBackground", "ChangeCharPitch", "ChangeLinePitch", "ChangeResHorz",
112 "ChangeResVert", "DefineChar", "EnterDoublewideMode", "EnterDraftQuality", "EnterItalicsMode",
113 "EnterLeftwardMode", "EnterMicroMode", "EnterNearLetterQuality", "EnterNormalQuality",
114 "EnterShadowMode", "EnterSubscriptMode", "EnterSuperscriptMode", "EnterUpwardMode",
115 "ExitDoublewideMode", "ExitItalicsMode", "ExitLeftwardMode", "ExitMicroMode", "ExitShadowMode",
116 "ExitSubscriptMode", "ExitSuperscriptMode", "ExitUpwardMode", "MicroColumnAddress", "MicroDown",
117 "MicroLeft", "MicroRight", "MicroRowAddress", "MicroUp", "OrderOfPins", "ParmDownMicro",
118 "ParmLeftMicro", "ParmRightMicro", "ParmUpMicro", "SelectCharSet", "SetBottomMargin",
119 "SetBottomMarginParm", "SetLeftMarginParm", "SetRightMarginParm", "SetTopMargin",
120 "SetTopMarginParm", "StartBitImage", "StartCharSetDef", "StopBitImage", "StopCharSetDef",
121 "SubscriptCharacters", "SuperscriptCharacters", "TheseCauseCr", "ZeroMotion", "CharSetNames",
122 "KeyMouse", "MouseInfo", "ReqMousePos", "GetMouse", "SetAForeground", "SetABackground",
123 "PkeyPlab", "DeviceType", "CodeSetInit", "Set0DesSeq", "Set1DesSeq", "Set2DesSeq", "Set3DesSeq",
124 "SetLrMargin", "SetTbMargin", "BitImageRepeat", "BitImageNewline", "BitImageCarriageReturn",
125 "ColorNames", "DefineBitImageRegion", "EndBitImageRegion", "SetColorBand", "SetPageLength",
126 "DisplayPcChar", "EnterPcCharsetMode", "ExitPcCharsetMode", "EnterScancodeMode",
127 "ExitScancodeMode", "PcTermOptions", "ScancodeEscape", "AltScancodeEsc",
128 "EnterHorizontalHlMode", "EnterLeftHlMode", "EnterLowHlMode", "EnterRightHlMode",
129 "EnterTopHlMode", "EnterVerticalHlMode", "SetAAttributes", "SetPglenInch", "TermcapInit2",
130 "TermcapReset", "LinefeedIfNotLf", "BackspaceIfNotBs", "OtherNonFunctionKeys", "ArrowKeyMap",
131 "AcsUlcorner", "AcsLlcorner", "AcsUrcorner", "AcsLrcorner", "AcsLtee", "AcsRtee", "AcsBtee",
132 "AcsTtee", "AcsHline", "AcsVline", "AcsPlus", "MemoryLock", "MemoryUnlock", "BoxChars1" };
134 //-/////////////////////////////////////////////////////////////////////////////////////////////////
135 // senf::term::Terminfo
137 prefix_ senf::term::Terminfo::Terminfo()
140 prefix_ senf::term::Terminfo::Terminfo(std::string const & term)
145 prefix_ void senf::term::Terminfo::load(std::string const & term)
147 std::string filename (findTerminfo(term));
148 if (filename.empty()) throw InvalidTerminfoException();
149 std::ifstream is (filename.c_str());
150 if (!is) throw InvalidTerminfoException();
154 prefix_ bool senf::term::Terminfo::getFlag(properties::Boolean p)
157 if (BoolVec::size_type(p) >= booleans_.size())
162 prefix_ senf::term::Terminfo::number_t senf::term::Terminfo::getNumber(properties::Numeric p)
165 if (NumberVec::size_type(p) >= numbers_.size())
170 prefix_ senf::term::Terminfo::string_t senf::term::Terminfo::getString(properties::String p)
173 if (StringVec::size_type(p) >= strings_.size())
178 prefix_ bool senf::term::Terminfo::hasProperty(properties::Boolean p)
184 prefix_ bool senf::term::Terminfo::hasProperty(properties::Numeric p)
187 return getNumber(p) != NoValue;
190 prefix_ bool senf::term::Terminfo::hasProperty(properties::String p)
193 return getString(p) != 0;
200 std::vector<senf::term::Terminfo::number_t> stack;
202 void push(senf::term::Terminfo::number_t v)
207 senf::term::Terminfo::number_t pop()
212 senf::term::Terminfo::number_t v (stack.back());
218 senf::term::Terminfo::number_t popNonzero()
220 senf::term::Terminfo::number_t v (pop());
227 // The following code is taken directly from utio. As far as I understand it is buggy
228 // and/or only partially implements the string format language. But seems to be enough for
229 // all the common terminal types ...
230 prefix_ std::string senf::term::Terminfo::formatString(properties::String p,
231 number_t arg1, number_t arg2,
232 number_t arg3, number_t arg4,
233 number_t arg5, number_t arg6,
234 number_t arg7, number_t arg8,
238 char const * fmt_p (getString(p));
242 std::string const prgstr (fmt_p);
244 bool bCondValue (false);
247 for (std::string::const_iterator i (prgstr.begin()); i != prgstr.end(); ++i) {
252 int width = 0, base = 0;
254 case '%': result += *i; break;
255 case 'i': ++arg1; ++arg2; break;
256 case 'c': result += char(stack.pop()); break;
257 case 'x': base = 16; continue;
258 case '0': if (!base) base = 8;
259 case '1': case '2': case '3': case '4':
260 case '5': case '6': case '7': case '8':
261 case '9': if (!base) base = 10;
262 width = width * base + (*i - '0');
266 case '\'': if (*(i - 1) == '%') {
267 if (*(i + 1) != '\\')
271 case '}': stack.push(width); break;
272 // Binary operands are in infix (reversed) order
273 case '+': stack.push(stack.pop() + stack.pop()); break;
274 case '-': stack.push(-stack.pop() + stack.pop()); break;
275 case '*': stack.push(stack.pop() * stack.pop()); break;
276 case '/': stack.push(stack.pop() / stack.popNonzero()); break;
277 case 'm': stack.push(stack.pop() % stack.popNonzero()); break;
278 case '|': stack.push(stack.pop() | stack.pop()); break;
279 case '&': stack.push(stack.pop() & stack.pop()); break;
280 case '^': stack.push(stack.pop() ^ stack.pop()); break;
281 case '>': stack.push(stack.pop() < stack.pop()); break;
282 case '<': stack.push(stack.pop() > stack.pop()); break;
283 case '=': stack.push(stack.pop() == stack.pop()); break;
284 case 'A': stack.push(stack.pop() && stack.pop()); break;
285 case 'O': stack.push(stack.pop() || stack.pop()); break;
286 case '!': stack.push(!stack.pop()); break;
287 case '~': stack.push(~stack.pop()); break;
288 case 't': bCondValue = stack.pop();
289 case 'e': if ((bCondValue = !bCondValue)) // this also supports elsif
290 --(i = prgstr.begin() + std::min (prgstr.find ("%e", i-prgstr.begin()),
291 prgstr.find ("%;", i-prgstr.begin())));
296 case '1': stack.push(arg1); break;
297 case '2': stack.push(arg2); break;
298 case '3': stack.push(arg3); break;
299 case '4': stack.push(arg4); break;
300 case '5': stack.push(arg5); break;
301 case '6': stack.push(arg6); break;
302 case '7': stack.push(arg7); break;
303 case '8': stack.push(arg8); break;
304 case '9': stack.push(arg9); break;
308 number_t n = stack.pop();
309 const std::string::size_type iSize = result.size();
311 result += std::string::value_type('0' + (n % 10));
312 } while ((n /= 10) || --width > 0);
313 reverse (result.begin() + iSize, result.end());
321 prefix_ void senf::term::Terminfo::dump(std::ostream & os)
324 os << "Terminfo entry: " << name_ << "\n";
325 os << "Booleans: " << booleans_.size() << "\n";
326 os << "Numbers: " << numbers_.size() << "\n";
327 os << "Strings: " << strings_.size() << "\n";
328 os << "String pool size: " << stringPool_.size() << "\n";
333 BoolVec::const_iterator i (booleans_.begin());
334 BoolVec::const_iterator const i_end (booleans_.end());
335 for (; i != i_end; ++i, ++n)
336 if (*i && n < sizeof(properties::BooleanNames)/sizeof(properties::BooleanNames[0]))
337 os << " " << properties::BooleanNames[n] << "\n";
343 NumberVec::const_iterator i (numbers_.begin());
344 NumberVec::const_iterator const i_end (numbers_.end());
345 for (; i != i_end; ++i, ++n)
347 && n < sizeof(properties::NumericNames)/sizeof(properties::NumericNames[0]))
348 os << " " << properties::NumericNames[n] << " = " << *i << "\n";
354 StringVec::const_iterator i (strings_.begin());
355 StringVec::const_iterator const i_end (strings_.end());
356 for (; i != i_end; ++i, ++n)
357 if (*i && n < sizeof(properties::StringNames)/sizeof(properties::StringNames[0])) {
358 os << " " << std::setw(32) << properties::StringNames[n] << " = ";
359 hexdump(*i, *i + strlen(*i), os, 32);
365 prefix_ std::string senf::term::Terminfo::findTerminfo(std::string const & name)
367 if (name.empty()) return "";
368 boost::filesystem::path subdir (name.substr(0,1)); subdir /= name;
369 boost::filesystem::path tientry;
372 char const * tivar (::getenv("TERMINFO"));
374 tientry = boost::filesystem::path(tivar) / subdir;
375 if (boost::filesystem::exists(tientry)) return tientry.string();
379 tientry = boost::filesystem::path("/etc/terminfo") / subdir;
380 if (boost::filesystem::exists(tientry)) return tientry.string();
382 tientry = boost::filesystem::path("/lib/terminfo") / subdir;
383 if (boost::filesystem::exists(tientry)) return tientry.string();
385 tientry = boost::filesystem::path("/usr/share/terminfo") / subdir;
386 if (boost::filesystem::exists(tientry)) return tientry.string();
393 boost::uint16_t const TerminfoMagic = 0x011A;
395 struct TerminfoHeader {
396 boost::uint16_t magic;
397 boost::uint16_t namesSz;
398 boost::uint16_t nBooleans;
399 boost::uint16_t nNumbers;
400 boost::uint16_t nStrings;
401 boost::uint16_t stringPoolSz;
406 prefix_ void senf::term::Terminfo::load(std::istream & is)
409 is.read(static_cast<char*>(static_cast<void*>(&h)), sizeof(h));
410 if (!is || h.magic != TerminfoMagic) throw InvalidTerminfoException();
412 name_.resize(h.namesSz);
413 is.read(&(name_[0]), name_.size());
414 if (!is) throw InvalidTerminfoException();
415 if (name_.size() & 1)
418 std::string::size_type n (name_.find('\0'));
419 if (n != std::string::npos)
423 booleans_.resize(h.nBooleans);
424 for (BoolVec::iterator i (booleans_.begin()); i != booleans_.end(); ++i) {
426 is.read(&v, sizeof(v));
427 if (!is) throw InvalidTerminfoException();
430 if (booleans_.size() & 1)
433 numbers_.resize(h.nNumbers);
434 for (NumberVec::iterator i (numbers_.begin()); i != numbers_.end(); ++i) {
436 is.read(static_cast<char*>(static_cast<void*>(&v)), sizeof(v));
437 if (!is) throw InvalidTerminfoException();
441 typedef std::vector<number_t> OffsetVec;
443 offsets.resize (h.nStrings);
444 for (OffsetVec::iterator i (offsets.begin()); i != offsets.end(); ++i) {
446 is.read(static_cast<char*>(static_cast<void*>(&v)), sizeof(v));
447 if (!is) throw InvalidTerminfoException();
451 stringPool_.resize(h.stringPoolSz);
452 is.read(&(stringPool_[0]), stringPool_.size());
453 if (!is) throw InvalidTerminfoException();
455 strings_.resize(offsets.size());
456 StringVec::iterator j (strings_.begin());
457 for (OffsetVec::iterator i (offsets.begin()); i != offsets.end(); ++i, ++j)
458 if (*i != NoValue && *i >= 0 && unsigned(*i) < stringPool_.size())
459 *j = &(stringPool_[0]) + *i;
464 //-/////////////////////////////////////////////////////////////////////////////////////////////////
465 // senf::term::KeyParser
467 char const * const senf::term::KeyParser::KeyNames[] = {
468 "Esc", "Backspace", "Backtab", "Begin", "CATab", "CTab", "Cancel", "Center", "Clear",
469 "ClearToEOL", "ClearToEOS", "Close", "Command", "Copy", "Create", "Delete", "DeleteLine",
470 "Down", "DownLeft", "DownRight", "End", "Enter", "Exit", "F0", "F1", "F2", "F3", "F4", "F5",
471 "F6", "F7", "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", "F16", "F17", "F18", "F19",
472 "F20", "F21", "F22", "F23", "F24", "F25", "F26", "F27", "F28", "F29", "F30", "F31", "F32",
473 "F33", "F34", "F35", "F36", "F37", "F38", "F39", "F40", "F41", "F42", "F43", "F44", "F45",
474 "F46", "F47", "F48", "F49", "F50", "F51", "F52", "F53", "F54", "F55", "F56", "F57", "F58",
475 "F59", "F60", "F61", "F62", "F63", "Find", "Help", "Home", "Insert", "InsertLine", "Left",
476 "Mark", "Message", "Mouse", "Move", "Next", "Open", "Options", "PageDown", "PageUp", "Previous",
477 "Print", "Redo", "Reference", "Refresh", "Replace", "Restart", "Resume", "Right", "Save",
478 "Select", "ShiftBegin", "ShiftCancel", "ShiftCommand", "ShiftCopy", "ShiftCreate",
479 "ShiftDelete", "ShiftDeleteLine", "ShiftEnd", "ShiftClearToEOL", "ShiftExit", "ShiftFind",
480 "ShiftHelp", "ShiftHome", "ShiftInsert", "ShiftLeft", "ShiftMessage", "ShiftMove", "ShiftNext",
481 "ShiftOptions", "ShiftPrevious", "ShiftPrint", "ShiftRedo", "ShiftReplace", "ShiftResume",
482 "ShiftRight", "ShiftSave", "ShiftSuspend", "ShiftTab", "ShiftUndo", "Suspend", "Undo", "Up",
483 "UpLeft", "UpRight" };
485 prefix_ senf::term::KeyParser::KeyParser()
488 prefix_ senf::term::KeyParser::KeyParser(Terminfo const & ti)
493 prefix_ void senf::term::KeyParser::load(Terminfo const & ti)
495 static Terminfo::properties::String keyStrings [] = {
496 Terminfo::properties::KeyCommand, Terminfo::properties::KeyBackspace,
497 Terminfo::properties::KeyBtab, Terminfo::properties::KeyBeg, Terminfo::properties::KeyCatab,
498 Terminfo::properties::KeyCtab, Terminfo::properties::KeyCancel, Terminfo::properties::KeyB2,
499 Terminfo::properties::KeyClear, Terminfo::properties::KeyEol, Terminfo::properties::KeyEos,
500 Terminfo::properties::KeyClose, Terminfo::properties::KeyCommand,
501 Terminfo::properties::KeyCopy, Terminfo::properties::KeyCreate, Terminfo::properties::KeyDc,
502 Terminfo::properties::KeyDl, Terminfo::properties::KeyDown, Terminfo::properties::KeyC1,
503 Terminfo::properties::KeyC3, Terminfo::properties::KeyEnd, Terminfo::properties::KeyEnter,
504 Terminfo::properties::KeyExit, Terminfo::properties::KeyF0, Terminfo::properties::KeyF1,
505 Terminfo::properties::KeyF2, Terminfo::properties::KeyF3, Terminfo::properties::KeyF4,
506 Terminfo::properties::KeyF5, Terminfo::properties::KeyF6, Terminfo::properties::KeyF7,
507 Terminfo::properties::KeyF8, Terminfo::properties::KeyF9, Terminfo::properties::KeyF10,
508 Terminfo::properties::KeyF11, Terminfo::properties::KeyF12, Terminfo::properties::KeyF13,
509 Terminfo::properties::KeyF14, Terminfo::properties::KeyF15, Terminfo::properties::KeyF16,
510 Terminfo::properties::KeyF17, Terminfo::properties::KeyF18, Terminfo::properties::KeyF19,
511 Terminfo::properties::KeyF20, Terminfo::properties::KeyF21, Terminfo::properties::KeyF22,
512 Terminfo::properties::KeyF23, Terminfo::properties::KeyF24, Terminfo::properties::KeyF25,
513 Terminfo::properties::KeyF26, Terminfo::properties::KeyF27, Terminfo::properties::KeyF28,
514 Terminfo::properties::KeyF29, Terminfo::properties::KeyF30, Terminfo::properties::KeyF31,
515 Terminfo::properties::KeyF32, Terminfo::properties::KeyF33, Terminfo::properties::KeyF34,
516 Terminfo::properties::KeyF35, Terminfo::properties::KeyF36, Terminfo::properties::KeyF37,
517 Terminfo::properties::KeyF38, Terminfo::properties::KeyF39, Terminfo::properties::KeyF40,
518 Terminfo::properties::KeyF41, Terminfo::properties::KeyF42, Terminfo::properties::KeyF43,
519 Terminfo::properties::KeyF44, Terminfo::properties::KeyF45, Terminfo::properties::KeyF46,
520 Terminfo::properties::KeyF47, Terminfo::properties::KeyF48, Terminfo::properties::KeyF49,
521 Terminfo::properties::KeyF50, Terminfo::properties::KeyF51, Terminfo::properties::KeyF52,
522 Terminfo::properties::KeyF53, Terminfo::properties::KeyF54, Terminfo::properties::KeyF55,
523 Terminfo::properties::KeyF56, Terminfo::properties::KeyF57, Terminfo::properties::KeyF58,
524 Terminfo::properties::KeyF59, Terminfo::properties::KeyF60, Terminfo::properties::KeyF61,
525 Terminfo::properties::KeyF62, Terminfo::properties::KeyF63, Terminfo::properties::KeyFind,
526 Terminfo::properties::KeyHelp, Terminfo::properties::KeyHome, Terminfo::properties::KeyIc,
527 Terminfo::properties::KeyIl, Terminfo::properties::KeyLeft, Terminfo::properties::KeyMark,
528 Terminfo::properties::KeyMessage, Terminfo::properties::KeyMouse,
529 Terminfo::properties::KeyMove, Terminfo::properties::KeyNext, Terminfo::properties::KeyOpen,
530 Terminfo::properties::KeyOptions, Terminfo::properties::KeyNpage,
531 Terminfo::properties::KeyPpage, Terminfo::properties::KeyPrevious,
532 Terminfo::properties::KeyPrint, Terminfo::properties::KeyRedo,
533 Terminfo::properties::KeyReference, Terminfo::properties::KeyRefresh,
534 Terminfo::properties::KeyReplace, Terminfo::properties::KeyRestart,
535 Terminfo::properties::KeyResume, Terminfo::properties::KeyRight,
536 Terminfo::properties::KeySave, Terminfo::properties::KeySelect,
537 Terminfo::properties::KeySbeg, Terminfo::properties::KeyScancel,
538 Terminfo::properties::KeyScommand, Terminfo::properties::KeyScopy,
539 Terminfo::properties::KeyScreate, Terminfo::properties::KeySdc,
540 Terminfo::properties::KeySdl, Terminfo::properties::KeySend, Terminfo::properties::KeySeol,
541 Terminfo::properties::KeySexit, Terminfo::properties::KeySfind,
542 Terminfo::properties::KeyShelp, Terminfo::properties::KeyShome,
543 Terminfo::properties::KeySic, Terminfo::properties::KeySleft,
544 Terminfo::properties::KeySmessage, Terminfo::properties::KeySmove,
545 Terminfo::properties::KeySnext, Terminfo::properties::KeySoptions,
546 Terminfo::properties::KeySprevious, Terminfo::properties::KeySprint,
547 Terminfo::properties::KeySredo, Terminfo::properties::KeySreplace,
548 Terminfo::properties::KeySrsume, Terminfo::properties::KeySright,
549 Terminfo::properties::KeySsave, Terminfo::properties::KeySsuspend,
550 Terminfo::properties::KeyStab, Terminfo::properties::KeySundo,
551 Terminfo::properties::KeySuspend, Terminfo::properties::KeyUndo,
552 Terminfo::properties::KeyUp, Terminfo::properties::KeyA1, Terminfo::properties::KeyA3 };
555 for (unsigned i (0); i < sizeof(keyStrings)/sizeof(keyStrings[0]); ++i) {
556 char const * key (ti.getString(keyStrings[i]));
558 table_.insert(std::make_pair(key, KeyCode(i+First)));
562 prefix_ std::pair<senf::term::KeyParser::keycode_t, std::string::size_type>
563 senf::term::KeyParser::lookup(std::string const & key)
567 return std::make_pair(KeyCode(0), 0);
569 // There are several cases:
570 // a) 'key' is an incomplete key sequence. In this case, 'key' will precede all completions in
571 // the key table. The first possible completion is found by 'upper_bound'
572 // b) 'key' is a complete key sequence. This is the key sequence *preceding* the 'upper_bound'
573 // c) 'key' is a complete key sequence with additional trailing characters. In this case, 'key'
574 // will follow the correct entry in the key table. Again, the correct key sequence is
575 // the one preceding the 'upper_bound'
577 Keytable::const_iterator i (table_.upper_bound(key));
578 if (i != table_.end() && i->first.substr(0, key.size()) == key)
579 return std::make_pair(Incomplete, key.size());
580 if (i == table_.begin())
581 return std::make_pair(keycode_t(key[0]), 1);
583 if (key.substr(0, i->first.size()) == i->first)
584 return std::make_pair(i->second, i->first.size());
585 return std::make_pair(keycode_t(key[0]), 1);
588 prefix_ std::string senf::term::KeyParser::describe(keycode_t key)
590 if (key < keycode_t(' '))
591 return "^" + std::string(1, '@' + key);
593 return std::string(1, char(key));
594 if (key >= keycode_t(First) && key < keycode_t(First + sizeof(KeyNames) / sizeof(KeyNames[0])))
595 return std::string(KeyNames[key-First]);
597 return "<" + boost::lexical_cast<std::string>(unsigned(key)) + ">";
600 prefix_ void senf::term::KeyParser::dump(std::ostream & os)
604 for (Keytable::const_iterator i (table_.begin()); i != table_.end(); ++i) {
605 unsigned index (i->second - First);
606 if (index < sizeof(KeyNames)/sizeof(KeyNames[0])) {
607 std::cout << " " << std::setw(32) << KeyNames[index] << ": ";
608 hexdump(i->first.begin(), i->first.end(), os);
613 //-/////////////////////////////////////////////////////////////////////////////////////////////////
615 //#include "Terminfo.mpp"
621 // comment-column: 40
622 // c-file-style: "senf"
623 // indent-tabs-mode: nil
624 // ispell-local-dictionary: "american"
625 // compile-command: "scons -u test"