/**************************************************************************** ** ** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the doxygen2qthelp project on Trolltech Labs. ** ** This file may be used under the terms of the GNU General Public ** License version 2.0 or 3.0 as published by the Free Software Foundation ** and appearing in the file LICENSE.GPL included in the packaging of ** this file. Please review the following information to ensure GNU ** General Public Licensing requirements will be met: ** http://www.fsf.org/licensing/licenses/info/GPLv2.html and ** http://www.gnu.org/copyleft/gpl.html. ** ** If you are unsure which license is appropriate for your use, please ** contact the sales department at qt-sales@nokia.com. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ****************************************************************************/ #include "config.h" #include "htmlhelpdatainterface_p.h" #include "qhelpgenerator_p.h" #include "qthelpprojectwriter_p.h" #include #include #include #include #include #include #include #if (QT_VERSION <= 0x040400) # error Please compile doxygen2qthelp against a Qt release _after_ 4.4.0, e.g. a recent snapshot #endif QT_BEGIN_NAMESPACE const char* const FILE_MISSING_FORMAT = "Error: File '%s' does not exist.\n"; enum Action { ACTION_USAGE, ACTION_RUN, ACTION_QUIT, ACTION_VERSION }; QString virtualFolder; QString nameSpace; QString outputFileName; QString inputFileName; bool verbose = false; bool forceOverwrite = false; bool helpProjectMode = false; bool error = false; void printUsage() { printf( "Usage: doxygen2qthelp OPTIONS []\n" " doxygen2qthelp --config=\n" "\n" "Parameters Description\n" " Read input from \n" " (InputFile=)\n" "\n" " Write output to \n" " (OutputFile=)\n" "\n" " --config= Read config from \n" "\n" " --folder= Set virtual folder [required]\n" " (VirtualFolder=)\n" "\n" " --force Overwrite existing files\n" " (ForceOverwrite=true)\n" "\n" " --help, -h Print help and exit\n" "\n" " --namespace= Set namespace to [required]\n" " (Namespace=)\n" "\n" " --qch Output as Qt Compressed Help file (*.qch) [default]\n" " (QhpMode=false)\n" "\n" " --qhp Output as Qt Help Project (*.qhp)\n" " (QhpMode=true)\n" "\n" " --verbose, -v Report in more detail\n" " (Verbose=true)\n" "\n" " --version, -V Print version information and exit\n" "\n" ); } void printVersion() { printf( "doxygen2qthelp " VERSION " of Qt " QT_VERSION_STR " by Trolltech ASA " "(compiled " __TIME__ ", " __DATE__ ")\n" ); } void printSettings() { printf( "Settings\n" " Input filename ....... %s\n" " Output filename ...... %s\n" "\n" " QtHelpProject mode ... %s\n" " Force overwrite ...... %s\n" "\n" " Namespace ............ %s\n" " Virtual folder ....... %s\n" "\n", qPrintable(inputFileName), qPrintable(outputFileName), helpProjectMode ? "yes" : "no", forceOverwrite ? "yes" : "no", qPrintable(nameSpace), qPrintable(virtualFolder) ); } bool checkNamespace() { const QString uri(QLatin1String("http://") + nameSpace + QLatin1String("/")); const QUrl url = QUrl::fromEncoded(uri.toAscii()); if (!url.isValid()) { printf("Error: Namespace does not conform to the rules " "for the host part of a URI.\n"); return false; } return true; } bool checkVirtualFolder() { const char * const VIRTUAL_FOLDER_ERROR = "Error: Virtual folder does not " "conform to the rules for a path segment of a URI.\n"; if (virtualFolder.contains('/') || virtualFolder.contains('?') || virtualFolder.contains('#')) { printf(VIRTUAL_FOLDER_ERROR); return false; } const QString uri(QLatin1String("http://example.org/") + virtualFolder + QLatin1String("/")); const QUrl url = QUrl::fromEncoded(uri.toAscii()); if (!url.isValid()) { printf(VIRTUAL_FOLDER_ERROR); return false; } return true; } bool checkFiles() { if (inputFileName == outputFileName) { printf("Error: Input and output filename identical\n"); return false; } if (!QFile(inputFileName).exists()) { printf(FILE_MISSING_FORMAT, qPrintable(inputFileName)); return false; } if (!forceOverwrite && QFile(outputFileName).exists()) { printf("Error: File '%s' exists. Use --force to overwrite.\n", qPrintable(outputFileName)); return false; } return true; } void guessOutputFilename() { if (!outputFileName.isEmpty()) return; const QString newSuffix(helpProjectMode ? ".qhp" : ".qch"); if (inputFileName.endsWith(QLatin1String(".hhp"))) { outputFileName = inputFileName.left(inputFileName.count() - 4); } else { outputFileName = inputFileName; } outputFileName += newSuffix; } bool run() { guessOutputFilename(); Q_ASSERT(!inputFileName.isEmpty()); Q_ASSERT(!outputFileName.isEmpty()); if (verbose) printSettings(); if (!checkNamespace() || !checkVirtualFolder() || !checkFiles()) return false; HtmlHelpDataInterface helpData(inputFileName, nameSpace, virtualFolder); if (helpProjectMode) { // Create .qhp QtHelpProjectWriter writer; if (!writer.writeFile(&helpData, outputFileName)) { printf("Error: Could not write to file '%s'.\n", qPrintable(outputFileName)); return false; } } else { // Create .qch QHelpGenerator generator; if (!generator.generate(&helpData, outputFileName)) { printf("Error: %s\n", qPrintable(generator.error())); return false; } } printf("Done.\n"); return true; } void setIfSpecified(const QSettings &iniReader, const QString &key, QString &output) { const QString res = iniReader.value(key).toString(); if (!res.isEmpty()) output = res; } void setIfSpecified(const QSettings &iniReader, const QString &key, bool &output) { const QVariant res = iniReader.value(key); if (!res.toString().isEmpty()) output = res.toBool(); } bool readConfigFile(const QString &fileName) { if (!QFile(fileName).exists()) { printf(FILE_MISSING_FORMAT, qPrintable(fileName)); return false; } QSettings iniReader(fileName, QSettings::IniFormat); setIfSpecified(iniReader, QLatin1String("ForceOverwrite"), forceOverwrite); setIfSpecified(iniReader, QLatin1String("InputFile"), inputFileName); setIfSpecified(iniReader, QLatin1String("Namespace"), nameSpace); setIfSpecified(iniReader, QLatin1String("OutputFile"), outputFileName); setIfSpecified(iniReader, QLatin1String("QhpMode"), helpProjectMode); setIfSpecified(iniReader, QLatin1String("Verbose"), verbose); setIfSpecified(iniReader, QLatin1String("VirtualFolder"), virtualFolder); return true; } Action parseArgs() { const char * const ILLEGAL_OPTION_FORMAT = "Error: Illegal option '%s'\n\n"; const QStringList args = QCoreApplication::arguments(); bool fileMode = false; for (int i = 1; i < args.count(); i++) { const QString &curArg = args.at(i); if (fileMode || (curArg[0] != '-')) { // Filenames only switch (args.count() - i) { case 2: // second last inputFileName = curArg; break; case 1: // last if (inputFileName.isEmpty()) { inputFileName = curArg; } else { outputFileName = curArg; } break; default: if (!fileMode) printf(ILLEGAL_OPTION_FORMAT, qPrintable(curArg)); error = true; return ACTION_USAGE; } } else { // Options or filenames QString opt; if (curArg[1] == '-') { // Long option opt = curArg.mid(2); if (opt.isEmpty()) { fileMode = true; } else if (opt.startsWith(QLatin1String("config="))) { if (!readConfigFile(opt.mid(6 + 1))) { return ACTION_QUIT; } } else if (opt.startsWith("folder=")) { virtualFolder = opt.mid(6 + 1); } else if (opt == QLatin1String("force")) { forceOverwrite = true; } else if (opt == QLatin1String("help")) { return ACTION_USAGE; } else if (opt.startsWith("namespace=")) { nameSpace = opt.mid(9 + 1); } else if (opt == QLatin1String("qch")) { helpProjectMode = false; } else if (opt == QLatin1String("qhp")) { helpProjectMode = true; } else if (opt == QLatin1String("verbose")) { verbose = true; } else if (opt == QLatin1String("version")) { return ACTION_VERSION; } else { printf(ILLEGAL_OPTION_FORMAT, qPrintable(curArg)); error = true; return ACTION_USAGE; } } else { // Short option opt = curArg.mid(1); if (opt.count() != 1) { printf(ILLEGAL_OPTION_FORMAT, qPrintable(curArg)); error = true; return ACTION_USAGE; } switch (opt.at(0).toAscii()) { case 'h': return ACTION_USAGE; case 'v': verbose = true; break; case 'V': return ACTION_VERSION; default: printf(ILLEGAL_OPTION_FORMAT, qPrintable(curArg)); error = true; return ACTION_USAGE; } } } } if (inputFileName.isEmpty()) { printf("Error: No input filename specified\n\n"); error = true; return ACTION_USAGE; } if (nameSpace.isEmpty()) { printf("Error: Namespace must not be empty.\n\n"); error = true; return ACTION_USAGE; } if (virtualFolder.isEmpty()) { printf("Error: Virtual folder must not be empty.\n\n"); error = true; return ACTION_USAGE; } return ACTION_RUN; } QT_END_NAMESPACE int main(int argc, char ** argv) { QCoreApplication app(argc, argv); const Action action = parseArgs(); switch (action) { case ACTION_RUN: error = ! run(); break; case ACTION_VERSION: printVersion(); break; case ACTION_QUIT: break; case ACTION_USAGE: // fall through default: printUsage(); break; } return error ? 1 : 0; }