00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00026 #include "Terminfo.hh"
00027
00028
00029
00030 #include <fstream>
00031 #include <iomanip>
00032 #include <boost/filesystem/operations.hpp>
00033 #include <senf/config.hh>
00034 #include <senf/Utils/hexdump.hh>
00035 #include <unistd.h>
00036 #include <string.h>
00037
00038
00039 #define prefix_
00040
00041
00042 char const * const senf::term::Terminfo::properties::BooleanNames [] = {
00043 "AutoLeftMargin", "AutoRightMargin", "NoEscCtlc", "CeolStandoutGlitch", "EatNewlineGlitch",
00044 "EraseOverstrike", "GenericType", "HardCopy", "HasMetaKey", "HasStatusLine", "InsertNullGlitch",
00045 "MemoryAbove", "MemoryBelow", "MoveInsertMode", "MoveStandoutMode", "OverStrike",
00046 "StatusLineEscOk", "DestTabsMagicSmso", "TildeGlitch", "TransparentUnderline", "XonXoff",
00047 "NeedsXonXoff", "PrtrSilent", "HardCursor", "NonRevRmcup", "NoPadChar", "NonDestScrollRegion",
00048 "CanChange", "BackColorErase", "HueLightnessSaturation", "ColAddrGlitch", "CrCancelsMicroMode",
00049 "HasPrintWheel", "RowAddrGlitch", "SemiAutoRightMargin", "CpiChangesRes", "LpiChangesRes",
00050 "BackspacesWithBs", "CrtNoScrolling", "NoCorrectlyWorkingCr", "GnuHasMetaKey",
00051 "LinefeedIsNewline", "HasHardwareTabs", "ReturnDoesClrEol" };
00052
00053 char const * const senf::term::Terminfo::properties::NumericNames[] = {
00054 "Columns", "InitTabs", "Lines", "LinesOfMemory", "MagicCookieGlitch", "PaddingBaudRate",
00055 "VirtualTerminal", "WidthStatusLine", "NumLabels", "LabelHeight", "LabelWidth", "MaxAttributes",
00056 "MaximumWindows", "MaxColors", "MaxPairs", "NoColorVideo", "BufferCapacity", "DotVertSpacing",
00057 "DotHorzSpacing", "MaxMicroAddress", "MaxMicroJump", "MicroColSize", "MicroLineSize",
00058 "NumberOfPins", "OutputResChar", "OutputResLine", "OutputResHorzInch", "OutputResVertInch",
00059 "PrintRate", "WideCharSize", "Buttons", "BitImageEntwining", "BitImageType",
00060 "MagicCookieGlitchUl", "CarriageReturnDelay", "NewLineDelay", "BackspaceDelay",
00061 "HorizontalTabDelay", "NumberOfFunctionKeys" };
00062
00063 char const * const senf::term::Terminfo::properties::StringNames[] = {
00064 "BackTab", "Bell", "CarriageReturn", "ChangeScrollRegion", "ClearAllTabs", "ClearScreen",
00065 "ClrEol", "ClrEos", "ColumnAddress", "CommandCharacter", "CursorAddress", "CursorDown",
00066 "CursorHome", "CursorInvisible", "CursorLeft", "CursorMemAddress", "CursorNormal",
00067 "CursorRight", "CursorToLl", "CursorUp", "CursorVisible", "DeleteCharacter", "DeleteLine",
00068 "DisStatusLine", "DownHalfLine", "EnterAltCharsetMode", "EnterBlinkMode", "EnterBoldMode",
00069 "EnterCaMode", "EnterDeleteMode", "EnterDimMode", "EnterInsertMode", "EnterSecureMode",
00070 "EnterProtectedMode", "EnterReverseMode", "EnterStandoutMode", "EnterUnderlineMode",
00071 "EraseChars", "ExitAltCharsetMode", "ExitAttributeMode", "ExitCaMode", "ExitDeleteMode",
00072 "ExitInsertMode", "ExitStandoutMode", "ExitUnderlineMode", "FlashScreen", "FormFeed",
00073 "FromStatusLine", "Init1string", "Init2string", "Init3string", "InitFile", "InsertCharacter",
00074 "InsertLine", "InsertPadding", "KeyBackspace", "KeyCatab", "KeyClear", "KeyCtab", "KeyDc",
00075 "KeyDl", "KeyDown", "KeyEic", "KeyEol", "KeyEos", "KeyF0", "KeyF1", "KeyF10", "KeyF2", "KeyF3",
00076 "KeyF4", "KeyF5", "KeyF6", "KeyF7", "KeyF8", "KeyF9", "KeyHome", "KeyIc", "KeyIl", "KeyLeft",
00077 "KeyLl", "KeyNpage", "KeyPpage", "KeyRight", "KeySf", "KeySr", "KeyStab", "KeyUp",
00078 "KeypadLocal", "KeypadXmit", "LabF0", "LabF1", "LabF10", "LabF2", "LabF3", "LabF4", "LabF5",
00079 "LabF6", "LabF7", "LabF8", "LabF9", "MetaOff", "MetaOn", "Newline", "PadChar", "ParmDch",
00080 "ParmDeleteLine", "ParmDownCursor", "ParmIch", "ParmIndex", "ParmInsertLine", "ParmLeftCursor",
00081 "ParmRightCursor", "ParmRindex", "ParmUpCursor", "PkeyKey", "PkeyLocal", "PkeyXmit",
00082 "PrintScreen", "PrtrOff", "PrtrOn", "RepeatChar", "Reset1string", "Reset2string",
00083 "Reset3string", "ResetFile", "RestoreCursor", "RowAddress", "SaveCursor", "ScrollForward",
00084 "ScrollReverse", "SetAttributes", "SetTab", "SetWindow", "Tab", "ToStatusLine", "UnderlineChar",
00085 "UpHalfLine", "InitProg", "KeyA1", "KeyA3", "KeyB2", "KeyC1", "KeyC3", "PrtrNon", "CharPadding",
00086 "AcsChars", "PlabNorm", "KeyBtab", "EnterXonMode", "ExitXonMode", "EnterAmMode", "ExitAmMode",
00087 "XonCharacter", "XoffCharacter", "EnaAcs", "LabelOn", "LabelOff", "KeyBeg", "KeyCancel",
00088 "KeyClose", "KeyCommand", "KeyCopy", "KeyCreate", "KeyEnd", "KeyEnter", "KeyExit", "KeyFind",
00089 "KeyHelp", "KeyMark", "KeyMessage", "KeyMove", "KeyNext", "KeyOpen", "KeyOptions",
00090 "KeyPrevious", "KeyPrint", "KeyRedo", "KeyReference", "KeyRefresh", "KeyReplace", "KeyRestart",
00091 "KeyResume", "KeySave", "KeySuspend", "KeyUndo", "KeySbeg", "KeyScancel", "KeyScommand",
00092 "KeyScopy", "KeyScreate", "KeySdc", "KeySdl", "KeySelect", "KeySend", "KeySeol", "KeySexit",
00093 "KeySfind", "KeyShelp", "KeyShome", "KeySic", "KeySleft", "KeySmessage", "KeySmove", "KeySnext",
00094 "KeySoptions", "KeySprevious", "KeySprint", "KeySredo", "KeySreplace", "KeySright", "KeySrsume",
00095 "KeySsave", "KeySsuspend", "KeySundo", "ReqForInput", "KeyF11", "KeyF12", "KeyF13", "KeyF14",
00096 "KeyF15", "KeyF16", "KeyF17", "KeyF18", "KeyF19", "KeyF20", "KeyF21", "KeyF22", "KeyF23",
00097 "KeyF24", "KeyF25", "KeyF26", "KeyF27", "KeyF28", "KeyF29", "KeyF30", "KeyF31", "KeyF32",
00098 "KeyF33", "KeyF34", "KeyF35", "KeyF36", "KeyF37", "KeyF38", "KeyF39", "KeyF40", "KeyF41",
00099 "KeyF42", "KeyF43", "KeyF44", "KeyF45", "KeyF46", "KeyF47", "KeyF48", "KeyF49", "KeyF50",
00100 "KeyF51", "KeyF52", "KeyF53", "KeyF54", "KeyF55", "KeyF56", "KeyF57", "KeyF58", "KeyF59",
00101 "KeyF60", "KeyF61", "KeyF62", "KeyF63", "ClrBol", "ClearMargins", "SetLeftMargin",
00102 "SetRightMargin", "LabelFormat", "SetClock", "DisplayClock", "RemoveClock", "CreateWindow",
00103 "GotoWindow", "Hangup", "DialPhone", "QuickDial", "Tone", "Pulse", "FlashHook", "FixedPause",
00104 "WaitTone", "User0", "User1", "User2", "User3", "User4", "User5", "User6", "User7", "User8",
00105 "User9", "OrigPair", "OrigColors", "InitializeColor", "InitializePair", "SetColorPair",
00106 "SetForeground", "SetBackground", "ChangeCharPitch", "ChangeLinePitch", "ChangeResHorz",
00107 "ChangeResVert", "DefineChar", "EnterDoublewideMode", "EnterDraftQuality", "EnterItalicsMode",
00108 "EnterLeftwardMode", "EnterMicroMode", "EnterNearLetterQuality", "EnterNormalQuality",
00109 "EnterShadowMode", "EnterSubscriptMode", "EnterSuperscriptMode", "EnterUpwardMode",
00110 "ExitDoublewideMode", "ExitItalicsMode", "ExitLeftwardMode", "ExitMicroMode", "ExitShadowMode",
00111 "ExitSubscriptMode", "ExitSuperscriptMode", "ExitUpwardMode", "MicroColumnAddress", "MicroDown",
00112 "MicroLeft", "MicroRight", "MicroRowAddress", "MicroUp", "OrderOfPins", "ParmDownMicro",
00113 "ParmLeftMicro", "ParmRightMicro", "ParmUpMicro", "SelectCharSet", "SetBottomMargin",
00114 "SetBottomMarginParm", "SetLeftMarginParm", "SetRightMarginParm", "SetTopMargin",
00115 "SetTopMarginParm", "StartBitImage", "StartCharSetDef", "StopBitImage", "StopCharSetDef",
00116 "SubscriptCharacters", "SuperscriptCharacters", "TheseCauseCr", "ZeroMotion", "CharSetNames",
00117 "KeyMouse", "MouseInfo", "ReqMousePos", "GetMouse", "SetAForeground", "SetABackground",
00118 "PkeyPlab", "DeviceType", "CodeSetInit", "Set0DesSeq", "Set1DesSeq", "Set2DesSeq", "Set3DesSeq",
00119 "SetLrMargin", "SetTbMargin", "BitImageRepeat", "BitImageNewline", "BitImageCarriageReturn",
00120 "ColorNames", "DefineBitImageRegion", "EndBitImageRegion", "SetColorBand", "SetPageLength",
00121 "DisplayPcChar", "EnterPcCharsetMode", "ExitPcCharsetMode", "EnterScancodeMode",
00122 "ExitScancodeMode", "PcTermOptions", "ScancodeEscape", "AltScancodeEsc",
00123 "EnterHorizontalHlMode", "EnterLeftHlMode", "EnterLowHlMode", "EnterRightHlMode",
00124 "EnterTopHlMode", "EnterVerticalHlMode", "SetAAttributes", "SetPglenInch", "TermcapInit2",
00125 "TermcapReset", "LinefeedIfNotLf", "BackspaceIfNotBs", "OtherNonFunctionKeys", "ArrowKeyMap",
00126 "AcsUlcorner", "AcsLlcorner", "AcsUrcorner", "AcsLrcorner", "AcsLtee", "AcsRtee", "AcsBtee",
00127 "AcsTtee", "AcsHline", "AcsVline", "AcsPlus", "MemoryLock", "MemoryUnlock", "BoxChars1" };
00128
00129
00130
00131
00132 prefix_ senf::term::Terminfo::Terminfo()
00133 {}
00134
00135 prefix_ senf::term::Terminfo::Terminfo(std::string const & term)
00136 {
00137 load(term);
00138 }
00139
00140 prefix_ void senf::term::Terminfo::load(std::string const & term)
00141 {
00142 std::string filename (findTerminfo(term));
00143 if (filename.empty()) throw InvalidTerminfoException();
00144 std::ifstream is (filename.c_str());
00145 if (!is) throw InvalidTerminfoException();
00146 load(is);
00147 }
00148
00149 prefix_ bool senf::term::Terminfo::getFlag(properties::Boolean p)
00150 const
00151 {
00152 if (BoolVec::size_type(p) >= booleans_.size())
00153 return false;
00154 return booleans_[p];
00155 }
00156
00157 prefix_ senf::term::Terminfo::number_t senf::term::Terminfo::getNumber(properties::Numeric p)
00158 const
00159 {
00160 if (NumberVec::size_type(p) >= numbers_.size())
00161 return NoValue;
00162 return numbers_[p];
00163 }
00164
00165 prefix_ senf::term::Terminfo::string_t senf::term::Terminfo::getString(properties::String p)
00166 const
00167 {
00168 if (StringVec::size_type(p) >= strings_.size())
00169 return 0;
00170 return strings_[p];
00171 }
00172
00173 prefix_ bool senf::term::Terminfo::hasProperty(properties::Boolean p)
00174 const
00175 {
00176 return getFlag(p);
00177 }
00178
00179 prefix_ bool senf::term::Terminfo::hasProperty(properties::Numeric p)
00180 const
00181 {
00182 return getNumber(p) != NoValue;
00183 }
00184
00185 prefix_ bool senf::term::Terminfo::hasProperty(properties::String p)
00186 const
00187 {
00188 return getString(p) != 0;
00189 }
00190
00191 namespace {
00192
00193 struct Stack
00194 {
00195 std::vector<senf::term::Terminfo::number_t> stack;
00196
00197 void push(senf::term::Terminfo::number_t v)
00198 {
00199 stack.push_back(v);
00200 }
00201
00202 senf::term::Terminfo::number_t pop()
00203 {
00204 if (stack.empty())
00205 return 0;
00206 else {
00207 senf::term::Terminfo::number_t v (stack.back());
00208 stack.pop_back();
00209 return v;
00210 }
00211 }
00212
00213 senf::term::Terminfo::number_t popNonzero()
00214 {
00215 senf::term::Terminfo::number_t v (pop());
00216 return v ? v : 1;
00217 }
00218 };
00219
00220 }
00221
00222
00223
00224
00225 prefix_ std::string senf::term::Terminfo::formatString(properties::String p,
00226 number_t arg1, number_t arg2,
00227 number_t arg3, number_t arg4,
00228 number_t arg5, number_t arg6,
00229 number_t arg7, number_t arg8,
00230 number_t arg9)
00231 const
00232 {
00233 char const * fmt_p (getString(p));
00234 if (! fmt_p)
00235 return "";
00236
00237 std::string const prgstr (fmt_p);
00238 Stack stack;
00239 bool bCondValue (false);
00240 std::string result;
00241
00242 for (std::string::const_iterator i (prgstr.begin()); i != prgstr.end(); ++i) {
00243 if (*i != '%') {
00244 result += *i;
00245 continue;
00246 }
00247 int width = 0, base = 0;
00248 switch (*++i) {
00249 case '%': result += *i; break;
00250 case 'i': ++arg1; ++arg2; break;
00251 case 'c': result += char(stack.pop()); break;
00252 case 'x': base = 16; continue;
00253 case '0': if (!base) base = 8;
00254 case '1': case '2': case '3': case '4':
00255 case '5': case '6': case '7': case '8':
00256 case '9': if (!base) base = 10;
00257 width = width * base + (*i - '0');
00258 continue;
00259 case '\\': base = 0;
00260 case '{': continue;
00261 case '\'': if (*(i - 1) == '%') {
00262 if (*(i + 1) != '\\')
00263 width = *++i;
00264 continue;
00265 }
00266 case '}': stack.push(width); break;
00267
00268 case '+': stack.push(stack.pop() + stack.pop()); break;
00269 case '-': stack.push(-stack.pop() + stack.pop()); break;
00270 case '*': stack.push(stack.pop() * stack.pop()); break;
00271 case '/': stack.push(stack.pop() / stack.popNonzero()); break;
00272 case 'm': stack.push(stack.pop() % stack.popNonzero()); break;
00273 case '|': stack.push(stack.pop() | stack.pop()); break;
00274 case '&': stack.push(stack.pop() & stack.pop()); break;
00275 case '^': stack.push(stack.pop() ^ stack.pop()); break;
00276 case '>': stack.push(stack.pop() < stack.pop()); break;
00277 case '<': stack.push(stack.pop() > stack.pop()); break;
00278 case '=': stack.push(stack.pop() == stack.pop()); break;
00279 case 'A': stack.push(stack.pop() && stack.pop()); break;
00280 case 'O': stack.push(stack.pop() || stack.pop()); break;
00281 case '!': stack.push(!stack.pop()); break;
00282 case '~': stack.push(~stack.pop()); break;
00283 case 't': bCondValue = stack.pop();
00284 case 'e': if ((bCondValue = !bCondValue))
00285 --(i = prgstr.begin() + std::min (prgstr.find ("%e", i-prgstr.begin()),
00286 prgstr.find ("%;", i-prgstr.begin())));
00287 case '?':
00288 case ';': break;
00289 case 'p':
00290 switch (*++i) {
00291 case '1': stack.push(arg1); break;
00292 case '2': stack.push(arg2); break;
00293 case '3': stack.push(arg3); break;
00294 case '4': stack.push(arg4); break;
00295 case '5': stack.push(arg5); break;
00296 case '6': stack.push(arg6); break;
00297 case '7': stack.push(arg7); break;
00298 case '8': stack.push(arg8); break;
00299 case '9': stack.push(arg9); break;
00300 }
00301 break;
00302 case 'd': {
00303 number_t n = stack.pop();
00304 const std::string::size_type iSize = result.size();
00305 do {
00306 result += std::string::value_type('0' + (n % 10));
00307 } while ((n /= 10) || --width > 0);
00308 reverse (result.begin() + iSize, result.end());
00309 break; }
00310 }
00311 }
00312
00313 return result;
00314 }
00315
00316 prefix_ void senf::term::Terminfo::dump(std::ostream & os)
00317 const
00318 {
00319 os << "Terminfo entry: " << name_ << "\n";
00320 os << "Booleans: " << booleans_.size() << "\n";
00321 os << "Numbers: " << numbers_.size() << "\n";
00322 os << "Strings: " << strings_.size() << "\n";
00323 os << "String pool size: " << stringPool_.size() << "\n";
00324
00325 {
00326 os << "Flags:\n";
00327 unsigned n (0);
00328 BoolVec::const_iterator i (booleans_.begin());
00329 BoolVec::const_iterator const i_end (booleans_.end());
00330 for (; i != i_end; ++i, ++n)
00331 if (*i && n < sizeof(properties::BooleanNames)/sizeof(properties::BooleanNames[0]))
00332 os << " " << properties::BooleanNames[n] << "\n";
00333 }
00334
00335 {
00336 os << "Numbers:\n";
00337 unsigned n (0);
00338 NumberVec::const_iterator i (numbers_.begin());
00339 NumberVec::const_iterator const i_end (numbers_.end());
00340 for (; i != i_end; ++i, ++n)
00341 if (*i != NoValue
00342 && n < sizeof(properties::NumericNames)/sizeof(properties::NumericNames[0]))
00343 os << " " << properties::NumericNames[n] << " = " << *i << "\n";
00344 }
00345
00346 {
00347 os << "Strings:\n";
00348 unsigned n (0);
00349 StringVec::const_iterator i (strings_.begin());
00350 StringVec::const_iterator const i_end (strings_.end());
00351 for (; i != i_end; ++i, ++n)
00352 if (*i && n < sizeof(properties::StringNames)/sizeof(properties::StringNames[0])) {
00353 os << " " << std::setw(32) << properties::StringNames[n] << " = ";
00354 hexdump(*i, *i + strlen(*i), os, 32);
00355 }
00356 }
00357
00358 }
00359
00360 prefix_ std::string senf::term::Terminfo::findTerminfo(std::string const & name)
00361 {
00362 if (name.empty()) return "";
00363 boost::filesystem::path subdir (name.substr(0,1)); subdir /= name;
00364 boost::filesystem::path tientry;
00365
00366 {
00367 char const * tivar (::getenv("TERMINFO"));
00368 if (tivar) {
00369 tientry = boost::filesystem::path(tivar) / subdir;
00370 if (boost::filesystem::exists(tientry)) return tientry.native_file_string();
00371 }
00372 }
00373
00374 tientry = boost::filesystem::path("/etc/terminfo") / subdir;
00375 if (boost::filesystem::exists(tientry)) return tientry.native_file_string();
00376
00377 tientry = boost::filesystem::path("/lib/terminfo") / subdir;
00378 if (boost::filesystem::exists(tientry)) return tientry.native_file_string();
00379
00380 tientry = boost::filesystem::path("/usr/share/terminfo") / subdir;
00381 if (boost::filesystem::exists(tientry)) return tientry.native_file_string();
00382
00383 return "";
00384 }
00385
00386 namespace {
00387
00388 boost::uint16_t const TerminfoMagic = 0x011A;
00389
00390 struct TerminfoHeader {
00391 boost::uint16_t magic;
00392 boost::uint16_t namesSz;
00393 boost::uint16_t nBooleans;
00394 boost::uint16_t nNumbers;
00395 boost::uint16_t nStrings;
00396 boost::uint16_t stringPoolSz;
00397 };
00398
00399 }
00400
00401 prefix_ void senf::term::Terminfo::load(std::istream & is)
00402 {
00403 TerminfoHeader h;
00404 is.read(static_cast<char*>(static_cast<void*>(&h)), sizeof(h));
00405 if (!is || h.magic != TerminfoMagic) throw InvalidTerminfoException();
00406
00407 name_.resize(h.namesSz);
00408 is.read(&(name_[0]), name_.size());
00409 if (!is) throw InvalidTerminfoException();
00410 if (name_.size() & 1)
00411 is.ignore(1u);
00412 {
00413 std::string::size_type n (name_.find('\0'));
00414 if (n != std::string::npos)
00415 name_.erase(n);
00416 }
00417
00418 booleans_.resize(h.nBooleans);
00419 for (BoolVec::iterator i (booleans_.begin()); i != booleans_.end(); ++i) {
00420 char v;
00421 is.read(&v, sizeof(v));
00422 if (!is) throw InvalidTerminfoException();
00423 *i = v;
00424 }
00425 if (booleans_.size() & 1)
00426 is.ignore(1u);
00427
00428 numbers_.resize(h.nNumbers);
00429 for (NumberVec::iterator i (numbers_.begin()); i != numbers_.end(); ++i) {
00430 number_t v;
00431 is.read(static_cast<char*>(static_cast<void*>(&v)), sizeof(v));
00432 if (!is) throw InvalidTerminfoException();
00433 *i = v;
00434 }
00435
00436 typedef std::vector<number_t> OffsetVec;
00437 OffsetVec offsets;
00438 offsets.resize (h.nStrings);
00439 for (OffsetVec::iterator i (offsets.begin()); i != offsets.end(); ++i) {
00440 number_t v;
00441 is.read(static_cast<char*>(static_cast<void*>(&v)), sizeof(v));
00442 if (!is) throw InvalidTerminfoException();
00443 *i = v;
00444 }
00445
00446 stringPool_.resize(h.stringPoolSz);
00447 is.read(&(stringPool_[0]), stringPool_.size());
00448 if (!is) throw InvalidTerminfoException();
00449
00450 strings_.resize(offsets.size());
00451 StringVec::iterator j (strings_.begin());
00452 for (OffsetVec::iterator i (offsets.begin()); i != offsets.end(); ++i, ++j)
00453 if (*i != NoValue && *i >= 0 && unsigned(*i) < stringPool_.size())
00454 *j = &(stringPool_[0]) + *i;
00455 else
00456 *j = 0;
00457 }
00458
00459
00460
00461
00462 char const * const senf::term::KeyParser::KeyNames[] = {
00463 "Esc", "Backspace", "Backtab", "Begin", "CATab", "CTab", "Cancel", "Center", "Clear",
00464 "ClearToEOL", "ClearToEOS", "Close", "Command", "Copy", "Create", "Delete", "DeleteLine",
00465 "Down", "DownLeft", "DownRight", "End", "Enter", "Exit", "F0", "F1", "F2", "F3", "F4", "F5",
00466 "F6", "F7", "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", "F16", "F17", "F18", "F19",
00467 "F20", "F21", "F22", "F23", "F24", "F25", "F26", "F27", "F28", "F29", "F30", "F31", "F32",
00468 "F33", "F34", "F35", "F36", "F37", "F38", "F39", "F40", "F41", "F42", "F43", "F44", "F45",
00469 "F46", "F47", "F48", "F49", "F50", "F51", "F52", "F53", "F54", "F55", "F56", "F57", "F58",
00470 "F59", "F60", "F61", "F62", "F63", "Find", "Help", "Home", "Insert", "InsertLine", "Left",
00471 "Mark", "Message", "Mouse", "Move", "Next", "Open", "Options", "PageDown", "PageUp", "Previous",
00472 "Print", "Redo", "Reference", "Refresh", "Replace", "Restart", "Resume", "Right", "Save",
00473 "Select", "ShiftBegin", "ShiftCancel", "ShiftCommand", "ShiftCopy", "ShiftCreate",
00474 "ShiftDelete", "ShiftDeleteLine", "ShiftEnd", "ShiftClearToEOL", "ShiftExit", "ShiftFind",
00475 "ShiftHelp", "ShiftHome", "ShiftInsert", "ShiftLeft", "ShiftMessage", "ShiftMove", "ShiftNext",
00476 "ShiftOptions", "ShiftPrevious", "ShiftPrint", "ShiftRedo", "ShiftReplace", "ShiftResume",
00477 "ShiftRight", "ShiftSave", "ShiftSuspend", "ShiftTab", "ShiftUndo", "Suspend", "Undo", "Up",
00478 "UpLeft", "UpRight" };
00479
00480 prefix_ senf::term::KeyParser::KeyParser()
00481 {}
00482
00483 prefix_ senf::term::KeyParser::KeyParser(Terminfo const & ti)
00484 {
00485 load(ti);
00486 }
00487
00488 prefix_ void senf::term::KeyParser::load(Terminfo const & ti)
00489 {
00490 static Terminfo::properties::String keyStrings [] = {
00491 Terminfo::properties::KeyCommand, Terminfo::properties::KeyBackspace,
00492 Terminfo::properties::KeyBtab, Terminfo::properties::KeyBeg, Terminfo::properties::KeyCatab,
00493 Terminfo::properties::KeyCtab, Terminfo::properties::KeyCancel, Terminfo::properties::KeyB2,
00494 Terminfo::properties::KeyClear, Terminfo::properties::KeyEol, Terminfo::properties::KeyEos,
00495 Terminfo::properties::KeyClose, Terminfo::properties::KeyCommand,
00496 Terminfo::properties::KeyCopy, Terminfo::properties::KeyCreate, Terminfo::properties::KeyDc,
00497 Terminfo::properties::KeyDl, Terminfo::properties::KeyDown, Terminfo::properties::KeyC1,
00498 Terminfo::properties::KeyC3, Terminfo::properties::KeyEnd, Terminfo::properties::KeyEnter,
00499 Terminfo::properties::KeyExit, Terminfo::properties::KeyF0, Terminfo::properties::KeyF1,
00500 Terminfo::properties::KeyF2, Terminfo::properties::KeyF3, Terminfo::properties::KeyF4,
00501 Terminfo::properties::KeyF5, Terminfo::properties::KeyF6, Terminfo::properties::KeyF7,
00502 Terminfo::properties::KeyF8, Terminfo::properties::KeyF9, Terminfo::properties::KeyF10,
00503 Terminfo::properties::KeyF11, Terminfo::properties::KeyF12, Terminfo::properties::KeyF13,
00504 Terminfo::properties::KeyF14, Terminfo::properties::KeyF15, Terminfo::properties::KeyF16,
00505 Terminfo::properties::KeyF17, Terminfo::properties::KeyF18, Terminfo::properties::KeyF19,
00506 Terminfo::properties::KeyF20, Terminfo::properties::KeyF21, Terminfo::properties::KeyF22,
00507 Terminfo::properties::KeyF23, Terminfo::properties::KeyF24, Terminfo::properties::KeyF25,
00508 Terminfo::properties::KeyF26, Terminfo::properties::KeyF27, Terminfo::properties::KeyF28,
00509 Terminfo::properties::KeyF29, Terminfo::properties::KeyF30, Terminfo::properties::KeyF31,
00510 Terminfo::properties::KeyF32, Terminfo::properties::KeyF33, Terminfo::properties::KeyF34,
00511 Terminfo::properties::KeyF35, Terminfo::properties::KeyF36, Terminfo::properties::KeyF37,
00512 Terminfo::properties::KeyF38, Terminfo::properties::KeyF39, Terminfo::properties::KeyF40,
00513 Terminfo::properties::KeyF41, Terminfo::properties::KeyF42, Terminfo::properties::KeyF43,
00514 Terminfo::properties::KeyF44, Terminfo::properties::KeyF45, Terminfo::properties::KeyF46,
00515 Terminfo::properties::KeyF47, Terminfo::properties::KeyF48, Terminfo::properties::KeyF49,
00516 Terminfo::properties::KeyF50, Terminfo::properties::KeyF51, Terminfo::properties::KeyF52,
00517 Terminfo::properties::KeyF53, Terminfo::properties::KeyF54, Terminfo::properties::KeyF55,
00518 Terminfo::properties::KeyF56, Terminfo::properties::KeyF57, Terminfo::properties::KeyF58,
00519 Terminfo::properties::KeyF59, Terminfo::properties::KeyF60, Terminfo::properties::KeyF61,
00520 Terminfo::properties::KeyF62, Terminfo::properties::KeyF63, Terminfo::properties::KeyFind,
00521 Terminfo::properties::KeyHelp, Terminfo::properties::KeyHome, Terminfo::properties::KeyIc,
00522 Terminfo::properties::KeyIl, Terminfo::properties::KeyLeft, Terminfo::properties::KeyMark,
00523 Terminfo::properties::KeyMessage, Terminfo::properties::KeyMouse,
00524 Terminfo::properties::KeyMove, Terminfo::properties::KeyNext, Terminfo::properties::KeyOpen,
00525 Terminfo::properties::KeyOptions, Terminfo::properties::KeyNpage,
00526 Terminfo::properties::KeyPpage, Terminfo::properties::KeyPrevious,
00527 Terminfo::properties::KeyPrint, Terminfo::properties::KeyRedo,
00528 Terminfo::properties::KeyReference, Terminfo::properties::KeyRefresh,
00529 Terminfo::properties::KeyReplace, Terminfo::properties::KeyRestart,
00530 Terminfo::properties::KeyResume, Terminfo::properties::KeyRight,
00531 Terminfo::properties::KeySave, Terminfo::properties::KeySelect,
00532 Terminfo::properties::KeySbeg, Terminfo::properties::KeyScancel,
00533 Terminfo::properties::KeyScommand, Terminfo::properties::KeyScopy,
00534 Terminfo::properties::KeyScreate, Terminfo::properties::KeySdc,
00535 Terminfo::properties::KeySdl, Terminfo::properties::KeySend, Terminfo::properties::KeySeol,
00536 Terminfo::properties::KeySexit, Terminfo::properties::KeySfind,
00537 Terminfo::properties::KeyShelp, Terminfo::properties::KeyShome,
00538 Terminfo::properties::KeySic, Terminfo::properties::KeySleft,
00539 Terminfo::properties::KeySmessage, Terminfo::properties::KeySmove,
00540 Terminfo::properties::KeySnext, Terminfo::properties::KeySoptions,
00541 Terminfo::properties::KeySprevious, Terminfo::properties::KeySprint,
00542 Terminfo::properties::KeySredo, Terminfo::properties::KeySreplace,
00543 Terminfo::properties::KeySrsume, Terminfo::properties::KeySright,
00544 Terminfo::properties::KeySsave, Terminfo::properties::KeySsuspend,
00545 Terminfo::properties::KeyStab, Terminfo::properties::KeySundo,
00546 Terminfo::properties::KeySuspend, Terminfo::properties::KeyUndo,
00547 Terminfo::properties::KeyUp, Terminfo::properties::KeyA1, Terminfo::properties::KeyA3 };
00548
00549 table_.clear();
00550 for (unsigned i (0); i < sizeof(keyStrings)/sizeof(keyStrings[0]); ++i) {
00551 char const * key (ti.getString(keyStrings[i]));
00552 if (key)
00553 table_.insert(std::make_pair(key, KeyCode(i+First)));
00554 }
00555 }
00556
00557 prefix_ std::pair<senf::term::KeyParser::keycode_t, std::string::size_type>
00558 senf::term::KeyParser::lookup(std::string const & key)
00559 const
00560 {
00561 if (key.empty())
00562 return std::make_pair(KeyCode(0), 0);
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572 Keytable::const_iterator i (table_.upper_bound(key));
00573 if (i != table_.end() && i->first.substr(0, key.size()) == key)
00574 return std::make_pair(Incomplete, key.size());
00575 if (i == table_.begin())
00576 return std::make_pair(keycode_t(key[0]), 1);
00577 --i;
00578 if (key.substr(0, i->first.size()) == i->first)
00579 return std::make_pair(i->second, i->first.size());
00580 return std::make_pair(keycode_t(key[0]), 1);
00581 }
00582
00583 prefix_ std::string senf::term::KeyParser::describe(keycode_t key)
00584 {
00585 if (key < keycode_t(' '))
00586 return "^" + std::string(1, '@' + key);
00587 if (key < 256)
00588 return std::string(1, char(key));
00589 if (key >= keycode_t(First) && key < keycode_t(First + sizeof(KeyNames) / sizeof(KeyNames[0])))
00590 return std::string(KeyNames[key-First]);
00591 else
00592 return "<" + boost::lexical_cast<std::string>(unsigned(key)) + ">";
00593 }
00594
00595 prefix_ void senf::term::KeyParser::dump(std::ostream & os)
00596 const
00597 {
00598 os << "Keytable:\n";
00599 for (Keytable::const_iterator i (table_.begin()); i != table_.end(); ++i) {
00600 unsigned index (i->second - First);
00601 if (index < sizeof(KeyNames)/sizeof(KeyNames[0])) {
00602 std::cout << " " << std::setw(32) << KeyNames[index] << ": ";
00603 hexdump(i->first.begin(), i->first.end(), os);
00604 }
00605 }
00606 }
00607
00608
00609 #undef prefix_
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621