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