From 472156a41b1348c714986c772759ad950fffbe75 Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Sun, 27 Jan 2013 15:11:21 -0600 Subject: Rename kioslaves --- tdeioslave/man/CMakeLists.txt | 10 +- tdeioslave/man/Makefile.am | 24 +- tdeioslave/man/kio_man.cpp | 1533 ------------------------------------- tdeioslave/man/kio_man.css | 21 - tdeioslave/man/kio_man.h | 100 --- tdeioslave/man/kio_man_test.cpp | 38 - tdeioslave/man/man.protocol | 2 +- tdeioslave/man/man2html.cpp | 2 +- tdeioslave/man/tdeio_man.cpp | 1533 +++++++++++++++++++++++++++++++++++++ tdeioslave/man/tdeio_man.css | 21 + tdeioslave/man/tdeio_man.h | 100 +++ tdeioslave/man/tdeio_man_test.cpp | 38 + 12 files changed, 1711 insertions(+), 1711 deletions(-) delete mode 100644 tdeioslave/man/kio_man.cpp delete mode 100644 tdeioslave/man/kio_man.css delete mode 100644 tdeioslave/man/kio_man.h delete mode 100644 tdeioslave/man/kio_man_test.cpp create mode 100644 tdeioslave/man/tdeio_man.cpp create mode 100644 tdeioslave/man/tdeio_man.css create mode 100644 tdeioslave/man/tdeio_man.h create mode 100644 tdeioslave/man/tdeio_man_test.cpp (limited to 'tdeioslave/man') diff --git a/tdeioslave/man/CMakeLists.txt b/tdeioslave/man/CMakeLists.txt index fca109df0..ad3ed012b 100644 --- a/tdeioslave/man/CMakeLists.txt +++ b/tdeioslave/man/CMakeLists.txt @@ -9,7 +9,7 @@ # ################################################# -# FIXME not built: man2html, kio_man_test +# FIXME not built: man2html, tdeio_man_test ##### system checks ############################# @@ -35,15 +35,15 @@ link_directories( ##### other data ################################ install( FILES man.protocol kmanpart.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) -install( FILES kio_man.css DESTINATION ${DATA_INSTALL_DIR}/tdeio_man ) +install( FILES tdeio_man.css DESTINATION ${DATA_INSTALL_DIR}/tdeio_man ) -##### kio_man (module) ########################## +##### tdeio_man (module) ########################## -set( target kio_man ) +set( target tdeio_man ) tde_add_kpart( ${target} AUTOMOC - SOURCES man2html.cpp kio_man.cpp + SOURCES man2html.cpp tdeio_man.cpp LINK tdeio-shared DESTINATION ${PLUGIN_INSTALL_DIR} ) diff --git a/tdeioslave/man/Makefile.am b/tdeioslave/man/Makefile.am index d43edb74d..7b2554ba0 100644 --- a/tdeioslave/man/Makefile.am +++ b/tdeioslave/man/Makefile.am @@ -3,22 +3,22 @@ INCLUDES= $(all_includes) AM_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_KIO) -ltdetexteditor -EXTRA_PROGRAMS = kio_man_test man2html +EXTRA_PROGRAMS = tdeio_man_test man2html ####### just for testing (j.habenicht@europemail.com, 15.02.2001) -kio_man_test_SOURCES = kio_man_test.cpp -kio_man_test_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_KIO) -ltdetexteditor -kio_man_test_LDADD = man2html.lo kio_man.lo $(LIB_KIO) $(LIB_TDEUI) $(LIB_TDECORE) $(LIB_QT) +tdeio_man_test_SOURCES = tdeio_man_test.cpp +tdeio_man_test_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_KIO) -ltdetexteditor +tdeio_man_test_LDADD = man2html.lo tdeio_man.lo $(LIB_KIO) $(LIB_TDEUI) $(LIB_TDECORE) $(LIB_QT) ####### Files -kde_module_LTLIBRARIES = kio_man.la libkmanpart.la +kde_module_LTLIBRARIES = tdeio_man.la libkmanpart.la -kio_man_la_SOURCES = man2html.cpp kio_man.cpp -kio_man_la_LIBADD = $(LIB_KSYCOCA) -kio_man_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) -noinst_HEADERS = kio_man.h +tdeio_man_la_SOURCES = man2html.cpp tdeio_man.cpp +tdeio_man_la_LIBADD = $(LIB_KSYCOCA) +tdeio_man_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +noinst_HEADERS = tdeio_man.h ### TODO Why is man2htmk.h distributed? libkmanpart_la_SOURCES = kmanpart.cpp @@ -28,9 +28,9 @@ libkmanpart_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) kdelnk_DATA = man.protocol kmanpart.desktop kdelnkdir = $(kde_servicesdir) -kio_man_data_DATA = kio_man.css -kio_man_datadir = $(kde_datadir)/tdeio_man -EXTRA_DIST=$(kio_man_data_DATA) +tdeio_man_data_DATA = tdeio_man.css +tdeio_man_datadir = $(kde_datadir)/tdeio_man +EXTRA_DIST=$(tdeio_man_data_DATA) METASOURCES = AUTO diff --git a/tdeioslave/man/kio_man.cpp b/tdeioslave/man/kio_man.cpp deleted file mode 100644 index d2ef8cb94..000000000 --- a/tdeioslave/man/kio_man.cpp +++ /dev/null @@ -1,1533 +0,0 @@ -/* This file is part of the KDE libraries - Copyright (c) 2000 Matthias Hoelzer-Kluepfel - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "kio_man.h" -#include "kio_man.moc" -#include "man2html.h" -#include -#include -#include - -using namespace TDEIO; - -MANProtocol *MANProtocol::_self = 0; - -#define SGML2ROFF_DIRS "/usr/lib/sgml" - -/* - * Drop trailing ".section[.gz]" from name - */ -static -void stripExtension( TQString *name ) -{ - int pos = name->length(); - - if ( name->find(".gz", -3) != -1 ) - pos -= 3; - else if ( name->find(".z", -2, false) != -1 ) - pos -= 2; - else if ( name->find(".bz2", -4) != -1 ) - pos -= 4; - else if ( name->find(".bz", -3) != -1 ) - pos -= 3; - - if ( pos > 0 ) - pos = name->findRev('.', pos-1); - - if ( pos > 0 ) - name->truncate( pos ); -} - -static -bool parseUrl(const TQString& _url, TQString &title, TQString §ion) -{ - section = TQString::null; - - TQString url = _url; - if (url.at(0) == '/') { - if (KStandardDirs::exists(url)) { - title = url; - return true; - } else - { - // If the directory does not exist, then it is perhaps a normal man page - kdDebug(7107) << url << " does not exist" << endl; - } - } - - while (url.at(0) == '/') - url.remove(0,1); - - title = url; - - int pos = url.find('('); - if (pos < 0) - return true; - - title = title.left(pos); - - section = url.mid(pos+1); - section = section.left(section.length()-1); - - return true; -} - - -MANProtocol::MANProtocol(const TQCString &pool_socket, const TQCString &app_socket) - : TQObject(), SlaveBase("man", pool_socket, app_socket) -{ - assert(!_self); - _self = this; - const TQString common_dir = TDEGlobal::dirs()->findResourceDir( "html", "en/common/kde-common.css" ); - const TQString strPath=TQString( "file:%1/en/common" ).arg( common_dir ); - m_htmlPath=strPath.local8Bit(); // ### TODO encode for HTML - m_cssPath=strPath.local8Bit(); // ### TODO encode for CSS - section_names << "1" << "2" << "3" << "3n" << "3p" << "4" << "5" << "6" << "7" - << "8" << "9" << "l" << "n"; - m_manCSSFile = locate( "data", "kio_man/tdeio_man.css" ); -} - -MANProtocol *MANProtocol::self() { return _self; } - -MANProtocol::~MANProtocol() -{ - _self = 0; -} - -void MANProtocol::parseWhatIs( TQMap &i, TQTextStream &t, const TQString &mark ) -{ - TQRegExp re( mark ); - TQString l; - while ( !t.atEnd() ) - { - l = t.readLine(); - int pos = re.search( l ); - if (pos != -1) - { - TQString names = l.left(pos); - TQString descr = l.mid(pos + re.matchedLength()); - while ((pos = names.find(",")) != -1) - { - i[names.left(pos++)] = descr; - while (names[pos] == ' ') - pos++; - names = names.mid(pos); - } - i[names] = descr; - } - } -} - -bool MANProtocol::addWhatIs(TQMap &i, const TQString &name, const TQString &mark) -{ - TQFile f(name); - if (!f.open(IO_ReadOnly)) - return false; - TQTextStream t(&f); - parseWhatIs( i, t, mark ); - return true; -} - -TQMap MANProtocol::buildIndexMap(const TQString §ion) -{ - TQMap i; - TQStringList man_dirs = manDirectories(); - // Supplementary places for whatis databases - man_dirs += m_mandbpath; - if (man_dirs.find("/var/cache/man")==man_dirs.end()) - man_dirs << "/var/cache/man"; - if (man_dirs.find("/var/catman")==man_dirs.end()) - man_dirs << "/var/catman"; - - TQStringList names; - names << "whatis.db" << "whatis"; - TQString mark = "\\s+\\(" + section + "[a-z]*\\)\\s+-\\s+"; - - for ( TQStringList::ConstIterator it_dir = man_dirs.begin(); - it_dir != man_dirs.end(); - ++it_dir ) - { - if ( TQFile::exists( *it_dir ) ) { - TQStringList::ConstIterator it_name; - for ( it_name = names.begin(); - it_name != names.end(); - it_name++ ) - { - if (addWhatIs(i, (*it_dir) + "/" + (*it_name), mark)) - break; - } - if ( it_name == names.end() ) { - TDEProcess proc; - proc << "whatis" << "-M" << (*it_dir) << "-w" << "*"; - myStdStream = TQString::null; - connect( &proc, TQT_SIGNAL( receivedStdout(TDEProcess *, char *, int ) ), - TQT_SLOT( slotGetStdOutput( TDEProcess *, char *, int ) ) ); - proc.start( TDEProcess::Block, TDEProcess::Stdout ); - TQTextStream t( &myStdStream, IO_ReadOnly ); - parseWhatIs( i, t, mark ); - } - } - } - return i; -} - -TQStringList MANProtocol::manDirectories() -{ - checkManPaths(); - // - // Build a list of man directories including translations - // - TQStringList man_dirs; - - for ( TQStringList::ConstIterator it_dir = m_manpath.begin(); - it_dir != m_manpath.end(); - it_dir++ ) - { - // Translated pages in "/" if the directory - // exists - TQStringList languages = TDEGlobal::locale()->languageList(); - - for (TQStringList::ConstIterator it_lang = languages.begin(); - it_lang != languages.end(); - it_lang++ ) - { - if ( !(*it_lang).isEmpty() && (*it_lang) != TQString("C") ) { - TQString dir = (*it_dir) + '/' + (*it_lang); - - struct stat sbuf; - - if ( ::stat( TQFile::encodeName( dir ), &sbuf ) == 0 - && S_ISDIR( sbuf.st_mode ) ) - { - const TQString p = TQDir(dir).canonicalPath(); - if (!man_dirs.contains(p)) man_dirs += p; - } - } - } - - // Untranslated pages in "" - const TQString p = TQDir(*it_dir).canonicalPath(); - if (!man_dirs.contains(p)) man_dirs += p; - } - return man_dirs; -} - -TQStringList MANProtocol::findPages(const TQString &_section, - const TQString &title, - bool full_path) -{ - TQString section = _section; - - TQStringList list; - - // kdDebug() << "findPages '" << section << "' '" << title << "'\n"; - if (title.at(0) == '/') { - list.append(title); - return list; - } - - const TQString star( "*" ); - - // - // Find man sections in this directory - // - TQStringList sect_list; - if ( section.isEmpty() ) - section = star; - - if ( section != star ) - { - // - // Section given as argument - // - sect_list += section; - while (section.at(section.length() - 1).isLetter()) { - section.truncate(section.length() - 1); - sect_list += section; - } - } else { - sect_list += section; - } - - TQStringList man_dirs = manDirectories(); - - // - // Find man pages in the sections listed above - // - for ( TQStringList::ConstIterator it_sect = sect_list.begin(); - it_sect != sect_list.end(); - it_sect++ ) - { - TQString it_real = (*it_sect).lower(); - // - // Find pages - // - for ( TQStringList::ConstIterator it_dir = man_dirs.begin(); - it_dir != man_dirs.end(); - it_dir++ ) - { - TQString man_dir = (*it_dir); - - // - // Sections = all sub directories "man*" and "sman*" - // - DIR *dp = ::opendir( TQFile::encodeName( man_dir ) ); - - if ( !dp ) - continue; - - struct dirent *ep; - - const TQString man = TQString("man"); - const TQString sman = TQString("sman"); - - while ( (ep = ::readdir( dp )) != 0L ) { - const TQString file = TQFile::decodeName( ep->d_name ); - TQString sect = TQString::null; - - if ( file.startsWith( man ) ) - sect = file.mid(3); - else if (file.startsWith(sman)) - sect = file.mid(4); - - if (sect.lower()==it_real) it_real = sect; - - // Only add sect if not already contained, avoid duplicates - if (!sect_list.contains(sect) && _section.isEmpty()) { - kdDebug() << "another section " << sect << endl; - sect_list += sect; - } - } - - ::closedir( dp ); - - if ( *it_sect != star ) { // in that case we only look around for sections - const TQString dir = man_dir + TQString("/man") + (it_real) + '/'; - const TQString sdir = man_dir + TQString("/sman") + (it_real) + '/'; - - findManPagesInSection(dir, title, full_path, list); - findManPagesInSection(sdir, title, full_path, list); - } - } - } - -// kdDebug(7107) << "finished " << list << " " << sect_list << endl; - - return list; -} - -void MANProtocol::findManPagesInSection(const TQString &dir, const TQString &title, bool full_path, TQStringList &list) -{ - kdDebug() << "findManPagesInSection " << dir << " " << title << endl; - bool title_given = !title.isEmpty(); - - DIR *dp = ::opendir( TQFile::encodeName( dir ) ); - - if ( !dp ) - return; - - struct dirent *ep; - - while ( (ep = ::readdir( dp )) != 0L ) { - if ( ep->d_name[0] != '.' ) { - - TQString name = TQFile::decodeName( ep->d_name ); - - // check title if we're looking for a specific page - if ( title_given ) { - if ( !name.startsWith( title ) ) { - continue; - } - else { - // beginning matches, do a more thorough check... - TQString tmp_name = name; - stripExtension( &tmp_name ); - if ( tmp_name != title ) - continue; - } - } - - if ( full_path ) - name.prepend( dir ); - - list += name ; - } - } - ::closedir( dp ); -} - -void MANProtocol::output(const char *insert) -{ - if (insert) - { - m_outputBuffer.writeBlock(insert,strlen(insert)); - } - if (!insert || m_outputBuffer.at() >= 2048) - { - m_outputBuffer.close(); - data(m_outputBuffer.buffer()); - m_outputBuffer.setBuffer(TQByteArray()); - m_outputBuffer.open(IO_WriteOnly); - } -} - -// called by man2html -char *read_man_page(const char *filename) -{ - return MANProtocol::self()->readManPage(filename); -} - -// called by man2html -void output_real(const char *insert) -{ - MANProtocol::self()->output(insert); -} - -static TQString text2html(const TQString& txt) -{ - TQString reply = txt; - - reply = reply.replace('&', "&"); - reply = reply.replace('<', "<"); - reply = reply.replace('>', ">"); - reply = reply.replace('"', "&dquot;"); - reply = reply.replace('\'', """); - return reply; -} - -void MANProtocol::get(const KURL& url ) -{ - kdDebug(7107) << "GET " << url.url() << endl; - - TQString title, section; - - if (!parseUrl(url.path(), title, section)) - { - showMainIndex(); - return; - } - - // see if an index was requested - if (url.query().isEmpty() && (title.isEmpty() || title == "/" || title == ".")) - { - if (section == "index" || section.isEmpty()) - showMainIndex(); - else - showIndex(section); - return; - } - - // tell the mimetype - mimeType("text/html"); - - const TQStringList foundPages=findPages(section, title); - bool pageFound=true; - if (foundPages.isEmpty()) - { - outputError(i18n("No man page matching to %1 found.

" - "Check that you have not mistyped the name of the page that you want.\n" - "Be careful that you must take care about upper case and lower case characters!
" - "If everything looks correct, then perhaps you need to set a better search path " - "for man pages, be it by the environment variable MANPATH or a matching file " - "in the directory /etc .").arg(text2html(title))); - pageFound=false; - } - else if (foundPages.count()>1) - { - pageFound=false; - //check for the case that there is foo.1 and foo.1.gz found: - // ### TODO make it more generic (other extensions) - if ((foundPages.count()==2) && - (((foundPages[0]+".gz") == foundPages[1]) || - (foundPages[0] == (foundPages[1]+".gz")))) - pageFound=true; - else - outputMatchingPages(foundPages); - } - //yes, we found exactly one man page - - if (pageFound) - { - setResourcePath(m_htmlPath,m_cssPath); - m_outputBuffer.open(IO_WriteOnly); - const TQCString filename=TQFile::encodeName(foundPages[0]); - char *buf = readManPage(filename); - - if (!buf) - { - outputError(i18n("Open of %1 failed.").arg(title)); - finished(); - return; - } - // will call output_real - scan_man_page(buf); - delete [] buf; - - output(0); // flush - - m_outputBuffer.close(); - data(m_outputBuffer.buffer()); - m_outputBuffer.setBuffer(TQByteArray()); - // tell we are done - data(TQByteArray()); - } - finished(); -} - -void MANProtocol::slotGetStdOutput(TDEProcess* /* p */, char *s, int len) -{ - myStdStream += TQString::fromLocal8Bit(s, len); -} - -void MANProtocol::slotGetStdOutputUtf8(TDEProcess* /* p */, char *s, int len) -{ - myStdStream += TQString::fromUtf8(s, len); -} - -char *MANProtocol::readManPage(const char *_filename) -{ - TQCString filename = _filename; - - char *buf = NULL; - - /* Determine type of man page file by checking its path. Determination by - * MIME type with KMimeType doesn't work reliablely. E.g., Solaris 7: - * /usr/man/sman7fs/pcfs.7fs -> text/x-csrc : WRONG - * If the path name constains the string sman, assume that it's SGML and - * convert it to roff format (used on Solaris). */ - //TQString file_mimetype = KMimeType::findByPath(TQString(filename), 0, false)->name(); - if (filename.contains("sman", false)) //file_mimetype == "text/html" || ) - { - myStdStream =TQString::null; - TDEProcess proc; - - /* Determine path to sgml2roff, if not already done. */ - getProgramPath(); - proc << mySgml2RoffPath << filename; - - TQApplication::connect(&proc, TQT_SIGNAL(receivedStdout (TDEProcess *, char *, int)), - this, TQT_SLOT(slotGetStdOutput(TDEProcess *, char *, int))); - proc.start(TDEProcess::Block, TDEProcess::All); - - const TQCString cstr=myStdStream.latin1(); - const int len = cstr.size()-1; - buf = new char[len + 4]; - tqmemmove(buf + 1, cstr.data(), len); - buf[0]=buf[len]='\n'; // Start and end with a end of line - buf[len+1]=buf[len+2]='\0'; // Two additional NUL characters at end - } - else - { - if (TQDir::isRelativePath(filename)) { - kdDebug(7107) << "relative " << filename << endl; - filename = TQDir::cleanDirPath(lastdir + "/" + filename).utf8(); - if (!KStandardDirs::exists(filename)) { // exists perhaps with suffix - lastdir = filename.left(filename.findRev('/')); - TQDir mandir(lastdir); - mandir.setNameFilter(filename.mid(filename.findRev('/') + 1) + ".*"); - filename = lastdir + "/" + TQFile::encodeName(mandir.entryList().first()); - } - kdDebug(7107) << "resolved to " << filename << endl; - } - lastdir = filename.left(filename.findRev('/')); - - myStdStream = TQString::null; - TDEProcess proc; - /* TODO: detect availability of 'man --recode' so that this can go - * upstream */ - proc << "man" << "--recode" << "UTF-8" << filename; - - TQApplication::connect(&proc, TQT_SIGNAL(receivedStdout (TDEProcess *, char *, int)), - this, TQT_SLOT(slotGetStdOutputUtf8(TDEProcess *, char *, int))); - proc.start(TDEProcess::Block, TDEProcess::All); - - const TQCString cstr=myStdStream.utf8(); - const int len = cstr.size()-1; - buf = new char[len + 4]; - tqmemmove(buf + 1, cstr.data(), len); - buf[0]=buf[len]='\n'; // Start and end with a end of line - buf[len+1]=buf[len+2]='\0'; // Two NUL characters at end - } - return buf; -} - - -void MANProtocol::outputError(const TQString& errmsg) -{ - TQByteArray array; - TQTextStream os(array, IO_WriteOnly); - os.setEncoding(TQTextStream::UnicodeUTF8); - - os << "" << endl; - os << "" << endl; - os << "" << i18n("Man output") << "\n" << endl; - if ( !m_manCSSFile.isEmpty() ) - os << "" << endl; - os << "" << endl; - os << i18n("

TDE Man Viewer Error

") << errmsg << "" << endl; - os << "" << endl; - - data(array); -} - -void MANProtocol::outputMatchingPages(const TQStringList &matchingPages) -{ - TQByteArray array; - TQTextStream os(array, IO_WriteOnly); - os.setEncoding(TQTextStream::UnicodeUTF8); - - os << "" << endl; - os << "\n"<" << i18n("Man output") <<"" << endl; - if ( !m_manCSSFile.isEmpty() ) - os << "" << endl; - os << "" <

" << i18n("There is more than one matching man page."); - os << "

\n
    \n"; - - int acckey=1; - for (TQStringList::ConstIterator it = matchingPages.begin(); it != matchingPages.end(); ++it) - { - os<<"
  • "<< *it <<"
    \n
    \n"; - acckey++; - } - os << "
\n"; - os << "
\n"; - os << "

" << i18n("Note: if you read a man page in your language," - " be aware it can contain some mistakes or be obsolete." - " In case of doubt, you should have a look at the English version.") << "

"; - - os << "\n"<" << endl; - os << "" << endl; - os << "" << i18n("UNIX Manual Index") << "" << endl; - if (!m_manCSSFile.isEmpty()) - os << "" << endl; - os << "" << endl; - os << "

" << i18n("UNIX Manual Index") << "

" << endl; - - // ### TODO: why still the environment variable - const TQString sectList = getenv("MANSECT"); - TQStringList sections; - if (sectList.isEmpty()) - sections = buildSectionList(manDirectories()); - else - sections = TQStringList::split(':', sectList); - - os << "" << endl; - - TQStringList::ConstIterator it; - for (it = sections.begin(); it != sections.end(); ++it) - os << "" << endl; - - os << "
" << i18n("Section ") - << *it << "  " << sectionName(*it) << "
" << endl; - - // print footer - os << "" << endl; - - data(array); - finished(); -} - -void MANProtocol::constructPath(TQStringList& constr_path, TQStringList constr_catmanpath) -{ - TQMap manpath_map; - TQMap mandb_map; - - // Add paths from /etc/man.conf - // - // Explicit manpaths may be given by lines starting with "MANPATH" or - // "MANDATORY_MANPATH" (depending on system ?). - // Mappings from $PATH to manpath are given by lines starting with - // "MANPATH_MAP" - - TQRegExp manpath_regex( "^MANPATH\\s" ); - TQRegExp mandatory_regex( "^MANDATORY_MANPATH\\s" ); - TQRegExp manpath_map_regex( "^MANPATH_MAP\\s" ); - TQRegExp mandb_map_regex( "^MANDB_MAP\\s" ); - //TQRegExp section_regex( "^SECTION\\s" ); - TQRegExp space_regex( "\\s+" ); // for parsing manpath map - - TQFile mc("/etc/man.conf"); // Caldera - if (!mc.exists()) - mc.setName("/etc/manpath.config"); // SuSE, Debian - if (!mc.exists()) - mc.setName("/etc/man.config"); // Mandrake - - if (mc.open(IO_ReadOnly)) - { - TQTextStream is(&mc); - is.setEncoding(TQTextStream::Locale); - - while (!is.eof()) - { - const TQString line = is.readLine(); - if ( manpath_regex.search(line, 0) == 0 ) - { - const TQString path = line.mid(8).stripWhiteSpace(); - constr_path += path; - } - else if ( mandatory_regex.search(line, 0) == 0 ) - { - const TQString path = line.mid(18).stripWhiteSpace(); - constr_path += path; - } - else if ( manpath_map_regex.search(line, 0) == 0 ) - { - // The entry is "MANPATH_MAP " - const TQStringList mapping = - TQStringList::split(space_regex, line); - - if ( mapping.count() == 3 ) - { - const TQString dir = TQDir::cleanDirPath( mapping[1] ); - const TQString mandir = TQDir::cleanDirPath( mapping[2] ); - - manpath_map[ dir ] = mandir; - } - } - else if ( mandb_map_regex.search(line, 0) == 0 ) - { - // The entry is "MANDB_MAP " - const TQStringList mapping = - TQStringList::split(space_regex, line); - - if ( mapping.count() == 3 ) - { - const TQString mandir = TQDir::cleanDirPath( mapping[1] ); - const TQString catmandir = TQDir::cleanDirPath( mapping[2] ); - - mandb_map[ mandir ] = catmandir; - } - } - /* sections are not used - else if ( section_regex.find(line, 0) == 0 ) - { - if ( !conf_section.isEmpty() ) - conf_section += ':'; - conf_section += line.mid(8).stripWhiteSpace(); - } - */ - } - mc.close(); - } - - // Default paths - static const char *manpaths[] = { - "/usr/X11/man", - "/usr/X11R6/man", - "/usr/man", - "/usr/local/man", - "/usr/exp/man", - "/usr/openwin/man", - "/usr/dt/man", - "/opt/freetool/man", - "/opt/local/man", - "/usr/tex/man", - "/usr/www/man", - "/usr/lang/man", - "/usr/gnu/man", - "/usr/share/man", - "/usr/motif/man", - "/usr/titools/man", - "/usr/sunpc/man", - "/usr/ncd/man", - "/usr/newsprint/man", - NULL }; - - - int i = 0; - while (manpaths[i]) { - if ( constr_path.findIndex( TQString( manpaths[i] ) ) == -1 ) - constr_path += TQString( manpaths[i] ); - i++; - } - - // Directories in $PATH - // - if a manpath mapping exists, use that mapping - // - if a directory "/man" or "/../man" exists, add it - // to the man path (the actual existence check is done further down) - - if ( ::getenv("PATH") ) { - const TQStringList path = - TQStringList::split( ":", - TQString::fromLocal8Bit( ::getenv("PATH") ) ); - - for ( TQStringList::const_iterator it = path.begin(); - it != path.end(); - ++it ) - { - const TQString dir = TQDir::cleanDirPath( *it ); - TQString mandir = manpath_map[ dir ]; - - if ( !mandir.isEmpty() ) { - // a path mapping exists - if ( constr_path.findIndex( mandir ) == -1 ) - constr_path += mandir; - } - else { - // no manpath mapping, use "/man" and "/../man" - - mandir = dir + TQString( "/man" ); - if ( constr_path.findIndex( mandir ) == -1 ) - constr_path += mandir; - - int pos = dir.findRev( '/' ); - if ( pos > 0 ) { - mandir = dir.left( pos ) + TQString("/man"); - if ( constr_path.findIndex( mandir ) == -1 ) - constr_path += mandir; - } - } - TQString catmandir = mandb_map[ mandir ]; - if ( !mandir.isEmpty() ) - { - if ( constr_catmanpath.findIndex( catmandir ) == -1 ) - constr_catmanpath += catmandir; - } - else - { - // What is the default mapping? - catmandir = mandir; - catmandir.replace("/usr/share/","/var/cache/"); - if ( constr_catmanpath.findIndex( catmandir ) == -1 ) - constr_catmanpath += catmandir; - } - } - } -} - -void MANProtocol::checkManPaths() -{ - static bool inited = false; - - if (inited) - return; - - inited = true; - - const TQString manpath_env = TQString::fromLocal8Bit( ::getenv("MANPATH") ); - //TQString mansect_env = TQString::fromLocal8Bit( ::getenv("MANSECT") ); - - // Decide if $MANPATH is enough on its own or if it should be merged - // with the constructed path. - // A $MANPATH starting or ending with ":", or containing "::", - // should be merged with the constructed path. - - bool construct_path = false; - - if ( manpath_env.isEmpty() - || manpath_env[0] == ':' - || manpath_env[manpath_env.length()-1] == ':' - || manpath_env.contains( "::" ) ) - { - construct_path = true; // need to read config file - } - - // Constucted man path -- consists of paths from - // /etc/man.conf - // default dirs - // $PATH - TQStringList constr_path; - TQStringList constr_catmanpath; // catmanpath - - TQString conf_section; - - if ( construct_path ) - { - constructPath(constr_path, constr_catmanpath); - } - - m_mandbpath=constr_catmanpath; - - // Merge $MANPATH with the constructed path to form the - // actual manpath. - // - // The merging syntax with ":" and "::" in $MANPATH will be - // satisfied if any empty string in path_list_env (there - // should be 1 or 0) is replaced by the constructed path. - - const TQStringList path_list_env = TQStringList::split( ':', manpath_env , true ); - - for ( TQStringList::const_iterator it = path_list_env.begin(); - it != path_list_env.end(); - ++it ) - { - struct stat sbuf; - - TQString dir = (*it); - - if ( !dir.isEmpty() ) { - // Add dir to the man path if it exists - if ( m_manpath.findIndex( dir ) == -1 ) { - if ( ::stat( TQFile::encodeName( dir ), &sbuf ) == 0 - && S_ISDIR( sbuf.st_mode ) ) - { - m_manpath += dir; - } - } - } - else { - // Insert constructed path ($MANPATH was empty, or - // there was a ":" at an end or "::") - - for ( TQStringList::Iterator it2 = constr_path.begin(); - it2 != constr_path.end(); - it2++ ) - { - dir = (*it2); - - if ( !dir.isEmpty() ) { - if ( m_manpath.findIndex( dir ) == -1 ) { - if ( ::stat( TQFile::encodeName( dir ), &sbuf ) == 0 - && S_ISDIR( sbuf.st_mode ) ) - { - m_manpath += dir; - } - } - } - } - } - } - -/* sections are not used - // Sections - TQStringList m_mansect = TQStringList::split( ':', mansect_env, true ); - - const char* default_sect[] = - { "1", "2", "3", "4", "5", "6", "7", "8", "9", "n", 0L }; - - for ( int i = 0; default_sect[i] != 0L; i++ ) - if ( m_mansect.findIndex( TQString( default_sect[i] ) ) == -1 ) - m_mansect += TQString( default_sect[i] ); -*/ - -} - - -//#define _USE_OLD_CODE - -#ifdef _USE_OLD_CODE -#warning "using old code" -#else - -// Define this, if you want to compile with qsort from stdlib.h -// else the Qt Heapsort will be used. -// Note, qsort seems to be a bit faster (~10%) on a large man section -// eg. man section 3 -#define _USE_QSORT - -// Setup my own structure, with char pointers. -// from now on only pointers are copied, no strings -// -// containing the whole path string, -// the beginning of the man page name -// and the length of the name -struct man_index_t { - char *manpath; // the full path including man file - const char *manpage_begin; // pointer to the begin of the man file name in the path - int manpage_len; // len of the man file name -}; -typedef man_index_t *man_index_ptr; - -#ifdef _USE_QSORT -int compare_man_index(const void *s1, const void *s2) -{ - struct man_index_t *m1 = *(struct man_index_t **)s1; - struct man_index_t *m2 = *(struct man_index_t **)s2; - int i; - // Compare the names of the pages - // with the shorter length. - // Man page names are not '\0' terminated, so - // this is a bit tricky - if ( m1->manpage_len > m2->manpage_len) - { - i = tqstrnicmp( m1->manpage_begin, - m2->manpage_begin, - m2->manpage_len); - if (!i) - return 1; - return i; - } - - if ( m1->manpage_len < m2->manpage_len) - { - i = tqstrnicmp( m1->manpage_begin, - m2->manpage_begin, - m1->manpage_len); - if (!i) - return -1; - return i; - } - - return tqstrnicmp( m1->manpage_begin, - m2->manpage_begin, - m1->manpage_len); -} - -#else /* !_USE_QSORT */ -#warning using heapsort -// Set up my own man page list, -// with a special compare function to sort itself -typedef TQPtrList QManIndexListBase; -typedef TQPtrListIterator QManIndexListIterator; - -class QManIndexList : public QManIndexListBase -{ -public: -private: - int compareItems( TQPtrCollection::Item s1, TQPtrCollection::Item s2 ) - { - struct man_index_t *m1 = (struct man_index_t *)s1; - struct man_index_t *m2 = (struct man_index_t *)s2; - int i; - // compare the names of the pages - // with the shorter length - if (m1->manpage_len > m2->manpage_len) - { - i = tqstrnicmp(m1->manpage_begin, - m2->manpage_begin, - m2->manpage_len); - if (!i) - return 1; - return i; - } - - if (m1->manpage_len > m2->manpage_len) - { - - i = tqstrnicmp(m1->manpage_begin, - m2->manpage_begin, - m1->manpage_len); - if (!i) - return -1; - return i; - } - - return tqstrnicmp(m1->manpage_begin, - m2->manpage_begin, - m1->manpage_len); - } -}; - -#endif /* !_USE_QSORT */ -#endif /* !_USE_OLD_CODE */ - - - - -void MANProtocol::showIndex(const TQString& section) -{ - TQByteArray array; - TQTextStream os(array, IO_WriteOnly); - os.setEncoding(TQTextStream::UnicodeUTF8); - - // print header - os << "" << endl; - os << "" << endl; - os << "" << i18n("UNIX Manual Index") << "" << endl; - if ( !m_manCSSFile.isEmpty() ) - os << "" << endl; - os << "" << endl; - os << "
" << endl; - os << "

" << i18n( "Index for Section %1: %2").arg(section).arg(sectionName(section)) << "

" << endl; - - // compose list of search paths ------------------------------------------------------------- - - checkManPaths(); - infoMessage(i18n("Generating Index")); - - // search for the man pages - TQStringList pages = findPages( section, TQString::null ); - - TQMap indexmap = buildIndexMap(section); - - // print out the list - os << "" << endl; - -#ifdef _USE_OLD_CODE - pages.sort(); - - TQMap pagemap; - - TQStringList::ConstIterator page; - for (page = pages.begin(); page != pages.end(); ++page) - { - TQString fileName = *page; - - stripExtension( &fileName ); - - pos = fileName.findRev('/'); - if (pos > 0) - fileName = fileName.mid(pos+1); - - if (!fileName.isEmpty()) - pagemap[fileName] = *page; - - } - - for (TQMap::ConstIterator it = pagemap.begin(); - it != pagemap.end(); ++it) - { - os << "" << endl; - } - -#else /* ! _USE_OLD_CODE */ - -#ifdef _USE_QSORT - - int listlen = pages.count(); - man_index_ptr *indexlist = new man_index_ptr[listlen]; - listlen = 0; - -#else /* !_USE_QSORT */ - - QManIndexList manpages; - manpages.setAutoDelete(TRUE); - -#endif /* _USE_QSORT */ - - TQStringList::const_iterator page; - for (page = pages.begin(); page != pages.end(); ++page) - { - // I look for the beginning of the man page name - // i.e. "bla/pagename.3.gz" by looking for the last "/" - // Then look for the end of the name by searching backwards - // for the last ".", not counting zip extensions. - // If the len of the name is >0, - // store it in the list structure, to be sorted later - - char *manpage_end; - struct man_index_t *manindex = new man_index_t; - manindex->manpath = strdup((*page).utf8()); - - manindex->manpage_begin = strrchr(manindex->manpath, '/'); - if (manindex->manpage_begin) - { - manindex->manpage_begin++; - assert(manindex->manpage_begin >= manindex->manpath); - } - else - { - manindex->manpage_begin = manindex->manpath; - assert(manindex->manpage_begin >= manindex->manpath); - } - - // Skip extension ".section[.gz]" - - char *begin = (char*)(manindex->manpage_begin); - int len = strlen( begin ); - char *end = begin+(len-1); - - if ( len >= 3 && strcmp( end-2, ".gz" ) == 0 ) - end -= 3; - else if ( len >= 2 && strcmp( end-1, ".Z" ) == 0 ) - end -= 2; - else if ( len >= 2 && strcmp( end-1, ".z" ) == 0 ) - end -= 2; - else if ( len >= 4 && strcmp( end-3, ".bz2" ) == 0 ) - end -= 4; - - while ( end >= begin && *end != '.' ) - end--; - - if ( end < begin ) - manpage_end = 0; - else - manpage_end = end; - - if (NULL == manpage_end) - { - // no '.' ending ??? - // set the pointer past the end of the filename - manindex->manpage_len = (*page).length(); - manindex->manpage_len -= (manindex->manpage_begin - manindex->manpath); - assert(manindex->manpage_len >= 0); - } - else - { - manindex->manpage_len = (manpage_end - manindex->manpage_begin); - assert(manindex->manpage_len >= 0); - } - - if (0 < manindex->manpage_len) - { - -#ifdef _USE_QSORT - - indexlist[listlen] = manindex; - listlen++; - -#else /* !_USE_QSORT */ - - manpages.append(manindex); - -#endif /* _USE_QSORT */ - - } - } - - // - // Now do the sorting on the page names - // and the printout afterwards - // While printing avoid duplicate man page names - // - - struct man_index_t dummy_index = {0l,0l,0}; - struct man_index_t *last_index = &dummy_index; - -#ifdef _USE_QSORT - - // sort and print - qsort(indexlist, listlen, sizeof(struct man_index_t *), compare_man_index); - - TQChar firstchar, tmp; - TQString indexLine="
\n"; - if (indexlist[0]->manpage_len>0) - { - firstchar=TQChar((indexlist[0]->manpage_begin)[0]).lower(); - - const TQString appendixstr = TQString( - " [%3]\n" - ).arg(firstchar).arg(firstchar).arg(firstchar); - indexLine.append(appendixstr); - } - os << "
" << endl; - - for (int i=0; imanpage_begin" has not, - // so do compare at most "manindex->manpage_len" of the strings. - if (last_index->manpage_len == manindex->manpage_len && - !tqstrncmp(last_index->manpage_begin, - manindex->manpage_begin, - manindex->manpage_len) - ) - { - continue; - } - - tmp=TQChar((manindex->manpage_begin)[0]).lower(); - if (firstchar != tmp) - { - firstchar = tmp; - os << "" << endl; - - const TQString appendixstr = TQString( - " [%3]\n" - ).arg(firstchar).arg(firstchar).arg(firstchar); - indexLine.append(appendixstr); - } - os << "" << endl; - last_index = manindex; - } - indexLine.append(""); - - for (int i=0; imanpath); // allocated by strdup - delete indexlist[i]; - } - - delete [] indexlist; - -#else /* !_USE_QSORT */ - - manpages.sort(); // using - - for (QManIndexListIterator mit(manpages); - mit.current(); - ++mit ) - { - struct man_index_t *manindex = mit.current(); - - // tqstrncmp(): - // "last_man" has already a \0 string ending, but - // "manindex->manpage_begin" has not, - // so do compare at most "manindex->manpage_len" of the strings. - if (last_index->manpage_len == manindex->manpage_len && - !tqstrncmp(last_index->manpage_begin, - manindex->manpage_begin, - manindex->manpage_len) - ) - { - continue; - } - - os << "" << endl; - last_index = manindex; - } -#endif /* _USE_QSORT */ -#endif /* _USE_OLD_CODE */ - - os << "
\n" - << it.key() << "  " - << (indexmap.contains(it.key()) ? indexmap[it.key()] : "" ) - << "
\n " << firstchar <<"\n
\n " << firstchar << "\n
manpath << "\">\n"; - - ((char *)manindex->manpage_begin)[manindex->manpage_len] = '\0'; - os << manindex->manpage_begin - << "  " - << (indexmap.contains(manindex->manpage_begin) ? indexmap[manindex->manpage_begin] : "" ) - << "
manpath << "\">\n"; - - manindex->manpage_begin[manindex->manpage_len] = '\0'; - os << manindex->manpage_begin - << "  " - << (indexmap.contains(manindex->manpage_begin) ? indexmap[manindex->manpage_begin] : "" ) - << "
" << endl; - - os << indexLine << endl; - - // print footer - os << "" << endl; - - infoMessage(TQString::null); - mimeType("text/html"); - data(array); - finished(); -} - -void MANProtocol::listDir(const KURL &url) -{ - kdDebug( 7107 ) << "ENTER listDir: " << url.prettyURL() << endl; - - TQString title; - TQString section; - - if ( !parseUrl(url.path(), title, section) ) { - error( TDEIO::ERR_MALFORMED_URL, url.url() ); - return; - } - - TQStringList list = findPages( section, TQString::null, false ); - - UDSEntryList uds_entry_list; - UDSEntry uds_entry; - UDSAtom uds_atom; - - uds_atom.m_uds = TDEIO::UDS_NAME; // we only do names... - uds_entry.append( uds_atom ); - - TQStringList::Iterator it = list.begin(); - TQStringList::Iterator end = list.end(); - - for ( ; it != end; ++it ) { - stripExtension( &(*it) ); - - uds_entry[0].m_str = *it; - uds_entry_list.append( uds_entry ); - } - - listEntries( uds_entry_list ); - finished(); -} - -void MANProtocol::getProgramPath() -{ - if (!mySgml2RoffPath.isEmpty()) - return; - - mySgml2RoffPath = TDEGlobal::dirs()->findExe("sgml2roff"); - if (!mySgml2RoffPath.isEmpty()) - return; - - /* sgml2roff isn't found in PATH. Check some possible locations where it may be found. */ - mySgml2RoffPath = TDEGlobal::dirs()->findExe("sgml2roff", TQString(SGML2ROFF_DIRS)); - if (!mySgml2RoffPath.isEmpty()) - return; - - /* Cannot find sgml2roff programm: */ - outputError(i18n("Could not find the sgml2roff program on your system. Please install it, if necessary, and extend the search path by adjusting the environment variable PATH before starting TDE.")); - finished(); - exit(); -} diff --git a/tdeioslave/man/kio_man.css b/tdeioslave/man/kio_man.css deleted file mode 100644 index 8a9f378bc..000000000 --- a/tdeioslave/man/kio_man.css +++ /dev/null @@ -1,21 +0,0 @@ -body {background-color:#fffff} - -/*for the list of one manpage section*/ -.secidxshort { - display:block; - position:absolute;overflow:auto; - top:0px;bottom:95%;left:0;right:0; -} -.secidxmain { -/*misfortunately accessing anchors in a scrollview - doesn't seem to work yet with konqi, so:*/ -/* - position:absolute;overflow:auto; - top:5%;bottom:0;left:0;right:0; -*/ -} -.secidxnextletter { - font-size:larger; - border-bottom:1px solid black; - text-align:center -} diff --git a/tdeioslave/man/kio_man.h b/tdeioslave/man/kio_man.h deleted file mode 100644 index 829a07964..000000000 --- a/tdeioslave/man/kio_man.h +++ /dev/null @@ -1,100 +0,0 @@ -/* This file is part of the KDE libraries - Copyright (c) 2000 Matthias Hoelzer-Kluepfel - - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ -#ifndef __kio_man_h__ -#define __kio_man_h__ - - -#include -#include -#include -#include -#include - - -#include -#include - - -class MANProtocol : public TQObject, public TDEIO::SlaveBase -{ - Q_OBJECT - -public: - - MANProtocol(const TQCString &pool_socket, const TQCString &app_socket); - virtual ~MANProtocol(); - - virtual void get(const KURL& url); - virtual void stat(const KURL& url); - - virtual void mimetype(const KURL &url); - virtual void listDir(const KURL &url); - - void outputError(const TQString& errmsg); - void outputMatchingPages(const TQStringList &matchingPages); - - void showMainIndex(); - void showIndex(const TQString& section); - - // the following two functions are the interface to man2html - void output(const char *insert); - char *readManPage(const char *filename); - - static MANProtocol *self(); - -private slots: - void slotGetStdOutput(TDEProcess*, char*, int); - void slotGetStdOutputUtf8(TDEProcess*, char*, int); - -private: - void checkManPaths(); - TQStringList manDirectories(); - TQMap buildIndexMap(const TQString& section); - bool addWhatIs(TQMap& i, const TQString& f, const TQString& mark); - void parseWhatIs( TQMap &i, TQTextStream &t, const TQString &mark ); - TQStringList findPages(const TQString& section, - const TQString &title, - bool full_path = true); - - void addToBuffer(const char *buffer, int buflen); - TQString pageName(const TQString& page) const; - TQStringList buildSectionList(const TQStringList& dirs) const; - void constructPath(TQStringList& constr_path, TQStringList constr_catmanpath); -private: - static MANProtocol *_self; - TQCString lastdir; - - void findManPagesInSection(const TQString &dir, const TQString &title, bool full_path, TQStringList &list); - TQStringList m_manpath; ///< Path of man directories - TQStringList m_mandbpath; ///< Path of catman directories - TQStringList section_names; - - TQString myStdStream; - TQString mySgml2RoffPath; - void getProgramPath(); - - TQCString m_htmlPath; ///< Path to TDE resources, encoded for HTML - TQCString m_cssPath; ///< Path to TDE resources, encoded for CSS - TQBuffer m_outputBuffer; ///< Buffer for the output - TQString m_manCSSFile; ///< Path to kio_man.css -}; - - -#endif diff --git a/tdeioslave/man/kio_man_test.cpp b/tdeioslave/man/kio_man_test.cpp deleted file mode 100644 index a181c47b3..000000000 --- a/tdeioslave/man/kio_man_test.cpp +++ /dev/null @@ -1,38 +0,0 @@ - - -#include - -#include "kio_man.h" - - -#include -#include - - -class kio_man_test : public MANProtocol -{ - Q_OBJECT - -public: - kio_man_test(const TQCString &pool_socket, const TQCString &app_socket); - -protected: - virtual void data(int); - -}; - - - - - -int main(int argc, char **argv) -{ - TDEApplication a( argc, argv , "p2"); - - MANProtocol testproto("/tmp/tdeiotest.in", "/tmp/tdeiotest.out"); - testproto.showIndex("3"); - - return 0; -} - - diff --git a/tdeioslave/man/man.protocol b/tdeioslave/man/man.protocol index 555970fdc..37a57cec4 100644 --- a/tdeioslave/man/man.protocol +++ b/tdeioslave/man/man.protocol @@ -1,5 +1,5 @@ [Protocol] -exec=kio_man +exec=tdeio_man protocol=man input=none output=filesystem diff --git a/tdeioslave/man/man2html.cpp b/tdeioslave/man/man2html.cpp index ec46b2d3d..577f7d53a 100644 --- a/tdeioslave/man/man2html.cpp +++ b/tdeioslave/man/man2html.cpp @@ -4073,7 +4073,7 @@ static char *scan_request(char *c) // Most English man pages are in ISO-8859-1 out_html("\n"); #else - // kio_man transforms from local to UTF-8 + // tdeio_man transforms from local to UTF-8 out_html("\n"); diff --git a/tdeioslave/man/tdeio_man.cpp b/tdeioslave/man/tdeio_man.cpp new file mode 100644 index 000000000..4c4f1945c --- /dev/null +++ b/tdeioslave/man/tdeio_man.cpp @@ -0,0 +1,1533 @@ +/* This file is part of the KDE libraries + Copyright (c) 2000 Matthias Hoelzer-Kluepfel + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "tdeio_man.h" +#include "tdeio_man.moc" +#include "man2html.h" +#include +#include +#include + +using namespace TDEIO; + +MANProtocol *MANProtocol::_self = 0; + +#define SGML2ROFF_DIRS "/usr/lib/sgml" + +/* + * Drop trailing ".section[.gz]" from name + */ +static +void stripExtension( TQString *name ) +{ + int pos = name->length(); + + if ( name->find(".gz", -3) != -1 ) + pos -= 3; + else if ( name->find(".z", -2, false) != -1 ) + pos -= 2; + else if ( name->find(".bz2", -4) != -1 ) + pos -= 4; + else if ( name->find(".bz", -3) != -1 ) + pos -= 3; + + if ( pos > 0 ) + pos = name->findRev('.', pos-1); + + if ( pos > 0 ) + name->truncate( pos ); +} + +static +bool parseUrl(const TQString& _url, TQString &title, TQString §ion) +{ + section = TQString::null; + + TQString url = _url; + if (url.at(0) == '/') { + if (KStandardDirs::exists(url)) { + title = url; + return true; + } else + { + // If the directory does not exist, then it is perhaps a normal man page + kdDebug(7107) << url << " does not exist" << endl; + } + } + + while (url.at(0) == '/') + url.remove(0,1); + + title = url; + + int pos = url.find('('); + if (pos < 0) + return true; + + title = title.left(pos); + + section = url.mid(pos+1); + section = section.left(section.length()-1); + + return true; +} + + +MANProtocol::MANProtocol(const TQCString &pool_socket, const TQCString &app_socket) + : TQObject(), SlaveBase("man", pool_socket, app_socket) +{ + assert(!_self); + _self = this; + const TQString common_dir = TDEGlobal::dirs()->findResourceDir( "html", "en/common/kde-common.css" ); + const TQString strPath=TQString( "file:%1/en/common" ).arg( common_dir ); + m_htmlPath=strPath.local8Bit(); // ### TODO encode for HTML + m_cssPath=strPath.local8Bit(); // ### TODO encode for CSS + section_names << "1" << "2" << "3" << "3n" << "3p" << "4" << "5" << "6" << "7" + << "8" << "9" << "l" << "n"; + m_manCSSFile = locate( "data", "tdeio_man/tdeio_man.css" ); +} + +MANProtocol *MANProtocol::self() { return _self; } + +MANProtocol::~MANProtocol() +{ + _self = 0; +} + +void MANProtocol::parseWhatIs( TQMap &i, TQTextStream &t, const TQString &mark ) +{ + TQRegExp re( mark ); + TQString l; + while ( !t.atEnd() ) + { + l = t.readLine(); + int pos = re.search( l ); + if (pos != -1) + { + TQString names = l.left(pos); + TQString descr = l.mid(pos + re.matchedLength()); + while ((pos = names.find(",")) != -1) + { + i[names.left(pos++)] = descr; + while (names[pos] == ' ') + pos++; + names = names.mid(pos); + } + i[names] = descr; + } + } +} + +bool MANProtocol::addWhatIs(TQMap &i, const TQString &name, const TQString &mark) +{ + TQFile f(name); + if (!f.open(IO_ReadOnly)) + return false; + TQTextStream t(&f); + parseWhatIs( i, t, mark ); + return true; +} + +TQMap MANProtocol::buildIndexMap(const TQString §ion) +{ + TQMap i; + TQStringList man_dirs = manDirectories(); + // Supplementary places for whatis databases + man_dirs += m_mandbpath; + if (man_dirs.find("/var/cache/man")==man_dirs.end()) + man_dirs << "/var/cache/man"; + if (man_dirs.find("/var/catman")==man_dirs.end()) + man_dirs << "/var/catman"; + + TQStringList names; + names << "whatis.db" << "whatis"; + TQString mark = "\\s+\\(" + section + "[a-z]*\\)\\s+-\\s+"; + + for ( TQStringList::ConstIterator it_dir = man_dirs.begin(); + it_dir != man_dirs.end(); + ++it_dir ) + { + if ( TQFile::exists( *it_dir ) ) { + TQStringList::ConstIterator it_name; + for ( it_name = names.begin(); + it_name != names.end(); + it_name++ ) + { + if (addWhatIs(i, (*it_dir) + "/" + (*it_name), mark)) + break; + } + if ( it_name == names.end() ) { + TDEProcess proc; + proc << "whatis" << "-M" << (*it_dir) << "-w" << "*"; + myStdStream = TQString::null; + connect( &proc, TQT_SIGNAL( receivedStdout(TDEProcess *, char *, int ) ), + TQT_SLOT( slotGetStdOutput( TDEProcess *, char *, int ) ) ); + proc.start( TDEProcess::Block, TDEProcess::Stdout ); + TQTextStream t( &myStdStream, IO_ReadOnly ); + parseWhatIs( i, t, mark ); + } + } + } + return i; +} + +TQStringList MANProtocol::manDirectories() +{ + checkManPaths(); + // + // Build a list of man directories including translations + // + TQStringList man_dirs; + + for ( TQStringList::ConstIterator it_dir = m_manpath.begin(); + it_dir != m_manpath.end(); + it_dir++ ) + { + // Translated pages in "/" if the directory + // exists + TQStringList languages = TDEGlobal::locale()->languageList(); + + for (TQStringList::ConstIterator it_lang = languages.begin(); + it_lang != languages.end(); + it_lang++ ) + { + if ( !(*it_lang).isEmpty() && (*it_lang) != TQString("C") ) { + TQString dir = (*it_dir) + '/' + (*it_lang); + + struct stat sbuf; + + if ( ::stat( TQFile::encodeName( dir ), &sbuf ) == 0 + && S_ISDIR( sbuf.st_mode ) ) + { + const TQString p = TQDir(dir).canonicalPath(); + if (!man_dirs.contains(p)) man_dirs += p; + } + } + } + + // Untranslated pages in "" + const TQString p = TQDir(*it_dir).canonicalPath(); + if (!man_dirs.contains(p)) man_dirs += p; + } + return man_dirs; +} + +TQStringList MANProtocol::findPages(const TQString &_section, + const TQString &title, + bool full_path) +{ + TQString section = _section; + + TQStringList list; + + // kdDebug() << "findPages '" << section << "' '" << title << "'\n"; + if (title.at(0) == '/') { + list.append(title); + return list; + } + + const TQString star( "*" ); + + // + // Find man sections in this directory + // + TQStringList sect_list; + if ( section.isEmpty() ) + section = star; + + if ( section != star ) + { + // + // Section given as argument + // + sect_list += section; + while (section.at(section.length() - 1).isLetter()) { + section.truncate(section.length() - 1); + sect_list += section; + } + } else { + sect_list += section; + } + + TQStringList man_dirs = manDirectories(); + + // + // Find man pages in the sections listed above + // + for ( TQStringList::ConstIterator it_sect = sect_list.begin(); + it_sect != sect_list.end(); + it_sect++ ) + { + TQString it_real = (*it_sect).lower(); + // + // Find pages + // + for ( TQStringList::ConstIterator it_dir = man_dirs.begin(); + it_dir != man_dirs.end(); + it_dir++ ) + { + TQString man_dir = (*it_dir); + + // + // Sections = all sub directories "man*" and "sman*" + // + DIR *dp = ::opendir( TQFile::encodeName( man_dir ) ); + + if ( !dp ) + continue; + + struct dirent *ep; + + const TQString man = TQString("man"); + const TQString sman = TQString("sman"); + + while ( (ep = ::readdir( dp )) != 0L ) { + const TQString file = TQFile::decodeName( ep->d_name ); + TQString sect = TQString::null; + + if ( file.startsWith( man ) ) + sect = file.mid(3); + else if (file.startsWith(sman)) + sect = file.mid(4); + + if (sect.lower()==it_real) it_real = sect; + + // Only add sect if not already contained, avoid duplicates + if (!sect_list.contains(sect) && _section.isEmpty()) { + kdDebug() << "another section " << sect << endl; + sect_list += sect; + } + } + + ::closedir( dp ); + + if ( *it_sect != star ) { // in that case we only look around for sections + const TQString dir = man_dir + TQString("/man") + (it_real) + '/'; + const TQString sdir = man_dir + TQString("/sman") + (it_real) + '/'; + + findManPagesInSection(dir, title, full_path, list); + findManPagesInSection(sdir, title, full_path, list); + } + } + } + +// kdDebug(7107) << "finished " << list << " " << sect_list << endl; + + return list; +} + +void MANProtocol::findManPagesInSection(const TQString &dir, const TQString &title, bool full_path, TQStringList &list) +{ + kdDebug() << "findManPagesInSection " << dir << " " << title << endl; + bool title_given = !title.isEmpty(); + + DIR *dp = ::opendir( TQFile::encodeName( dir ) ); + + if ( !dp ) + return; + + struct dirent *ep; + + while ( (ep = ::readdir( dp )) != 0L ) { + if ( ep->d_name[0] != '.' ) { + + TQString name = TQFile::decodeName( ep->d_name ); + + // check title if we're looking for a specific page + if ( title_given ) { + if ( !name.startsWith( title ) ) { + continue; + } + else { + // beginning matches, do a more thorough check... + TQString tmp_name = name; + stripExtension( &tmp_name ); + if ( tmp_name != title ) + continue; + } + } + + if ( full_path ) + name.prepend( dir ); + + list += name ; + } + } + ::closedir( dp ); +} + +void MANProtocol::output(const char *insert) +{ + if (insert) + { + m_outputBuffer.writeBlock(insert,strlen(insert)); + } + if (!insert || m_outputBuffer.at() >= 2048) + { + m_outputBuffer.close(); + data(m_outputBuffer.buffer()); + m_outputBuffer.setBuffer(TQByteArray()); + m_outputBuffer.open(IO_WriteOnly); + } +} + +// called by man2html +char *read_man_page(const char *filename) +{ + return MANProtocol::self()->readManPage(filename); +} + +// called by man2html +void output_real(const char *insert) +{ + MANProtocol::self()->output(insert); +} + +static TQString text2html(const TQString& txt) +{ + TQString reply = txt; + + reply = reply.replace('&', "&"); + reply = reply.replace('<', "<"); + reply = reply.replace('>', ">"); + reply = reply.replace('"', "&dquot;"); + reply = reply.replace('\'', """); + return reply; +} + +void MANProtocol::get(const KURL& url ) +{ + kdDebug(7107) << "GET " << url.url() << endl; + + TQString title, section; + + if (!parseUrl(url.path(), title, section)) + { + showMainIndex(); + return; + } + + // see if an index was requested + if (url.query().isEmpty() && (title.isEmpty() || title == "/" || title == ".")) + { + if (section == "index" || section.isEmpty()) + showMainIndex(); + else + showIndex(section); + return; + } + + // tell the mimetype + mimeType("text/html"); + + const TQStringList foundPages=findPages(section, title); + bool pageFound=true; + if (foundPages.isEmpty()) + { + outputError(i18n("No man page matching to %1 found.

" + "Check that you have not mistyped the name of the page that you want.\n" + "Be careful that you must take care about upper case and lower case characters!
" + "If everything looks correct, then perhaps you need to set a better search path " + "for man pages, be it by the environment variable MANPATH or a matching file " + "in the directory /etc .").arg(text2html(title))); + pageFound=false; + } + else if (foundPages.count()>1) + { + pageFound=false; + //check for the case that there is foo.1 and foo.1.gz found: + // ### TODO make it more generic (other extensions) + if ((foundPages.count()==2) && + (((foundPages[0]+".gz") == foundPages[1]) || + (foundPages[0] == (foundPages[1]+".gz")))) + pageFound=true; + else + outputMatchingPages(foundPages); + } + //yes, we found exactly one man page + + if (pageFound) + { + setResourcePath(m_htmlPath,m_cssPath); + m_outputBuffer.open(IO_WriteOnly); + const TQCString filename=TQFile::encodeName(foundPages[0]); + char *buf = readManPage(filename); + + if (!buf) + { + outputError(i18n("Open of %1 failed.").arg(title)); + finished(); + return; + } + // will call output_real + scan_man_page(buf); + delete [] buf; + + output(0); // flush + + m_outputBuffer.close(); + data(m_outputBuffer.buffer()); + m_outputBuffer.setBuffer(TQByteArray()); + // tell we are done + data(TQByteArray()); + } + finished(); +} + +void MANProtocol::slotGetStdOutput(TDEProcess* /* p */, char *s, int len) +{ + myStdStream += TQString::fromLocal8Bit(s, len); +} + +void MANProtocol::slotGetStdOutputUtf8(TDEProcess* /* p */, char *s, int len) +{ + myStdStream += TQString::fromUtf8(s, len); +} + +char *MANProtocol::readManPage(const char *_filename) +{ + TQCString filename = _filename; + + char *buf = NULL; + + /* Determine type of man page file by checking its path. Determination by + * MIME type with KMimeType doesn't work reliablely. E.g., Solaris 7: + * /usr/man/sman7fs/pcfs.7fs -> text/x-csrc : WRONG + * If the path name constains the string sman, assume that it's SGML and + * convert it to roff format (used on Solaris). */ + //TQString file_mimetype = KMimeType::findByPath(TQString(filename), 0, false)->name(); + if (filename.contains("sman", false)) //file_mimetype == "text/html" || ) + { + myStdStream =TQString::null; + TDEProcess proc; + + /* Determine path to sgml2roff, if not already done. */ + getProgramPath(); + proc << mySgml2RoffPath << filename; + + TQApplication::connect(&proc, TQT_SIGNAL(receivedStdout (TDEProcess *, char *, int)), + this, TQT_SLOT(slotGetStdOutput(TDEProcess *, char *, int))); + proc.start(TDEProcess::Block, TDEProcess::All); + + const TQCString cstr=myStdStream.latin1(); + const int len = cstr.size()-1; + buf = new char[len + 4]; + tqmemmove(buf + 1, cstr.data(), len); + buf[0]=buf[len]='\n'; // Start and end with a end of line + buf[len+1]=buf[len+2]='\0'; // Two additional NUL characters at end + } + else + { + if (TQDir::isRelativePath(filename)) { + kdDebug(7107) << "relative " << filename << endl; + filename = TQDir::cleanDirPath(lastdir + "/" + filename).utf8(); + if (!KStandardDirs::exists(filename)) { // exists perhaps with suffix + lastdir = filename.left(filename.findRev('/')); + TQDir mandir(lastdir); + mandir.setNameFilter(filename.mid(filename.findRev('/') + 1) + ".*"); + filename = lastdir + "/" + TQFile::encodeName(mandir.entryList().first()); + } + kdDebug(7107) << "resolved to " << filename << endl; + } + lastdir = filename.left(filename.findRev('/')); + + myStdStream = TQString::null; + TDEProcess proc; + /* TODO: detect availability of 'man --recode' so that this can go + * upstream */ + proc << "man" << "--recode" << "UTF-8" << filename; + + TQApplication::connect(&proc, TQT_SIGNAL(receivedStdout (TDEProcess *, char *, int)), + this, TQT_SLOT(slotGetStdOutputUtf8(TDEProcess *, char *, int))); + proc.start(TDEProcess::Block, TDEProcess::All); + + const TQCString cstr=myStdStream.utf8(); + const int len = cstr.size()-1; + buf = new char[len + 4]; + tqmemmove(buf + 1, cstr.data(), len); + buf[0]=buf[len]='\n'; // Start and end with a end of line + buf[len+1]=buf[len+2]='\0'; // Two NUL characters at end + } + return buf; +} + + +void MANProtocol::outputError(const TQString& errmsg) +{ + TQByteArray array; + TQTextStream os(array, IO_WriteOnly); + os.setEncoding(TQTextStream::UnicodeUTF8); + + os << "" << endl; + os << "" << endl; + os << "" << i18n("Man output") << "\n" << endl; + if ( !m_manCSSFile.isEmpty() ) + os << "" << endl; + os << "" << endl; + os << i18n("

TDE Man Viewer Error

") << errmsg << "" << endl; + os << "" << endl; + + data(array); +} + +void MANProtocol::outputMatchingPages(const TQStringList &matchingPages) +{ + TQByteArray array; + TQTextStream os(array, IO_WriteOnly); + os.setEncoding(TQTextStream::UnicodeUTF8); + + os << "" << endl; + os << "\n"<" << i18n("Man output") <<"" << endl; + if ( !m_manCSSFile.isEmpty() ) + os << "" << endl; + os << "" <

" << i18n("There is more than one matching man page."); + os << "

\n
    \n"; + + int acckey=1; + for (TQStringList::ConstIterator it = matchingPages.begin(); it != matchingPages.end(); ++it) + { + os<<"
  • "<< *it <<"
    \n
    \n"; + acckey++; + } + os << "
\n"; + os << "
\n"; + os << "

" << i18n("Note: if you read a man page in your language," + " be aware it can contain some mistakes or be obsolete." + " In case of doubt, you should have a look at the English version.") << "

"; + + os << "\n"<" << endl; + os << "" << endl; + os << "" << i18n("UNIX Manual Index") << "" << endl; + if (!m_manCSSFile.isEmpty()) + os << "" << endl; + os << "" << endl; + os << "

" << i18n("UNIX Manual Index") << "

" << endl; + + // ### TODO: why still the environment variable + const TQString sectList = getenv("MANSECT"); + TQStringList sections; + if (sectList.isEmpty()) + sections = buildSectionList(manDirectories()); + else + sections = TQStringList::split(':', sectList); + + os << "" << endl; + + TQStringList::ConstIterator it; + for (it = sections.begin(); it != sections.end(); ++it) + os << "" << endl; + + os << "
" << i18n("Section ") + << *it << "  " << sectionName(*it) << "
" << endl; + + // print footer + os << "" << endl; + + data(array); + finished(); +} + +void MANProtocol::constructPath(TQStringList& constr_path, TQStringList constr_catmanpath) +{ + TQMap manpath_map; + TQMap mandb_map; + + // Add paths from /etc/man.conf + // + // Explicit manpaths may be given by lines starting with "MANPATH" or + // "MANDATORY_MANPATH" (depending on system ?). + // Mappings from $PATH to manpath are given by lines starting with + // "MANPATH_MAP" + + TQRegExp manpath_regex( "^MANPATH\\s" ); + TQRegExp mandatory_regex( "^MANDATORY_MANPATH\\s" ); + TQRegExp manpath_map_regex( "^MANPATH_MAP\\s" ); + TQRegExp mandb_map_regex( "^MANDB_MAP\\s" ); + //TQRegExp section_regex( "^SECTION\\s" ); + TQRegExp space_regex( "\\s+" ); // for parsing manpath map + + TQFile mc("/etc/man.conf"); // Caldera + if (!mc.exists()) + mc.setName("/etc/manpath.config"); // SuSE, Debian + if (!mc.exists()) + mc.setName("/etc/man.config"); // Mandrake + + if (mc.open(IO_ReadOnly)) + { + TQTextStream is(&mc); + is.setEncoding(TQTextStream::Locale); + + while (!is.eof()) + { + const TQString line = is.readLine(); + if ( manpath_regex.search(line, 0) == 0 ) + { + const TQString path = line.mid(8).stripWhiteSpace(); + constr_path += path; + } + else if ( mandatory_regex.search(line, 0) == 0 ) + { + const TQString path = line.mid(18).stripWhiteSpace(); + constr_path += path; + } + else if ( manpath_map_regex.search(line, 0) == 0 ) + { + // The entry is "MANPATH_MAP " + const TQStringList mapping = + TQStringList::split(space_regex, line); + + if ( mapping.count() == 3 ) + { + const TQString dir = TQDir::cleanDirPath( mapping[1] ); + const TQString mandir = TQDir::cleanDirPath( mapping[2] ); + + manpath_map[ dir ] = mandir; + } + } + else if ( mandb_map_regex.search(line, 0) == 0 ) + { + // The entry is "MANDB_MAP " + const TQStringList mapping = + TQStringList::split(space_regex, line); + + if ( mapping.count() == 3 ) + { + const TQString mandir = TQDir::cleanDirPath( mapping[1] ); + const TQString catmandir = TQDir::cleanDirPath( mapping[2] ); + + mandb_map[ mandir ] = catmandir; + } + } + /* sections are not used + else if ( section_regex.find(line, 0) == 0 ) + { + if ( !conf_section.isEmpty() ) + conf_section += ':'; + conf_section += line.mid(8).stripWhiteSpace(); + } + */ + } + mc.close(); + } + + // Default paths + static const char *manpaths[] = { + "/usr/X11/man", + "/usr/X11R6/man", + "/usr/man", + "/usr/local/man", + "/usr/exp/man", + "/usr/openwin/man", + "/usr/dt/man", + "/opt/freetool/man", + "/opt/local/man", + "/usr/tex/man", + "/usr/www/man", + "/usr/lang/man", + "/usr/gnu/man", + "/usr/share/man", + "/usr/motif/man", + "/usr/titools/man", + "/usr/sunpc/man", + "/usr/ncd/man", + "/usr/newsprint/man", + NULL }; + + + int i = 0; + while (manpaths[i]) { + if ( constr_path.findIndex( TQString( manpaths[i] ) ) == -1 ) + constr_path += TQString( manpaths[i] ); + i++; + } + + // Directories in $PATH + // - if a manpath mapping exists, use that mapping + // - if a directory "/man" or "/../man" exists, add it + // to the man path (the actual existence check is done further down) + + if ( ::getenv("PATH") ) { + const TQStringList path = + TQStringList::split( ":", + TQString::fromLocal8Bit( ::getenv("PATH") ) ); + + for ( TQStringList::const_iterator it = path.begin(); + it != path.end(); + ++it ) + { + const TQString dir = TQDir::cleanDirPath( *it ); + TQString mandir = manpath_map[ dir ]; + + if ( !mandir.isEmpty() ) { + // a path mapping exists + if ( constr_path.findIndex( mandir ) == -1 ) + constr_path += mandir; + } + else { + // no manpath mapping, use "/man" and "/../man" + + mandir = dir + TQString( "/man" ); + if ( constr_path.findIndex( mandir ) == -1 ) + constr_path += mandir; + + int pos = dir.findRev( '/' ); + if ( pos > 0 ) { + mandir = dir.left( pos ) + TQString("/man"); + if ( constr_path.findIndex( mandir ) == -1 ) + constr_path += mandir; + } + } + TQString catmandir = mandb_map[ mandir ]; + if ( !mandir.isEmpty() ) + { + if ( constr_catmanpath.findIndex( catmandir ) == -1 ) + constr_catmanpath += catmandir; + } + else + { + // What is the default mapping? + catmandir = mandir; + catmandir.replace("/usr/share/","/var/cache/"); + if ( constr_catmanpath.findIndex( catmandir ) == -1 ) + constr_catmanpath += catmandir; + } + } + } +} + +void MANProtocol::checkManPaths() +{ + static bool inited = false; + + if (inited) + return; + + inited = true; + + const TQString manpath_env = TQString::fromLocal8Bit( ::getenv("MANPATH") ); + //TQString mansect_env = TQString::fromLocal8Bit( ::getenv("MANSECT") ); + + // Decide if $MANPATH is enough on its own or if it should be merged + // with the constructed path. + // A $MANPATH starting or ending with ":", or containing "::", + // should be merged with the constructed path. + + bool construct_path = false; + + if ( manpath_env.isEmpty() + || manpath_env[0] == ':' + || manpath_env[manpath_env.length()-1] == ':' + || manpath_env.contains( "::" ) ) + { + construct_path = true; // need to read config file + } + + // Constucted man path -- consists of paths from + // /etc/man.conf + // default dirs + // $PATH + TQStringList constr_path; + TQStringList constr_catmanpath; // catmanpath + + TQString conf_section; + + if ( construct_path ) + { + constructPath(constr_path, constr_catmanpath); + } + + m_mandbpath=constr_catmanpath; + + // Merge $MANPATH with the constructed path to form the + // actual manpath. + // + // The merging syntax with ":" and "::" in $MANPATH will be + // satisfied if any empty string in path_list_env (there + // should be 1 or 0) is replaced by the constructed path. + + const TQStringList path_list_env = TQStringList::split( ':', manpath_env , true ); + + for ( TQStringList::const_iterator it = path_list_env.begin(); + it != path_list_env.end(); + ++it ) + { + struct stat sbuf; + + TQString dir = (*it); + + if ( !dir.isEmpty() ) { + // Add dir to the man path if it exists + if ( m_manpath.findIndex( dir ) == -1 ) { + if ( ::stat( TQFile::encodeName( dir ), &sbuf ) == 0 + && S_ISDIR( sbuf.st_mode ) ) + { + m_manpath += dir; + } + } + } + else { + // Insert constructed path ($MANPATH was empty, or + // there was a ":" at an end or "::") + + for ( TQStringList::Iterator it2 = constr_path.begin(); + it2 != constr_path.end(); + it2++ ) + { + dir = (*it2); + + if ( !dir.isEmpty() ) { + if ( m_manpath.findIndex( dir ) == -1 ) { + if ( ::stat( TQFile::encodeName( dir ), &sbuf ) == 0 + && S_ISDIR( sbuf.st_mode ) ) + { + m_manpath += dir; + } + } + } + } + } + } + +/* sections are not used + // Sections + TQStringList m_mansect = TQStringList::split( ':', mansect_env, true ); + + const char* default_sect[] = + { "1", "2", "3", "4", "5", "6", "7", "8", "9", "n", 0L }; + + for ( int i = 0; default_sect[i] != 0L; i++ ) + if ( m_mansect.findIndex( TQString( default_sect[i] ) ) == -1 ) + m_mansect += TQString( default_sect[i] ); +*/ + +} + + +//#define _USE_OLD_CODE + +#ifdef _USE_OLD_CODE +#warning "using old code" +#else + +// Define this, if you want to compile with qsort from stdlib.h +// else the Qt Heapsort will be used. +// Note, qsort seems to be a bit faster (~10%) on a large man section +// eg. man section 3 +#define _USE_QSORT + +// Setup my own structure, with char pointers. +// from now on only pointers are copied, no strings +// +// containing the whole path string, +// the beginning of the man page name +// and the length of the name +struct man_index_t { + char *manpath; // the full path including man file + const char *manpage_begin; // pointer to the begin of the man file name in the path + int manpage_len; // len of the man file name +}; +typedef man_index_t *man_index_ptr; + +#ifdef _USE_QSORT +int compare_man_index(const void *s1, const void *s2) +{ + struct man_index_t *m1 = *(struct man_index_t **)s1; + struct man_index_t *m2 = *(struct man_index_t **)s2; + int i; + // Compare the names of the pages + // with the shorter length. + // Man page names are not '\0' terminated, so + // this is a bit tricky + if ( m1->manpage_len > m2->manpage_len) + { + i = tqstrnicmp( m1->manpage_begin, + m2->manpage_begin, + m2->manpage_len); + if (!i) + return 1; + return i; + } + + if ( m1->manpage_len < m2->manpage_len) + { + i = tqstrnicmp( m1->manpage_begin, + m2->manpage_begin, + m1->manpage_len); + if (!i) + return -1; + return i; + } + + return tqstrnicmp( m1->manpage_begin, + m2->manpage_begin, + m1->manpage_len); +} + +#else /* !_USE_QSORT */ +#warning using heapsort +// Set up my own man page list, +// with a special compare function to sort itself +typedef TQPtrList QManIndexListBase; +typedef TQPtrListIterator QManIndexListIterator; + +class QManIndexList : public QManIndexListBase +{ +public: +private: + int compareItems( TQPtrCollection::Item s1, TQPtrCollection::Item s2 ) + { + struct man_index_t *m1 = (struct man_index_t *)s1; + struct man_index_t *m2 = (struct man_index_t *)s2; + int i; + // compare the names of the pages + // with the shorter length + if (m1->manpage_len > m2->manpage_len) + { + i = tqstrnicmp(m1->manpage_begin, + m2->manpage_begin, + m2->manpage_len); + if (!i) + return 1; + return i; + } + + if (m1->manpage_len > m2->manpage_len) + { + + i = tqstrnicmp(m1->manpage_begin, + m2->manpage_begin, + m1->manpage_len); + if (!i) + return -1; + return i; + } + + return tqstrnicmp(m1->manpage_begin, + m2->manpage_begin, + m1->manpage_len); + } +}; + +#endif /* !_USE_QSORT */ +#endif /* !_USE_OLD_CODE */ + + + + +void MANProtocol::showIndex(const TQString& section) +{ + TQByteArray array; + TQTextStream os(array, IO_WriteOnly); + os.setEncoding(TQTextStream::UnicodeUTF8); + + // print header + os << "" << endl; + os << "" << endl; + os << "" << i18n("UNIX Manual Index") << "" << endl; + if ( !m_manCSSFile.isEmpty() ) + os << "" << endl; + os << "" << endl; + os << "
" << endl; + os << "

" << i18n( "Index for Section %1: %2").arg(section).arg(sectionName(section)) << "

" << endl; + + // compose list of search paths ------------------------------------------------------------- + + checkManPaths(); + infoMessage(i18n("Generating Index")); + + // search for the man pages + TQStringList pages = findPages( section, TQString::null ); + + TQMap indexmap = buildIndexMap(section); + + // print out the list + os << "" << endl; + +#ifdef _USE_OLD_CODE + pages.sort(); + + TQMap pagemap; + + TQStringList::ConstIterator page; + for (page = pages.begin(); page != pages.end(); ++page) + { + TQString fileName = *page; + + stripExtension( &fileName ); + + pos = fileName.findRev('/'); + if (pos > 0) + fileName = fileName.mid(pos+1); + + if (!fileName.isEmpty()) + pagemap[fileName] = *page; + + } + + for (TQMap::ConstIterator it = pagemap.begin(); + it != pagemap.end(); ++it) + { + os << "" << endl; + } + +#else /* ! _USE_OLD_CODE */ + +#ifdef _USE_QSORT + + int listlen = pages.count(); + man_index_ptr *indexlist = new man_index_ptr[listlen]; + listlen = 0; + +#else /* !_USE_QSORT */ + + QManIndexList manpages; + manpages.setAutoDelete(TRUE); + +#endif /* _USE_QSORT */ + + TQStringList::const_iterator page; + for (page = pages.begin(); page != pages.end(); ++page) + { + // I look for the beginning of the man page name + // i.e. "bla/pagename.3.gz" by looking for the last "/" + // Then look for the end of the name by searching backwards + // for the last ".", not counting zip extensions. + // If the len of the name is >0, + // store it in the list structure, to be sorted later + + char *manpage_end; + struct man_index_t *manindex = new man_index_t; + manindex->manpath = strdup((*page).utf8()); + + manindex->manpage_begin = strrchr(manindex->manpath, '/'); + if (manindex->manpage_begin) + { + manindex->manpage_begin++; + assert(manindex->manpage_begin >= manindex->manpath); + } + else + { + manindex->manpage_begin = manindex->manpath; + assert(manindex->manpage_begin >= manindex->manpath); + } + + // Skip extension ".section[.gz]" + + char *begin = (char*)(manindex->manpage_begin); + int len = strlen( begin ); + char *end = begin+(len-1); + + if ( len >= 3 && strcmp( end-2, ".gz" ) == 0 ) + end -= 3; + else if ( len >= 2 && strcmp( end-1, ".Z" ) == 0 ) + end -= 2; + else if ( len >= 2 && strcmp( end-1, ".z" ) == 0 ) + end -= 2; + else if ( len >= 4 && strcmp( end-3, ".bz2" ) == 0 ) + end -= 4; + + while ( end >= begin && *end != '.' ) + end--; + + if ( end < begin ) + manpage_end = 0; + else + manpage_end = end; + + if (NULL == manpage_end) + { + // no '.' ending ??? + // set the pointer past the end of the filename + manindex->manpage_len = (*page).length(); + manindex->manpage_len -= (manindex->manpage_begin - manindex->manpath); + assert(manindex->manpage_len >= 0); + } + else + { + manindex->manpage_len = (manpage_end - manindex->manpage_begin); + assert(manindex->manpage_len >= 0); + } + + if (0 < manindex->manpage_len) + { + +#ifdef _USE_QSORT + + indexlist[listlen] = manindex; + listlen++; + +#else /* !_USE_QSORT */ + + manpages.append(manindex); + +#endif /* _USE_QSORT */ + + } + } + + // + // Now do the sorting on the page names + // and the printout afterwards + // While printing avoid duplicate man page names + // + + struct man_index_t dummy_index = {0l,0l,0}; + struct man_index_t *last_index = &dummy_index; + +#ifdef _USE_QSORT + + // sort and print + qsort(indexlist, listlen, sizeof(struct man_index_t *), compare_man_index); + + TQChar firstchar, tmp; + TQString indexLine="
\n"; + if (indexlist[0]->manpage_len>0) + { + firstchar=TQChar((indexlist[0]->manpage_begin)[0]).lower(); + + const TQString appendixstr = TQString( + " [%3]\n" + ).arg(firstchar).arg(firstchar).arg(firstchar); + indexLine.append(appendixstr); + } + os << "
" << endl; + + for (int i=0; imanpage_begin" has not, + // so do compare at most "manindex->manpage_len" of the strings. + if (last_index->manpage_len == manindex->manpage_len && + !tqstrncmp(last_index->manpage_begin, + manindex->manpage_begin, + manindex->manpage_len) + ) + { + continue; + } + + tmp=TQChar((manindex->manpage_begin)[0]).lower(); + if (firstchar != tmp) + { + firstchar = tmp; + os << "" << endl; + + const TQString appendixstr = TQString( + " [%3]\n" + ).arg(firstchar).arg(firstchar).arg(firstchar); + indexLine.append(appendixstr); + } + os << "" << endl; + last_index = manindex; + } + indexLine.append(""); + + for (int i=0; imanpath); // allocated by strdup + delete indexlist[i]; + } + + delete [] indexlist; + +#else /* !_USE_QSORT */ + + manpages.sort(); // using + + for (QManIndexListIterator mit(manpages); + mit.current(); + ++mit ) + { + struct man_index_t *manindex = mit.current(); + + // tqstrncmp(): + // "last_man" has already a \0 string ending, but + // "manindex->manpage_begin" has not, + // so do compare at most "manindex->manpage_len" of the strings. + if (last_index->manpage_len == manindex->manpage_len && + !tqstrncmp(last_index->manpage_begin, + manindex->manpage_begin, + manindex->manpage_len) + ) + { + continue; + } + + os << "" << endl; + last_index = manindex; + } +#endif /* _USE_QSORT */ +#endif /* _USE_OLD_CODE */ + + os << "
\n" + << it.key() << "  " + << (indexmap.contains(it.key()) ? indexmap[it.key()] : "" ) + << "
\n " << firstchar <<"\n
\n " << firstchar << "\n
manpath << "\">\n"; + + ((char *)manindex->manpage_begin)[manindex->manpage_len] = '\0'; + os << manindex->manpage_begin + << "  " + << (indexmap.contains(manindex->manpage_begin) ? indexmap[manindex->manpage_begin] : "" ) + << "
manpath << "\">\n"; + + manindex->manpage_begin[manindex->manpage_len] = '\0'; + os << manindex->manpage_begin + << "  " + << (indexmap.contains(manindex->manpage_begin) ? indexmap[manindex->manpage_begin] : "" ) + << "
" << endl; + + os << indexLine << endl; + + // print footer + os << "" << endl; + + infoMessage(TQString::null); + mimeType("text/html"); + data(array); + finished(); +} + +void MANProtocol::listDir(const KURL &url) +{ + kdDebug( 7107 ) << "ENTER listDir: " << url.prettyURL() << endl; + + TQString title; + TQString section; + + if ( !parseUrl(url.path(), title, section) ) { + error( TDEIO::ERR_MALFORMED_URL, url.url() ); + return; + } + + TQStringList list = findPages( section, TQString::null, false ); + + UDSEntryList uds_entry_list; + UDSEntry uds_entry; + UDSAtom uds_atom; + + uds_atom.m_uds = TDEIO::UDS_NAME; // we only do names... + uds_entry.append( uds_atom ); + + TQStringList::Iterator it = list.begin(); + TQStringList::Iterator end = list.end(); + + for ( ; it != end; ++it ) { + stripExtension( &(*it) ); + + uds_entry[0].m_str = *it; + uds_entry_list.append( uds_entry ); + } + + listEntries( uds_entry_list ); + finished(); +} + +void MANProtocol::getProgramPath() +{ + if (!mySgml2RoffPath.isEmpty()) + return; + + mySgml2RoffPath = TDEGlobal::dirs()->findExe("sgml2roff"); + if (!mySgml2RoffPath.isEmpty()) + return; + + /* sgml2roff isn't found in PATH. Check some possible locations where it may be found. */ + mySgml2RoffPath = TDEGlobal::dirs()->findExe("sgml2roff", TQString(SGML2ROFF_DIRS)); + if (!mySgml2RoffPath.isEmpty()) + return; + + /* Cannot find sgml2roff programm: */ + outputError(i18n("Could not find the sgml2roff program on your system. Please install it, if necessary, and extend the search path by adjusting the environment variable PATH before starting TDE.")); + finished(); + exit(); +} diff --git a/tdeioslave/man/tdeio_man.css b/tdeioslave/man/tdeio_man.css new file mode 100644 index 000000000..8a9f378bc --- /dev/null +++ b/tdeioslave/man/tdeio_man.css @@ -0,0 +1,21 @@ +body {background-color:#fffff} + +/*for the list of one manpage section*/ +.secidxshort { + display:block; + position:absolute;overflow:auto; + top:0px;bottom:95%;left:0;right:0; +} +.secidxmain { +/*misfortunately accessing anchors in a scrollview + doesn't seem to work yet with konqi, so:*/ +/* + position:absolute;overflow:auto; + top:5%;bottom:0;left:0;right:0; +*/ +} +.secidxnextletter { + font-size:larger; + border-bottom:1px solid black; + text-align:center +} diff --git a/tdeioslave/man/tdeio_man.h b/tdeioslave/man/tdeio_man.h new file mode 100644 index 000000000..7ba9d1dbc --- /dev/null +++ b/tdeioslave/man/tdeio_man.h @@ -0,0 +1,100 @@ +/* This file is part of the KDE libraries + Copyright (c) 2000 Matthias Hoelzer-Kluepfel + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef __tdeio_man_h__ +#define __tdeio_man_h__ + + +#include +#include +#include +#include +#include + + +#include +#include + + +class MANProtocol : public TQObject, public TDEIO::SlaveBase +{ + Q_OBJECT + +public: + + MANProtocol(const TQCString &pool_socket, const TQCString &app_socket); + virtual ~MANProtocol(); + + virtual void get(const KURL& url); + virtual void stat(const KURL& url); + + virtual void mimetype(const KURL &url); + virtual void listDir(const KURL &url); + + void outputError(const TQString& errmsg); + void outputMatchingPages(const TQStringList &matchingPages); + + void showMainIndex(); + void showIndex(const TQString& section); + + // the following two functions are the interface to man2html + void output(const char *insert); + char *readManPage(const char *filename); + + static MANProtocol *self(); + +private slots: + void slotGetStdOutput(TDEProcess*, char*, int); + void slotGetStdOutputUtf8(TDEProcess*, char*, int); + +private: + void checkManPaths(); + TQStringList manDirectories(); + TQMap buildIndexMap(const TQString& section); + bool addWhatIs(TQMap& i, const TQString& f, const TQString& mark); + void parseWhatIs( TQMap &i, TQTextStream &t, const TQString &mark ); + TQStringList findPages(const TQString& section, + const TQString &title, + bool full_path = true); + + void addToBuffer(const char *buffer, int buflen); + TQString pageName(const TQString& page) const; + TQStringList buildSectionList(const TQStringList& dirs) const; + void constructPath(TQStringList& constr_path, TQStringList constr_catmanpath); +private: + static MANProtocol *_self; + TQCString lastdir; + + void findManPagesInSection(const TQString &dir, const TQString &title, bool full_path, TQStringList &list); + TQStringList m_manpath; ///< Path of man directories + TQStringList m_mandbpath; ///< Path of catman directories + TQStringList section_names; + + TQString myStdStream; + TQString mySgml2RoffPath; + void getProgramPath(); + + TQCString m_htmlPath; ///< Path to TDE resources, encoded for HTML + TQCString m_cssPath; ///< Path to TDE resources, encoded for CSS + TQBuffer m_outputBuffer; ///< Buffer for the output + TQString m_manCSSFile; ///< Path to tdeio_man.css +}; + + +#endif diff --git a/tdeioslave/man/tdeio_man_test.cpp b/tdeioslave/man/tdeio_man_test.cpp new file mode 100644 index 000000000..a7f41434e --- /dev/null +++ b/tdeioslave/man/tdeio_man_test.cpp @@ -0,0 +1,38 @@ + + +#include + +#include "tdeio_man.h" + + +#include +#include + + +class tdeio_man_test : public MANProtocol +{ + Q_OBJECT + +public: + tdeio_man_test(const TQCString &pool_socket, const TQCString &app_socket); + +protected: + virtual void data(int); + +}; + + + + + +int main(int argc, char **argv) +{ + TDEApplication a( argc, argv , "p2"); + + MANProtocol testproto("/tmp/tdeiotest.in", "/tmp/tdeiotest.out"); + testproto.showIndex("3"); + + return 0; +} + + -- cgit v1.2.3