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 |
42 | extern "C" int xmlLoadExtDtdDefaultValue; |
43 | #endif |
44 | |
45 | class MyPair { |
46 | public: |
47 | QString word; |
48 | int base;}; |
49 | |
50 | typedef QList<MyPair> PairList; |
51 | |
52 | void 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 | |
84 | int 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, ¶ms[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 | |