Search:

SENF Extensible Network Framework

  • Home
  • Download
  • Wiki
  • BerliOS
  • ChangeLog
  • Browse SVN
  • Bug Tracker
  • Overview
  • Examples
  • HowTos
  • Glossary
  • PPI
  • Packets
  • Scheduler
  • Socket
  • Utils
  • Console
  • Daemon
  • Logger
  • Termlib
  • Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

Terminfo.cc

Go to the documentation of this file.
00001 // $Id: Terminfo.cc 1742 2010-11-04 14:51:56Z g0dil $
00002 //
00003 // Copyright (C) 2009
00004 // Fraunhofer (FOKUS)
00005 // Competence Center NETwork research (NET), St. Augustin, GERMANY
00006 //     Stefan Bund <g0dil@berlios.de>
00007 //
00008 // This program is free software; you can redistribute it and/or modify
00009 // it under the terms of the GNU General Public License as published by
00010 // the Free Software Foundation; either version 2 of the License, or
00011 // (at your option) any later version.
00012 //
00013 // This program is distributed in the hope that it will be useful,
00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 // GNU General Public License for more details.
00017 //
00018 // You should have received a copy of the GNU General Public License
00019 // along with this program; if not, write to the
00020 // Free Software Foundation, Inc.,
00021 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00022 
00026 #include "Terminfo.hh"
00027 //#include "Terminfo.ih"
00028 
00029 // Custom includes
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 //#include "Terminfo.mpp"
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 // senf::term::Terminfo
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 // The following code is taken directly from utio. As far as I understand it is buggy
00223 // and/or only partially implements the string format language. But seems to be enough for
00224 // all the common terminal types ...
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         // Binary operands are in infix (reversed) order
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)) // this also supports elsif
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 // senf::term::KeyParser
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     // There are several cases:
00565     // a) 'key' is an incomplete key sequence. In this case, 'key' will precede all completions in
00566     //    the key table. The first possible completion is found by 'upper_bound'
00567     // b) 'key' is a complete key sequence. This is the key sequence *preceding* the 'upper_bound'
00568     // c) 'key' is a complete key sequence with additional trailing characters. In this case, 'key'
00569     //    will follow the correct entry in the key table. Again, the correct key sequence is
00570     //    the one preceding the 'upper_bound'
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 //#include "Terminfo.mpp"
00611 
00612 
00613 // Local Variables:
00614 // mode: c++
00615 // fill-column: 100
00616 // comment-column: 40
00617 // c-file-style: "senf"
00618 // indent-tabs-mode: nil
00619 // ispell-local-dictionary: "american"
00620 // compile-command: "scons -u test"
00621 // End:

Contact: senf-dev@lists.berlios.de | © 2006-2010 Fraunhofer Institute for Open Communication Systems, Network Research