|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the tools applications of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 /* |
|
43 main.cpp |
|
44 */ |
|
45 |
|
46 #include <qglobal.h> |
|
47 #include <QtCore> |
|
48 #include <stdlib.h> |
|
49 #include "apigenerator.h" |
|
50 #include "codemarker.h" |
|
51 #include "codeparser.h" |
|
52 #include "config.h" |
|
53 #include "cppcodemarker.h" |
|
54 #include "cppcodeparser.h" |
|
55 #include "cpptoqsconverter.h" |
|
56 #include "doc.h" |
|
57 #include "htmlgenerator.h" |
|
58 #include "jambiapiparser.h" |
|
59 #include "javacodemarker.h" |
|
60 #include "javadocgenerator.h" |
|
61 #include "linguistgenerator.h" |
|
62 #include "loutgenerator.h" |
|
63 #include "mangenerator.h" |
|
64 #include "plaincodemarker.h" |
|
65 #include "polyarchiveextractor.h" |
|
66 #include "polyuncompressor.h" |
|
67 #include "qsakernelparser.h" |
|
68 #include "qscodemarker.h" |
|
69 #include "qscodeparser.h" |
|
70 #include "sgmlgenerator.h" |
|
71 #include "webxmlgenerator.h" |
|
72 #include "tokenizer.h" |
|
73 #include "tree.h" |
|
74 |
|
75 QT_BEGIN_NAMESPACE |
|
76 |
|
77 /* |
|
78 The default indent for code is 4. |
|
79 The default value for false is 0. |
|
80 The default language is c++. |
|
81 The default output format is html. |
|
82 The default tab size is 8. |
|
83 And those are all the default values for configuration variables. |
|
84 */ |
|
85 static const struct { |
|
86 const char *key; |
|
87 const char *value; |
|
88 } defaults[] = { |
|
89 { CONFIG_CODEINDENT, "4" }, |
|
90 { CONFIG_FALSEHOODS, "0" }, |
|
91 { CONFIG_LANGUAGE, "Cpp" }, |
|
92 { CONFIG_OUTPUTFORMATS, "HTML" }, |
|
93 { CONFIG_TABSIZE, "8" }, |
|
94 { 0, 0 } |
|
95 }; |
|
96 |
|
97 static bool slow = false; |
|
98 static bool showInternal = false; |
|
99 static bool obsoleteLinks = false; |
|
100 static QStringList defines; |
|
101 static QHash<QString, Tree *> trees; |
|
102 |
|
103 /*! |
|
104 Find the Tree for language \a lang and return a pointer to it. |
|
105 If there is no Tree for language \a lang in the Tree table, add |
|
106 a new one. The Tree table is indexed by \a lang strings. |
|
107 */ |
|
108 static Tree* treeForLanguage(const QString &lang) |
|
109 { |
|
110 Tree* tree = trees.value(lang); |
|
111 if (tree == 0) { |
|
112 tree = new Tree; |
|
113 trees.insert( lang, tree ); |
|
114 } |
|
115 return tree; |
|
116 } |
|
117 |
|
118 /*! |
|
119 Print the help message to \c stdout. |
|
120 */ |
|
121 static void printHelp() |
|
122 { |
|
123 Location::information(tr("Usage: qdoc [options] file1.qdocconf ...\n" |
|
124 "Options:\n" |
|
125 " -help " |
|
126 "Display this information and exit\n" |
|
127 " -version " |
|
128 "Display version of qdoc and exit\n" |
|
129 " -D<name> " |
|
130 "Define <name> as a macro while parsing sources\n" |
|
131 " -slow " |
|
132 "Turn on features that slow down qdoc\n" |
|
133 " -showinternal " |
|
134 "Include stuff marked internal\n" |
|
135 " -obsoletelinks " |
|
136 "Report links from obsolete items to non-obsolete items") ); |
|
137 } |
|
138 |
|
139 /*! |
|
140 Prints the qdoc version number to stdout. |
|
141 */ |
|
142 static void printVersion() |
|
143 { |
|
144 QString s = QString(tr("qdoc version ")) + QString(QT_VERSION_STR); |
|
145 Location::information(s); |
|
146 } |
|
147 |
|
148 /*! |
|
149 Processes the qdoc config file \a fileName. This is the |
|
150 controller for all of qdoc. |
|
151 */ |
|
152 static void processQdocconfFile(const QString &fileName) |
|
153 { |
|
154 QList<QTranslator *> translators; |
|
155 |
|
156 /* |
|
157 The Config instance represents the configuration data for qdoc. |
|
158 All the other classes are initialized with the config. Here we |
|
159 initialize the configuration with some default values. |
|
160 */ |
|
161 Config config(tr("qdoc")); |
|
162 int i = 0; |
|
163 while (defaults[i].key) { |
|
164 config.setStringList(defaults[i].key, |
|
165 QStringList() << defaults[i].value); |
|
166 ++i; |
|
167 } |
|
168 config.setStringList(CONFIG_SLOW, QStringList(slow ? "true" : "false")); |
|
169 config.setStringList(CONFIG_SHOWINTERNAL, |
|
170 QStringList(showInternal ? "true" : "false")); |
|
171 config.setStringList(CONFIG_OBSOLETELINKS, |
|
172 QStringList(obsoleteLinks ? "true" : "false")); |
|
173 |
|
174 /* |
|
175 With the default configuration values in place, load |
|
176 the qdoc configuration file. Note that the configuration |
|
177 file may include other configuration files. |
|
178 |
|
179 The Location class keeps track of the current location |
|
180 in the file being processed, mainly for error reporting |
|
181 purposes. |
|
182 */ |
|
183 Location::initialize(config); |
|
184 config.load(fileName); |
|
185 |
|
186 /* |
|
187 Add the defines to the configuration variables. |
|
188 */ |
|
189 QStringList defs = defines + config.getStringList(CONFIG_DEFINES); |
|
190 config.setStringList(CONFIG_DEFINES,defs); |
|
191 Location::terminate(); |
|
192 |
|
193 QString prevCurrentDir = QDir::currentPath(); |
|
194 QString dir = QFileInfo(fileName).path(); |
|
195 if (!dir.isEmpty()) |
|
196 QDir::setCurrent(dir); |
|
197 |
|
198 /* |
|
199 Initialize all the classes and data structures with the |
|
200 qdoc configuration. |
|
201 */ |
|
202 Location::initialize(config); |
|
203 Tokenizer::initialize(config); |
|
204 Doc::initialize(config); |
|
205 CppToQsConverter::initialize(config); |
|
206 CodeMarker::initialize(config); |
|
207 CodeParser::initialize(config); |
|
208 Generator::initialize(config); |
|
209 |
|
210 /* |
|
211 Load the language translators, if the configuration specifies any. |
|
212 */ |
|
213 QStringList fileNames = config.getStringList(CONFIG_TRANSLATORS); |
|
214 QStringList::Iterator fn = fileNames.begin(); |
|
215 while (fn != fileNames.end()) { |
|
216 QTranslator *translator = new QTranslator(0); |
|
217 if (!translator->load(*fn)) |
|
218 config.lastLocation().error(tr("Cannot load translator '%1'") |
|
219 .arg(*fn)); |
|
220 QCoreApplication::instance()->installTranslator(translator); |
|
221 translators.append(translator); |
|
222 ++fn; |
|
223 } |
|
224 |
|
225 //QSet<QString> outputLanguages = config.getStringSet(CONFIG_OUTPUTLANGUAGES); |
|
226 |
|
227 /* |
|
228 Get the source language (Cpp) from the configuration |
|
229 and the location in the configuration file where the |
|
230 source language was set. |
|
231 */ |
|
232 QString lang = config.getString(CONFIG_LANGUAGE); |
|
233 Location langLocation = config.lastLocation(); |
|
234 |
|
235 /* |
|
236 Initialize the tree where all the parsed sources will be stored. |
|
237 The tree gets built as the source files are parsed, and then the |
|
238 documentation output is generated by traversing the tree. |
|
239 */ |
|
240 Tree *tree = new Tree; |
|
241 tree->setVersion(config.getString(CONFIG_VERSION)); |
|
242 |
|
243 /* |
|
244 There must be a code parser for the source code language, e.g. C++. |
|
245 If there isn't one, give up. |
|
246 */ |
|
247 CodeParser *codeParser = CodeParser::parserForLanguage(lang); |
|
248 if (codeParser == 0) |
|
249 config.lastLocation().fatal(tr("Cannot parse programming language '%1'").arg(lang)); |
|
250 |
|
251 /* |
|
252 By default, the only output format is HTML. |
|
253 */ |
|
254 QSet<QString> outputFormats = config.getStringSet(CONFIG_OUTPUTFORMATS); |
|
255 Location outputFormatsLocation = config.lastLocation(); |
|
256 |
|
257 /* |
|
258 There must be a code marker for the source code language, e.g. C++. |
|
259 If there isn't one, give up. |
|
260 */ |
|
261 CodeMarker *marker = CodeMarker::markerForLanguage(lang); |
|
262 if (!marker && !outputFormats.isEmpty()) |
|
263 langLocation.fatal(tr("Cannot output documentation for programming language '%1'").arg(lang)); |
|
264 |
|
265 /* |
|
266 Read some XML indexes. What are they??? |
|
267 */ |
|
268 QStringList indexFiles = config.getStringList(CONFIG_INDEXES); |
|
269 tree->readIndexes(indexFiles); |
|
270 |
|
271 /* |
|
272 Get all the header files: "*.ch *.h *.h++ *.hh *.hpp *.hxx" |
|
273 Put them in a set. |
|
274 */ |
|
275 QSet<QString> excludedDirs; |
|
276 QStringList excludedDirsList = config.getStringList(CONFIG_EXCLUDEDIRS); |
|
277 foreach (const QString &excludeDir, excludedDirsList) |
|
278 excludedDirs.insert(QDir::fromNativeSeparators(excludeDir)); |
|
279 QSet<QString> headers = QSet<QString>::fromList( |
|
280 config.getAllFiles(CONFIG_HEADERS, CONFIG_HEADERDIRS, |
|
281 codeParser->headerFileNameFilter(), |
|
282 excludedDirs)); |
|
283 |
|
284 /* |
|
285 Parse each header file in the set and add it to the big tree. |
|
286 */ |
|
287 QSet<QString>::ConstIterator h = headers.begin(); |
|
288 while (h != headers.end()) { |
|
289 codeParser->parseHeaderFile(config.location(), *h, tree); |
|
290 ++h; |
|
291 } |
|
292 codeParser->doneParsingHeaderFiles(tree); |
|
293 |
|
294 /* |
|
295 Get all the source text files: "*.cpp *.qdoc *.mm" |
|
296 Put them in a set. |
|
297 */ |
|
298 QSet<QString> sources = QSet<QString>::fromList( |
|
299 config.getAllFiles(CONFIG_SOURCES, CONFIG_SOURCEDIRS, |
|
300 codeParser->sourceFileNameFilter(), |
|
301 excludedDirs)); |
|
302 |
|
303 /* |
|
304 Parse each source text file in the set and add it to the big tree. |
|
305 */ |
|
306 QSet<QString>::ConstIterator s = sources.begin(); |
|
307 while (s != sources.end()) { |
|
308 codeParser->parseSourceFile(config.location(), *s, tree); |
|
309 ++s; |
|
310 } |
|
311 codeParser->doneParsingSourceFiles(tree); |
|
312 |
|
313 /* |
|
314 Now the big tree has been built from all the header and |
|
315 source files. Resolve all the class names, function names, |
|
316 targets, URLs, links, and other stuff that needs resolving. |
|
317 */ |
|
318 tree->resolveGroups(); |
|
319 tree->resolveTargets(); |
|
320 |
|
321 /* |
|
322 Now the tree has been built, and all the stuff that needed |
|
323 resolving has been resolved. Now it is time to traverse |
|
324 the big tree and generate the documentation output. |
|
325 */ |
|
326 QSet<QString>::ConstIterator of = outputFormats.begin(); |
|
327 while (of != outputFormats.end()) { |
|
328 Generator *generator = Generator::generatorForFormat(*of); |
|
329 if (generator == 0) |
|
330 outputFormatsLocation.fatal(tr("Unknown output format '%1'") |
|
331 .arg(*of)); |
|
332 generator->generateTree(tree, marker); |
|
333 ++of; |
|
334 } |
|
335 |
|
336 /* |
|
337 Generate the XML tag file, if it was requested. |
|
338 */ |
|
339 QString tagFile = config.getString(CONFIG_TAGFILE); |
|
340 if (!tagFile.isEmpty()) |
|
341 tree->generateTagFile(tagFile); |
|
342 |
|
343 tree->setVersion(""); |
|
344 Generator::terminate(); |
|
345 CodeParser::terminate(); |
|
346 CodeMarker::terminate(); |
|
347 CppToQsConverter::terminate(); |
|
348 Doc::terminate(); |
|
349 Tokenizer::terminate(); |
|
350 Location::terminate(); |
|
351 QDir::setCurrent(prevCurrentDir); |
|
352 |
|
353 foreach (QTranslator *translator, translators) |
|
354 delete translator; |
|
355 delete tree; |
|
356 } |
|
357 |
|
358 QT_END_NAMESPACE |
|
359 |
|
360 int main(int argc, char **argv) |
|
361 { |
|
362 QT_USE_NAMESPACE |
|
363 |
|
364 QCoreApplication app(argc, argv); |
|
365 QString cf = "qsauncompress \1 \2"; |
|
366 PolyArchiveExtractor qsaExtractor(QStringList() << "qsa",cf); |
|
367 cf = "tar -C \2 -xf \1"; |
|
368 PolyArchiveExtractor tarExtractor(QStringList() << "tar",cf); |
|
369 cf = "tar -C \2 -Zxf \1"; |
|
370 PolyArchiveExtractor tazExtractor(QStringList() << "taz",cf); |
|
371 cf = "tar -C \2 -jxf \1"; |
|
372 PolyArchiveExtractor tbz2Extractor(QStringList() << "tbz" << "tbz2",cf); |
|
373 cf = "tar -C \2 -zxf \1"; |
|
374 PolyArchiveExtractor tgzExtractor(QStringList() << "tgz",cf); |
|
375 cf = "unzip \1 -d \2"; |
|
376 PolyArchiveExtractor zipExtractor(QStringList() << "zip",cf); |
|
377 cf = "bunzip2 -c \1 > \2"; |
|
378 PolyUncompressor bz2Uncompressor(QStringList() << "bz" << "bz2",cf); |
|
379 cf = "gunzip -c \1 > \2"; |
|
380 PolyUncompressor gzAndZUncompressor(QStringList() << "gz" << "z" << "Z",cf); |
|
381 cf = "unzip -c \1 > \2"; |
|
382 PolyUncompressor zipUncompressor(QStringList() << "zip",cf); |
|
383 |
|
384 /* |
|
385 Create code parsers for the languages to be parsed, |
|
386 and create a tree for C++. |
|
387 */ |
|
388 CppCodeParser cppParser; |
|
389 Tree *cppTree = treeForLanguage(cppParser.language()); |
|
390 |
|
391 QsCodeParser qsParser(cppTree); |
|
392 QsaKernelParser qsaKernelParser(cppTree); |
|
393 JambiApiParser jambiParser(cppTree); |
|
394 |
|
395 /* |
|
396 Create code markers for plain text, C++, Java, and qs. |
|
397 */ |
|
398 PlainCodeMarker plainMarker; |
|
399 CppCodeMarker cppMarker; |
|
400 JavaCodeMarker javaMarker; |
|
401 QsCodeMarker qsMarker; |
|
402 |
|
403 ApiGenerator apiGenerator; |
|
404 HtmlGenerator htmlGenerator; |
|
405 JavadocGenerator javadocGenerator; |
|
406 LinguistGenerator linguistGenerator; |
|
407 LoutGenerator loutGenerator; |
|
408 ManGenerator manGenerator; |
|
409 SgmlGenerator smglGenerator; |
|
410 WebXMLGenerator webxmlGenerator; |
|
411 |
|
412 QStringList qdocFiles; |
|
413 QString opt; |
|
414 int i = 1; |
|
415 |
|
416 while (i < argc) { |
|
417 opt = argv[i++]; |
|
418 |
|
419 if (opt == "-help") { |
|
420 printHelp(); |
|
421 return EXIT_SUCCESS; |
|
422 } |
|
423 else if (opt == "-version") { |
|
424 printVersion(); |
|
425 return EXIT_SUCCESS; |
|
426 } |
|
427 else if (opt == "--") { |
|
428 while (i < argc) |
|
429 qdocFiles.append(argv[i++]); |
|
430 } |
|
431 else if (opt.startsWith("-D")) { |
|
432 QString define = opt.mid(2); |
|
433 defines += define; |
|
434 } |
|
435 else if (opt == "-slow") { |
|
436 slow = true; |
|
437 } |
|
438 else if (opt == "-showinternal") { |
|
439 showInternal = true; |
|
440 } |
|
441 else if (opt == "-obsoletelinks") { |
|
442 obsoleteLinks = true; |
|
443 } |
|
444 else { |
|
445 qdocFiles.append(opt); |
|
446 } |
|
447 } |
|
448 |
|
449 if (qdocFiles.isEmpty()) { |
|
450 printHelp(); |
|
451 return EXIT_FAILURE; |
|
452 } |
|
453 |
|
454 /* |
|
455 Main loop. |
|
456 */ |
|
457 foreach (QString qf, qdocFiles) |
|
458 processQdocconfFile(qf); |
|
459 |
|
460 qDeleteAll(trees); |
|
461 return EXIT_SUCCESS; |
|
462 } |
|
463 |