tools/qdoc3/main.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     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