00001 #ifndef _WIN32
00002 extern "C" int xmlLoadExtDtdDefaultValue;
00003 #endif
00004
00005 #include <QCoreApplication>
00006 #include <config-kdoctools.h>
00007 #include <config.h>
00008 #include <string.h>
00009 #include <sys/time.h>
00010 #include <unistd.h>
00011 #include <libxml/xmlversion.h>
00012 #include <libxml/xmlmemory.h>
00013 #include <libxml/debugXML.h>
00014 #include <libxml/HTMLtree.h>
00015 #include <libxml/xmlIO.h>
00016 #include <libxml/parserInternals.h>
00017 #include <libxslt/xsltconfig.h>
00018 #include <libxslt/xsltInternals.h>
00019 #include <libxslt/transform.h>
00020 #include <libxslt/xsltutils.h>
00021 #include <QtCore/QString>
00022 #include <kstandarddirs.h>
00023 #include <kcomponentdata.h>
00024 #include "xslt.h"
00025 #include <QtCore/QFile>
00026 #include <QtCore/QDir>
00027 #include <kcmdlineargs.h>
00028 #include <klocale.h>
00029 #include <kaboutdata.h>
00030 #include <stdlib.h>
00031 #include <kdebug.h>
00032 #include <QtCore/QTextCodec>
00033 #include <QtCore/QFileInfo>
00034 #include <kshell.h>
00035 #include <kurl.h>
00036 #include <QtCore/QList>
00037
00038 class MyPair {
00039 public:
00040 QString word;
00041 int base;};
00042
00043 typedef QList<MyPair> PairList;
00044
00045 void parseEntry(PairList &list, xmlNodePtr cur, int base)
00046 {
00047 if ( !cur )
00048 return;
00049
00050 base += atoi( ( const char* )xmlGetProp(cur, ( const xmlChar* )"header") );
00051 if ( base > 10 )
00052 base = 10;
00053
00054
00055 cur = cur->xmlChildrenNode;
00056 while (cur != NULL) {
00057
00058 if ( cur->type == XML_TEXT_NODE ) {
00059 QString words = QString::fromUtf8( ( char* )cur->content );
00060 const QStringList wlist = words.simplified().split( ' ',QString::SkipEmptyParts );
00061 for ( QStringList::ConstIterator it = wlist.begin();
00062 it != wlist.end(); ++it )
00063 {
00064 MyPair m;
00065 m.word = *it;
00066 m.base = base;
00067 list.append( m );
00068 }
00069 } else if ( !xmlStrcmp( cur->name, (const xmlChar *) "entry") )
00070 parseEntry( list, cur, base );
00071
00072 cur = cur->next;
00073 }
00074
00075 }
00076
00077 int main(int argc, char **argv) {
00078
00079
00080
00081 KCmdLineOptions options;
00082 options.add("stylesheet <xsl>", ki18n("Stylesheet to use"));
00083 options.add("stdout", ki18n("Output whole document to stdout"));
00084 options.add("o");
00085 options.add("output <file>", ki18n("Output whole document to file"));
00086 options.add("htdig", ki18n("Create a ht://dig compatible index"));
00087 options.add("check", ki18n("Check the document for validity"));
00088 options.add("cache <file>", ki18n("Create a cache file for the document"));
00089 options.add("srcdir <dir>", ki18n("Set the srcdir, for kdelibs"));
00090 options.add("param <key>=<value>", ki18n("Parameters to pass to the stylesheet"));
00091 options.add("+xml", ki18n("The file to transform"));
00092
00093 KAboutData aboutData( "meinproc4", "kio_help4", ki18n("XML-Translator" ),
00094 "$Revision: 1002073 $",
00095 ki18n("KDE Translator for XML"));
00096
00097 KCmdLineArgs::init(argc, argv, &aboutData, KCmdLineArgs::CmdLineArgKDE);
00098 KCmdLineArgs::addCmdLineOptions( options );
00099
00100 QCoreApplication app( argc, argv );
00101 KComponentData ins("kio_help4");
00102 KGlobal::locale();
00103
00104 KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
00105 if ( args->count() != 1 ) {
00106 args->usage();
00107 return ( 1 );
00108 }
00109
00110
00111 QString srcdir;
00112 if ( args->isSet( "srcdir" ) )
00113 srcdir = QDir( args->getOption( "srcdir" ) ).absolutePath();
00114 fillInstance(ins,srcdir);
00115
00116 LIBXML_TEST_VERSION
00117
00118 QString checkFilename = args->arg( 0 );
00119 QFileInfo checkFile(checkFilename);
00120 if (!checkFile.exists())
00121 {
00122 kError() << "File '" << checkFilename << "' does not exist." << endl;
00123 return ( 2 );
00124 }
00125 if (!checkFile.isFile())
00126 {
00127 kError() << "'" << checkFilename << "' is not a file." << endl;
00128 return ( 2 );
00129 }
00130 if (!checkFile.isReadable())
00131 {
00132 kError() << "File '" << checkFilename << "' is not readable." << endl;
00133 return ( 2 );
00134 }
00135
00136 if ( args->isSet( "check" ) ) {
00137 QString pwd_buffer = QDir::currentPath();
00138 QFileInfo file( args->arg( 0 ) );
00139
00140 QByteArray catalogs;
00141 catalogs += KUrl::fromLocalFile( KStandardDirs::locate( "dtd", "customization/catalog.xml" ) ).toEncoded();
00142 catalogs += ' ';
00143 catalogs += KUrl::fromLocalFile( KStandardDirs::locate( "dtd", "docbook/xml-dtd-4.1.2/catalog.xml" ) ).toEncoded();
00144
00145 setenv( "XML_CATALOG_FILES", catalogs.constData(), 1 );
00146 QString exe;
00147 #if defined( XMLLINT )
00148 exe = XMLLINT;
00149 #endif
00150 if ( !QFileInfo( exe ).isExecutable() ) {
00151 exe = KStandardDirs::findExe( "xmllint" );
00152 if (exe.isEmpty())
00153 exe = KStandardDirs::locate( "exe", "xmllint" );
00154 }
00155 if ( QFileInfo( exe ).isExecutable() ) {
00156 QDir::setCurrent( file.absolutePath() );
00157 QString cmd = exe;
00158 cmd += " --valid --noout ";
00159 #ifdef Q_OS_WIN
00160 cmd += file.fileName();
00161 #else
00162 cmd += KShell::quoteArg(file.fileName());
00163 #endif
00164 cmd += " 2>&1";
00165 FILE *xmllint = popen( QFile::encodeName( cmd ).constData(), "r" );
00166 char buf[ 512 ];
00167 bool noout = true;
00168 unsigned int n;
00169 while ( ( n = fread(buf, 1, sizeof( buf ) - 1, xmllint ) ) ) {
00170 noout = false;
00171 buf[ n ] = '\0';
00172 fputs( buf, stderr );
00173 }
00174 pclose( xmllint );
00175 QDir::setCurrent( pwd_buffer );
00176 if ( !noout )
00177 return 1;
00178 } else {
00179 kWarning() << "couldn't find xmllint";
00180 }
00181 }
00182
00183 xmlSubstituteEntitiesDefault(1);
00184 xmlLoadExtDtdDefaultValue = 1;
00185
00186 QVector<const char *> params;
00187 #ifndef Q_WS_WIN
00188
00189
00190
00191
00192 if (args->isSet( "output" ) ) {
00193 params.append( qstrdup( "outputFile" ) );
00194 params.append( qstrdup( args->getOption( "output" ).toLocal8Bit() ) );
00195 }
00196 #endif
00197 {
00198 const QStringList paramList = args->getOptionList( "param" );
00199 QStringList::ConstIterator it = paramList.begin();
00200 QStringList::ConstIterator end = paramList.end();
00201 for ( ; it != end; ++it ) {
00202 const QString tuple = *it;
00203 const int ch = tuple.indexOf( '=' );
00204 if ( ch == -1 ) {
00205 kError() << "Key-Value tuple '" << tuple << "' lacks a '='!" << endl;
00206 return( 2 );
00207 }
00208 params.append( qstrdup( tuple.left( ch ).toUtf8() ) );
00209 params.append( qstrdup( tuple.mid( ch + 1 ).toUtf8() ) );
00210 }
00211 }
00212 params.append( NULL );
00213
00214 bool index = args->isSet( "htdig" );
00215 QString tss = args->getOption( "stylesheet" );
00216 if ( tss.isEmpty() )
00217 tss = "customization/kde-chunk.xsl";
00218 if ( index )
00219 tss = "customization/htdig_index.xsl" ;
00220
00221 tss = KStandardDirs::locate( "dtd", tss );
00222
00223 if ( index ) {
00224 xsltStylesheetPtr style_sheet =
00225 xsltParseStylesheetFile((const xmlChar *)tss.toLatin1().data());
00226
00227 if (style_sheet != NULL) {
00228
00229 xmlDocPtr doc = xmlParseFile( QFile::encodeName( args->arg( 0 ) ).constData() );
00230
00231 xmlDocPtr res = xsltApplyStylesheet(style_sheet, doc, ¶ms[0]);
00232
00233 xmlFreeDoc(doc);
00234 xsltFreeStylesheet(style_sheet);
00235 if (res != NULL) {
00236 xmlNodePtr cur = xmlDocGetRootElement(res);
00237 if (!cur || xmlStrcmp(cur->name, (const xmlChar *) "entry")) {
00238 fprintf(stderr,"document of the wrong type, root node != entry");
00239 xmlFreeDoc(res);
00240 return(1);
00241 }
00242 PairList list;
00243 parseEntry( list, cur, 0 );
00244 int wi = 0;
00245 for ( PairList::ConstIterator it = list.constBegin(); it != list.constEnd();
00246 ++it, ++wi )
00247 fprintf( stdout, "w\t%s\t%d\t%d\n", ( *it ).word.toUtf8().data(),
00248 1000*wi/list.count(), ( *it ).base );
00249
00250 xmlFreeDoc(res);
00251 } else {
00252 kDebug() << "couldn't parse document " << args->arg( 0 );
00253 }
00254 } else {
00255 kDebug() << "couldn't parse style sheet " << tss;
00256 }
00257
00258 } else {
00259 QString output = transform(args->arg( 0 ) , tss, params);
00260 if (output.isEmpty()) {
00261 fprintf(stderr, "unable to parse %s\n", args->arg( 0 ).toLocal8Bit().data());
00262 return(1);
00263 }
00264
00265 QString cache = args->getOption( "cache" );
00266 if ( !cache.isEmpty() ) {
00267 if ( !saveToCache( output, cache ) ) {
00268 kError() << i18n( "Could not write to cache file %1." , cache ) << endl;
00269 }
00270 goto end;
00271 }
00272
00273 if (output.indexOf( "<FILENAME " ) == -1 || args->isSet( "stdout" ) || args->isSet("output") )
00274 {
00275 QFile file;
00276 if (args->isSet( "stdout" ) ) {
00277 file.open( stdout, QIODevice::WriteOnly );
00278 } else {
00279 if (args->isSet( "output" ) )
00280 file.setFileName( args->getOption( "output" ));
00281 else
00282 file.setFileName( "index.html" );
00283 file.open(QIODevice::WriteOnly);
00284 }
00285 replaceCharsetHeader( output );
00286 #ifdef Q_WS_WIN
00287 QByteArray data = output.toUtf8();
00288 #else
00289 QByteArray data = output.toLocal8Bit();
00290 #endif
00291 file.write(data.data(), data.length());
00292 file.close();
00293 } else {
00294 int index = 0;
00295 while (true) {
00296 index = output.indexOf("<FILENAME ", index);
00297 if (index == -1)
00298 break;
00299 int filename_index = index + strlen("<FILENAME filename=\"");
00300
00301 QString filename = output.mid(filename_index,
00302 output.indexOf("\"", filename_index) -
00303 filename_index);
00304
00305 QString filedata = splitOut(output, index);
00306 QFile file(filename);
00307 file.open(QIODevice::WriteOnly);
00308 replaceCharsetHeader( filedata );
00309 QByteArray data = fromUnicode( filedata );
00310 file.write(data.data(), data.length());
00311 file.close();
00312
00313 index += 8;
00314 }
00315 }
00316 }
00317 end:
00318 xmlCleanupParser();
00319 xmlMemoryDump();
00320 return(0);
00321 }
00322