1
2#include <config-kdoctools.h>
3#include <config.h>
4#include "xslt.h"
5#include "meinproc_common.h"
6
7#include <QCoreApplication>
8#include <QtCore/QString>
9#include <QtCore/QFile>
10#include <QtCore/QDir>
11#include <QtCore/QTextCodec>
12#include <QtCore/QFileInfo>
13#include <QtCore/QList>
14
15#include <kaboutdata.h>
16#include <kcomponentdata.h>
17#include <kcmdlineargs.h>
18#include <kdebug.h>
19#include <klocale.h>
20#include <kstandarddirs.h>
21#include <kshell.h>
22#include <kurl.h>
23
24#include <libxml/xmlversion.h>
25#include <libxml/xmlmemory.h>
26#include <libxml/debugXML.h>
27#include <libxml/HTMLtree.h>
28#include <libxml/xmlIO.h>
29#include <libxml/parserInternals.h>
30#include <libxslt/xsltconfig.h>
31#include <libxslt/xsltInternals.h>
32#include <libxslt/transform.h>
33#include <libxslt/xsltutils.h>
34#include <libexslt/exslt.h>
35
36#include <stdlib.h>
37#include <string.h>
38#include <sys/time.h>
39#include <unistd.h>
40
41#ifndef _WIN32
42extern "C" int xmlLoadExtDtdDefaultValue;
43#endif
44
45class MyPair {
46public:
47 QString word;
48 int base;};
49
50typedef QList<MyPair> PairList;
51
52void parseEntry(PairList &list, xmlNodePtr cur, int base)
53{
54 if ( !cur )
55 return;
56
57 base += atoi( ( const char* )xmlGetProp(cur, ( const xmlChar* )"header") );
58 if ( base > 10 ) // 10 is the maximum
59 base = 10;
60
61 /* We don't care what the top level element name is */
62 cur = cur->xmlChildrenNode;
63 while (cur != NULL) {
64
65 if ( cur->type == XML_TEXT_NODE ) {
66 QString words = QString::fromUtf8( ( char* )cur->content );
67 const QStringList wlist = words.simplified().split( ' ',QString::SkipEmptyParts );
68 for ( QStringList::ConstIterator it = wlist.begin();
69 it != wlist.end(); ++it )
70 {
71 MyPair m;
72 m.word = *it;
73 m.base = base;
74 list.append( m );
75 }
76 } else if ( !xmlStrcmp( cur->name, (const xmlChar *) "entry") )
77 parseEntry( list, cur, base );
78
79 cur = cur->next;
80 }
81
82}
83
84int main(int argc, char **argv) {
85
86 // xsltSetGenericDebugFunc(stderr, NULL);
87
88 KCmdLineOptions options;
89 options.add("stylesheet <xsl>", ki18n("Stylesheet to use"));
90 options.add("stdout", ki18n("Output whole document to stdout"));
91 options.add("o");
92 options.add("output <file>", ki18n("Output whole document to file"));
93 options.add("htdig", ki18n("Create a ht://dig compatible index"));
94 options.add("check", ki18n("Check the document for validity"));
95 options.add("cache <file>", ki18n("Create a cache file for the document"));
96 options.add("srcdir <dir>", ki18n("Set the srcdir, for kdelibs"));
97 options.add("param <key>=<value>", ki18n("Parameters to pass to the stylesheet"));
98 options.add("+xml", ki18n("The file to transform"));
99
100 KAboutData aboutData( "meinproc4", "kio_help4", ki18n("XML-Translator" ),
101 "$Revision$",
102 ki18n("KDE Translator for XML"));
103
104 KCmdLineArgs::init(argc, argv, &aboutData, KCmdLineArgs::CmdLineArgKDE);
105 KCmdLineArgs::addCmdLineOptions( options );
106
107 QCoreApplication app( argc, argv );
108 KComponentData ins("kio_help4");
109 KGlobal::locale();
110
111 KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
112 if ( args->count() != 1 ) {
113 args->usage();
114 return ( 1 );
115 }
116
117 exsltRegisterAll();
118
119 // Need to set SRCDIR before calling fillInstance
120 QString srcdir;
121 if ( args->isSet( "srcdir" ) )
122 srcdir = QDir( args->getOption( "srcdir" ) ).absolutePath();
123 fillInstance(ins,srcdir);
124
125 LIBXML_TEST_VERSION
126
127 const QString checkFilename = args->arg( 0 );
128 CheckFileResult ckr = checkFile( checkFilename );
129 if ( ckr != CheckFileSuccess )
130 {
131 if ( ckr == CheckFileDoesNotExist ) kError() << "File '" << checkFilename << "' does not exist.";
132 else if ( ckr == CheckFileIsNotFile ) kError() << "'" << checkFilename << "' is not a file.";
133 else if ( ckr == CheckFileIsNotReadable ) kError() << "File '" << checkFilename << "' is not readable.";
134 return ( 2 );
135 }
136
137 if ( args->isSet( "check" ) ) {
138
139 QByteArray catalogs;
140 catalogs += KUrl::fromLocalFile( KStandardDirs::locate( "dtd", "customization/catalog.xml" ) ).toEncoded();
141
142 QString exe;
143#if defined( XMLLINT )
144 exe = XMLLINT;
145#endif
146 if ( !QFileInfo( exe ).isExecutable() ) {
147 exe = KStandardDirs::findExe( "xmllint" );
148 if (exe.isEmpty())
149 exe = KStandardDirs::locate( "exe", "xmllint" );
150 }
151
152 CheckResult cr = check( checkFilename, exe, catalogs );
153 if ( cr != CheckSuccess )
154 {
155 if ( cr == CheckNoXmllint ) kWarning() << "couldn't find xmllint";
156 return 1;
157 }
158 }
159
160 QVector<const char *> params;
161 {
162 const QStringList paramList = args->getOptionList( "param" );
163 QStringList::ConstIterator it = paramList.begin();
164 QStringList::ConstIterator end = paramList.end();
165 for ( ; it != end; ++it ) {
166 const QString tuple = *it;
167 const int ch = tuple.indexOf( '=' );
168 if ( ch == -1 ) {
169 kError() << "Key-Value tuple '" << tuple << "' lacks a '='!" << endl;
170 return( 2 );
171 }
172 params.append( qstrdup( tuple.left( ch ).toUtf8() ) );
173 params.append( qstrdup( tuple.mid( ch + 1 ).toUtf8() ) );
174 }
175 }
176 params.append( NULL );
177
178 bool index = args->isSet( "htdig" );
179 QString tss = args->getOption( "stylesheet" );
180 if ( tss.isEmpty() )
181 tss = "customization/kde-chunk.xsl";
182 if ( index )
183 tss = "customization/htdig_index.xsl" ;
184
185 tss = KStandardDirs::locate( "dtd", tss );
186 const QString cache = args->getOption( "cache" );
187 const bool usingStdOut = args->isSet( "stdout" );
188 const bool usingOutput = args->isSet("output");
189 const QString outputOption = args->getOption( "output" );
190
191 if ( index ) {
192 xsltStylesheetPtr style_sheet =
193 xsltParseStylesheetFile((const xmlChar *)tss.toLatin1().data());
194
195 if (style_sheet != NULL) {
196
197 xmlDocPtr doc = xmlReadFile( QFile::encodeName( checkFilename ).constData(),
198 NULL, XML_PARSE_NOENT|XML_PARSE_DTDLOAD|XML_PARSE_NONET );
199 xmlDocPtr res = xsltApplyStylesheet(style_sheet, doc, &params[0]);
200
201 xmlFreeDoc(doc);
202 xsltFreeStylesheet(style_sheet);
203 if (res != NULL) {
204 xmlNodePtr cur = xmlDocGetRootElement(res);
205 if (!cur || xmlStrcmp(cur->name, (const xmlChar *) "entry")) {
206 fprintf(stderr,"document of the wrong type, root node != entry");
207 xmlFreeDoc(res);
208 return(1);
209 }
210 PairList list;
211 parseEntry( list, cur, 0 );
212 int wi = 0;
213 for ( PairList::ConstIterator it = list.constBegin(); it != list.constEnd();
214 ++it, ++wi )
215 fprintf( stdout, "w\t%s\t%d\t%d\n", ( *it ).word.toUtf8().data(),
216 1000*wi/list.count(), ( *it ).base );
217
218 xmlFreeDoc(res);
219 } else {
220 kDebug() << "couldn't parse document " << checkFilename;
221 }
222 } else {
223 kDebug() << "couldn't parse style sheet " << tss;
224 }
225
226 } else {
227 QString output = transform(checkFilename , tss, params);
228 if (output.isEmpty()) {
229 fprintf(stderr, "unable to parse %s\n", checkFilename.toLocal8Bit().data());
230 return(1);
231 }
232
233 if ( !cache.isEmpty() ) {
234 if ( !saveToCache( output, cache ) ) {
235 kError() << i18n( "Could not write to cache file %1." , cache ) << endl;
236 }
237 goto end;
238 }
239
240 doOutput(output, usingStdOut, usingOutput, outputOption, true /* replaceCharset */);
241 }
242 end:
243 xmlCleanupParser();
244 xmlMemoryDump();
245 return(0);
246}
247
248