diff options
Diffstat (limited to 'src/tools/qdoc/doc.cpp')
-rw-r--r-- | src/tools/qdoc/doc.cpp | 3380 |
1 files changed, 0 insertions, 3380 deletions
diff --git a/src/tools/qdoc/doc.cpp b/src/tools/qdoc/doc.cpp deleted file mode 100644 index 4ed5894543..0000000000 --- a/src/tools/qdoc/doc.cpp +++ /dev/null @@ -1,3380 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "config.h" -#include "doc.h" -#include "codemarker.h" -#include "editdistance.h" -#include "openedlist.h" -#include "quoter.h" -#include "text.h" -#include "atom.h" -#include "tokenizer.h" -#include <qdatetime.h> -#include <qfile.h> -#include <qfileinfo.h> -#include <qhash.h> -#include <qtextstream.h> -#include <qregexp.h> -#include <ctype.h> -#include <limits.h> -#include <qdebug.h> -#include "generator.h" - -QT_BEGIN_NAMESPACE - -Q_GLOBAL_STATIC(QSet<QString>, null_Set_QString) -Q_GLOBAL_STATIC(TopicList, nullTopicList) -Q_GLOBAL_STATIC(QStringList, null_QStringList) -Q_GLOBAL_STATIC(QList<Text>, null_QList_Text) -Q_GLOBAL_STATIC(QStringMultiMap, null_QStringMultiMap) - -struct Macro -{ - QString defaultDef; - Location defaultDefLocation; - QStringMap otherDefs; - int numParams; -}; - -enum { - CMD_A, - CMD_ANNOTATEDLIST, - CMD_B, - CMD_BADCODE, - CMD_BOLD, - CMD_BR, - CMD_BRIEF, - CMD_C, - CMD_CAPTION, - CMD_CHAPTER, - CMD_CODE, - CMD_CODELINE, - CMD_DIV, - CMD_DOTS, - CMD_E, - CMD_ELSE, - CMD_ENDCHAPTER, - CMD_ENDCODE, - CMD_ENDDIV, - CMD_ENDFOOTNOTE, - CMD_ENDIF, - CMD_ENDLEGALESE, - CMD_ENDLINK, - CMD_ENDLIST, - CMD_ENDMAPREF, - CMD_ENDOMIT, - CMD_ENDPART, - CMD_ENDQUOTATION, - CMD_ENDRAW, - CMD_ENDSECTION1, - CMD_ENDSECTION2, - CMD_ENDSECTION3, - CMD_ENDSECTION4, - CMD_ENDSIDEBAR, - CMD_ENDTABLE, - CMD_ENDTOPICREF, - CMD_FOOTNOTE, - CMD_GENERATELIST, - CMD_GRANULARITY, - CMD_HEADER, - CMD_HR, - CMD_I, - CMD_IF, - CMD_IMAGE, - CMD_IMPORTANT, - CMD_INCLUDE, - CMD_INLINEIMAGE, - CMD_INDEX, - CMD_INPUT, - CMD_KEYWORD, - CMD_L, - CMD_LEGALESE, - CMD_LI, - CMD_LINK, - CMD_LIST, - CMD_MAPREF, - CMD_META, - CMD_NEWCODE, - CMD_NOTE, - CMD_O, - CMD_OLDCODE, - CMD_OMIT, - CMD_OMITVALUE, - CMD_OVERLOAD, - CMD_PART, - CMD_PRINTLINE, - CMD_PRINTTO, - CMD_PRINTUNTIL, - CMD_QUOTATION, - CMD_QUOTEFILE, - CMD_QUOTEFROMFILE, - CMD_QUOTEFUNCTION, - CMD_RAW, - CMD_ROW, - CMD_SA, - CMD_SECTION1, - CMD_SECTION2, - CMD_SECTION3, - CMD_SECTION4, - CMD_SIDEBAR, - CMD_SINCELIST, - CMD_SKIPLINE, - CMD_SKIPTO, - CMD_SKIPUNTIL, - CMD_SNIPPET, - CMD_SPAN, - CMD_SUB, - CMD_SUP, - CMD_TABLE, - CMD_TABLEOFCONTENTS, - CMD_TARGET, - CMD_TOPICREF, - CMD_TT, - CMD_UICONTROL, - CMD_UNDERLINE, - CMD_UNICODE, - CMD_VALUE, - CMD_WARNING, - CMD_QML, - CMD_ENDQML, - CMD_CPP, - CMD_ENDCPP, - CMD_QMLTEXT, - CMD_ENDQMLTEXT, - CMD_CPPTEXT, - CMD_ENDCPPTEXT, - CMD_JS, - CMD_ENDJS, - NOT_A_CMD -}; - -static struct { - const char *english; - int no; - QString *alias; -} cmds[] = { - { "a", CMD_A, 0 }, - { "annotatedlist", CMD_ANNOTATEDLIST, 0 }, - { "b", CMD_B, 0 }, - { "badcode", CMD_BADCODE, 0 }, - { "bold", CMD_BOLD, 0 }, - { "br", CMD_BR, 0 }, - { "brief", CMD_BRIEF, 0 }, - { "c", CMD_C, 0 }, - { "caption", CMD_CAPTION, 0 }, - { "chapter", CMD_CHAPTER, 0 }, - { "code", CMD_CODE, 0 }, - { "codeline", CMD_CODELINE, 0}, - { "div", CMD_DIV, 0 }, - { "dots", CMD_DOTS, 0 }, - { "e", CMD_E, 0 }, - { "else", CMD_ELSE, 0 }, - { "endchapter", CMD_ENDCHAPTER, 0 }, - { "endcode", CMD_ENDCODE, 0 }, - { "enddiv", CMD_ENDDIV, 0 }, - { "endfootnote", CMD_ENDFOOTNOTE, 0 }, - { "endif", CMD_ENDIF, 0 }, - { "endlegalese", CMD_ENDLEGALESE, 0 }, - { "endlink", CMD_ENDLINK, 0 }, - { "endlist", CMD_ENDLIST, 0 }, - { "endmapref", CMD_ENDMAPREF, 0 }, - { "endomit", CMD_ENDOMIT, 0 }, - { "endpart", CMD_ENDPART, 0 }, - { "endquotation", CMD_ENDQUOTATION, 0 }, - { "endraw", CMD_ENDRAW, 0 }, - { "endsection1", CMD_ENDSECTION1, 0 }, // ### don't document for now - { "endsection2", CMD_ENDSECTION2, 0 }, // ### don't document for now - { "endsection3", CMD_ENDSECTION3, 0 }, // ### don't document for now - { "endsection4", CMD_ENDSECTION4, 0 }, // ### don't document for now - { "endsidebar", CMD_ENDSIDEBAR, 0 }, - { "endtable", CMD_ENDTABLE, 0 }, - { "endtopicref", CMD_ENDTOPICREF, 0 }, - { "footnote", CMD_FOOTNOTE, 0 }, - { "generatelist", CMD_GENERATELIST, 0 }, - { "granularity", CMD_GRANULARITY, 0 }, // ### don't document for now - { "header", CMD_HEADER, 0 }, - { "hr", CMD_HR, 0 }, - { "i", CMD_I, 0 }, - { "if", CMD_IF, 0 }, - { "image", CMD_IMAGE, 0 }, - { "important", CMD_IMPORTANT, 0 }, - { "include", CMD_INCLUDE, 0 }, - { "inlineimage", CMD_INLINEIMAGE, 0 }, - { "index", CMD_INDEX, 0 }, // ### don't document for now - { "input", CMD_INPUT, 0 }, - { "keyword", CMD_KEYWORD, 0 }, - { "l", CMD_L, 0 }, - { "legalese", CMD_LEGALESE, 0 }, - { "li", CMD_LI, 0 }, - { "link", CMD_LINK, 0 }, - { "list", CMD_LIST, 0 }, - { "mapref", CMD_MAPREF, 0 }, - { "meta", CMD_META, 0 }, - { "newcode", CMD_NEWCODE, 0 }, - { "note", CMD_NOTE, 0 }, - { "o", CMD_O, 0 }, - { "oldcode", CMD_OLDCODE, 0 }, - { "omit", CMD_OMIT, 0 }, - { "omitvalue", CMD_OMITVALUE, 0 }, - { "overload", CMD_OVERLOAD, 0 }, - { "part", CMD_PART, 0 }, - { "printline", CMD_PRINTLINE, 0 }, - { "printto", CMD_PRINTTO, 0 }, - { "printuntil", CMD_PRINTUNTIL, 0 }, - { "quotation", CMD_QUOTATION, 0 }, - { "quotefile", CMD_QUOTEFILE, 0 }, - { "quotefromfile", CMD_QUOTEFROMFILE, 0 }, - { "quotefunction", CMD_QUOTEFUNCTION, 0 }, - { "raw", CMD_RAW, 0 }, - { "row", CMD_ROW, 0 }, - { "sa", CMD_SA, 0 }, - { "section1", CMD_SECTION1, 0 }, - { "section2", CMD_SECTION2, 0 }, - { "section3", CMD_SECTION3, 0 }, - { "section4", CMD_SECTION4, 0 }, - { "sidebar", CMD_SIDEBAR, 0 }, - { "sincelist", CMD_SINCELIST, 0 }, - { "skipline", CMD_SKIPLINE, 0 }, - { "skipto", CMD_SKIPTO, 0 }, - { "skipuntil", CMD_SKIPUNTIL, 0 }, - { "snippet", CMD_SNIPPET, 0 }, - { "span", CMD_SPAN, 0 }, - { "sub", CMD_SUB, 0 }, - { "sup", CMD_SUP, 0 }, - { "table", CMD_TABLE, 0 }, - { "tableofcontents", CMD_TABLEOFCONTENTS, 0 }, - { "target", CMD_TARGET, 0 }, - { "topicref", CMD_TOPICREF, 0 }, - { "tt", CMD_TT, 0 }, - { "uicontrol", CMD_UICONTROL, 0 }, - { "underline", CMD_UNDERLINE, 0 }, - { "unicode", CMD_UNICODE, 0 }, - { "value", CMD_VALUE, 0 }, - { "warning", CMD_WARNING, 0 }, - { "qml", CMD_QML, 0 }, - { "endqml", CMD_ENDQML, 0 }, - { "cpp", CMD_CPP, 0 }, - { "endcpp", CMD_ENDCPP, 0 }, - { "qmltext", CMD_QMLTEXT, 0 }, - { "endqmltext", CMD_ENDQMLTEXT, 0 }, - { "cpptext", CMD_CPPTEXT, 0 }, - { "endcpptext", CMD_ENDCPPTEXT, 0 }, - { "js", CMD_JS, 0 }, - { "endjs", CMD_ENDJS, 0 }, - { 0, 0, 0 } -}; - -typedef QHash<QString, int> QHash_QString_int; -typedef QHash<QString, Macro> QHash_QString_Macro; - -Q_GLOBAL_STATIC(QStringMap, aliasMap) -Q_GLOBAL_STATIC(QHash_QString_int, cmdHash) -Q_GLOBAL_STATIC(QHash_QString_Macro, macroHash) - -class DocPrivateExtra -{ -public: - Doc::Sections granularity_; - Doc::Sections section_; // ### - QList<Atom*> tableOfContents_; - QVector<int> tableOfContentsLevels_; - QList<Atom*> keywords_; - QList<Atom*> targets_; - QStringMultiMap metaMap_; - - DocPrivateExtra() - : granularity_(Doc::Part) - , section_(Doc::NoSection) - { } -}; - -struct Shared // ### get rid of -{ - Shared() - : count(1) { } - void ref() { ++count; } - bool deref() { return (--count == 0); } - - int count; -}; - -static QString cleanLink(const QString &link) -{ - int colonPos = link.indexOf(':'); - if ((colonPos == -1) || - (!link.startsWith("file:") && !link.startsWith("mailto:"))) - return link; - return link.mid(colonPos + 1).simplified(); -} - -typedef QMap<QString, ArgList> CommandMap; - -class DocPrivate : public Shared -{ -public: - DocPrivate(const Location& start = Location::null, - const Location& end = Location::null, - const QString& source = QString()); - ~DocPrivate(); - - void addAlso(const Text& also); - void constructExtra(); - bool isEnumDocSimplifiable() const; - - // ### move some of this in DocPrivateExtra - Location start_loc; - Location end_loc; - QString src; - Text text; - QSet<QString> params; - QList<Text> alsoList; - QStringList enumItemList; - QStringList omitEnumItemList; - QSet<QString> metacommandsUsed; - CommandMap metaCommandMap; - bool hasLegalese : 1; - bool hasSectioningUnits : 1; - DocPrivateExtra *extra; - TopicList topics_; - DitaRefList ditamap_; -}; - -DocPrivate::DocPrivate(const Location& start, - const Location& end, - const QString& source) - : start_loc(start), - end_loc(end), - src(source), - hasLegalese(false), - hasSectioningUnits(false), - extra(0) -{ - // nothing. -} - -/*! - If the doc is a ditamap, the destructor deletes each element - in the ditamap structure. These were allocated as needed. - */ -DocPrivate::~DocPrivate() -{ - delete extra; - foreach (DitaRef* t, ditamap_) { - delete t; - } -} - -void DocPrivate::addAlso(const Text& also) -{ - alsoList.append(also); -} - -void DocPrivate::constructExtra() -{ - if (extra == 0) - extra = new DocPrivateExtra; -} - -bool DocPrivate::isEnumDocSimplifiable() const -{ - bool justMetColon = false; - int numValueTables = 0; - - const Atom *atom = text.firstAtom(); - while (atom) { - if (atom->type() == Atom::AutoLink || atom->type() == Atom::String) { - justMetColon = atom->string().endsWith(QLatin1Char(':')); - } - else if ((atom->type() == Atom::ListLeft) && - (atom->string() == ATOM_LIST_VALUE)) { - if (justMetColon || numValueTables > 0) - return false; - ++numValueTables; - } - atom = atom->next(); - } - return true; -} - -class DocParser -{ - Q_DECLARE_TR_FUNCTIONS(QDoc::DocParser) - -public: - void parse(const QString &source, - DocPrivate *docPrivate, - const QSet<QString> &metaCommandSet, - const QSet<QString>& possibleTopics); - - static int endCmdFor(int cmd); - static QString cmdName(int cmd); - static QString endCmdName(int cmd); - static QString untabifyEtc(const QString& str); - static int indentLevel(const QString& str); - static QString unindent(int level, const QString& str); - static QString slashed(const QString& str); - - static int tabSize; - static QStringList exampleFiles; - static QStringList exampleDirs; - static QStringList sourceFiles; - static QStringList sourceDirs; - static bool quoting; - -private: - Location& location(); - QString detailsUnknownCommand(const QSet<QString>& metaCommandSet, - const QString& str); - void insertTarget(const QString& target, bool keyword); - void include(const QString& fileName, const QString& identifier); - void startFormat(const QString& format, int cmd); - bool openCommand(int cmd); - bool closeCommand(int endCmd); - void startSection(Doc::Sections unit, int cmd); - void endSection(int unit, int endCmd); - void parseAlso(); - void append(const QString &string); - void append(Atom::AtomType type, const QString& string = QString()); - void append(Atom::AtomType type, const QString& p1, const QString& p2); - void append(const QString& p1, const QString& p2); - void appendChar(QChar ch); - void appendWord(const QString &word); - void appendToCode(const QString &code); - void appendToCode(const QString &code, Atom::AtomType defaultType); - void startNewPara(); - void enterPara(Atom::AtomType leftType = Atom::ParaLeft, - Atom::AtomType rightType = Atom::ParaRight, - const QString& string = QString()); - void leavePara(); - void leaveValue(); - void leaveValueList(); - void leaveTableRow(); - CodeMarker *quoteFromFile(); - void expandMacro(const QString& name, const QString& def, int numParams); - QString expandMacroToString(const QString &name, const QString &def, int numParams); - Doc::Sections getSectioningUnit(); - QString getArgument(bool verbatim = false); - QString getBracedArgument(bool verbatim); - QString getBracketedArgument(); - QString getOptionalArgument(); - QString getRestOfLine(); - QString getMetaCommandArgument(const QString &cmdStr); - QString getUntilEnd(int cmd); - QString getCode(int cmd, CodeMarker *marker); - QString getUnmarkedCode(int cmd); - - bool isBlankLine(); - bool isLeftBraceAhead(); - bool isLeftBracketAhead(); - void skipSpacesOnLine(); - void skipSpacesOrOneEndl(); - void skipAllSpaces(); - void skipToNextPreprocessorCommand(); - - QStack<int> openedInputs; - - QString in; - int pos; - int len; - Location cachedLoc; - int cachedPos; - - DocPrivate* priv; - enum ParagraphState { - OutsideParagraph, - InSingleLineParagraph, - InMultiLineParagraph - }; - ParagraphState paraState; - bool inTableHeader; - bool inTableRow; - bool inTableItem; - bool indexStartedPara; // ### rename - Atom::AtomType pendingParaLeftType; - Atom::AtomType pendingParaRightType; - QString pendingParaString; - - int braceDepth; - int minIndent; - Doc::Sections currentSection; - QMap<QString, Location> targetMap_; - QMap<int, QString> pendingFormats; - QStack<int> openedCommands; - QStack<OpenedList> openedLists; - Quoter quoter; - QStack<DitaRef*> ditarefs_; -}; - -int DocParser::tabSize; -QStringList DocParser::exampleFiles; -QStringList DocParser::exampleDirs; -QStringList DocParser::sourceFiles; -QStringList DocParser::sourceDirs; -bool DocParser::quoting; - -/*! - Parse the \a source string to build a Text data structure - in \a docPrivate. The Text data structure is a linked list - of Atoms. - - \a metaCommandSet is the set of metacommands that may be - found in \a source. These metacommands are not markup text - commands. They are topic commands and related metacommands. - */ -void DocParser::parse(const QString& source, - DocPrivate *docPrivate, - const QSet<QString>& metaCommandSet, - const QSet<QString>& possibleTopics) -{ - in = source; - pos = 0; - len = in.length(); - cachedLoc = docPrivate->start_loc; - cachedPos = 0; - priv = docPrivate; - priv->text << Atom::Nop; - priv->topics_.clear(); - - paraState = OutsideParagraph; - inTableHeader = false; - inTableRow = false; - inTableItem = false; - indexStartedPara = false; - pendingParaLeftType = Atom::Nop; - pendingParaRightType = Atom::Nop; - - braceDepth = 0; - minIndent = INT_MAX; - currentSection = Doc::NoSection; - openedCommands.push(CMD_OMIT); - quoter.reset(); - - CodeMarker *marker = 0; - Atom *currentLinkAtom = 0; - QString p1, p2; - QStack<bool> preprocessorSkipping; - int numPreprocessorSkipping = 0; - - while (pos < len) { - QChar ch = in.at(pos); - - switch (ch.unicode()) { - case '\\': - { - QString cmdStr; - pos++; - while (pos < len) { - ch = in.at(pos); - if (ch.isLetterOrNumber()) { - cmdStr += ch; - pos++; - } - else { - break; - } - } - if (cmdStr.isEmpty()) { - if (pos < len) { - enterPara(); - if (in.at(pos).isSpace()) { - skipAllSpaces(); - appendChar(QLatin1Char(' ')); - } - else { - appendChar(in.at(pos++)); - } - } - } - else { - int cmd = cmdHash()->value(cmdStr,NOT_A_CMD); - switch (cmd) { - case CMD_A: - enterPara(); - p1 = getArgument(); - append(Atom::FormattingLeft,ATOM_FORMATTING_PARAMETER); - append(Atom::String, p1); - append(Atom::FormattingRight,ATOM_FORMATTING_PARAMETER); - priv->params.insert(p1); - break; - case CMD_BADCODE: - leavePara(); - append(Atom::CodeBad,getCode(CMD_BADCODE, marker)); - break; - case CMD_BR: - enterPara(); - append(Atom::BR); - break; - case CMD_BOLD: - location().warning(tr("'\\bold' is deprecated. Use '\\b'")); - case CMD_B: - startFormat(ATOM_FORMATTING_BOLD, cmd); - break; - case CMD_BRIEF: - leavePara(); - enterPara(Atom::BriefLeft, Atom::BriefRight); - break; - case CMD_C: - enterPara(); - p1 = untabifyEtc(getArgument(true)); - marker = CodeMarker::markerForCode(p1); - append(Atom::C, marker->markedUpCode(p1, 0, location())); - break; - case CMD_CAPTION: - leavePara(); - enterPara(Atom::CaptionLeft, Atom::CaptionRight); - break; - case CMD_CHAPTER: - startSection(Doc::Chapter, cmd); - break; - case CMD_CODE: - leavePara(); - append(Atom::Code, getCode(CMD_CODE, 0)); - break; - case CMD_QML: - leavePara(); - append(Atom::Qml, getCode(CMD_QML, CodeMarker::markerForLanguage(QLatin1String("QML")))); - break; - case CMD_QMLTEXT: - append(Atom::QmlText); - break; - case CMD_JS: - leavePara(); - append(Atom::JavaScript, getCode(CMD_JS, CodeMarker::markerForLanguage(QLatin1String("JavaScript")))); - break; - case CMD_DIV: - leavePara(); - p1 = getArgument(true); - append(Atom::DivLeft, p1); - openedCommands.push(cmd); - break; - case CMD_ENDDIV: - leavePara(); - append(Atom::DivRight); - closeCommand(cmd); - break; - case CMD_CODELINE: - { - if (!quoting) { - if (priv->text.lastAtom()->type() == Atom::Code - && priv->text.lastAtom()->string().endsWith("\n\n")) - priv->text.lastAtom()->chopString(); - appendToCode("\n"); - } - else { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, " "); - } - } - break; - case CMD_DOTS: - { - if (!quoting) { - if (priv->text.lastAtom()->type() == Atom::Code - && priv->text.lastAtom()->string().endsWith("\n\n")) - priv->text.lastAtom()->chopString(); - - QString arg = getOptionalArgument(); - int indent = 4; - if (!arg.isEmpty()) - indent = arg.toInt(); - for (int i = 0; i < indent; ++i) - appendToCode(" "); - appendToCode("...\n"); - } - else { - append(Atom::CodeQuoteCommand, cmdStr); - QString arg = getOptionalArgument(); - if (arg.isEmpty()) - arg = "4"; - append(Atom::CodeQuoteArgument, arg); - } - } - break; - case CMD_ELSE: - if (preprocessorSkipping.size() > 0) { - if (preprocessorSkipping.top()) { - --numPreprocessorSkipping; - } - else { - ++numPreprocessorSkipping; - } - preprocessorSkipping.top() = !preprocessorSkipping.top(); - (void)getRestOfLine(); // ### should ensure that it's empty - if (numPreprocessorSkipping) - skipToNextPreprocessorCommand(); - } - else { - location().warning(tr("Unexpected '\\%1'").arg(cmdName(CMD_ELSE))); - } - break; - case CMD_ENDCHAPTER: - endSection(Doc::Chapter, cmd); - break; - case CMD_ENDCODE: - closeCommand(cmd); - break; - case CMD_ENDQML: - closeCommand(cmd); - break; - case CMD_ENDQMLTEXT: - append(Atom::EndQmlText); - break; - case CMD_ENDJS: - closeCommand(cmd); - break; - case CMD_ENDFOOTNOTE: - if (closeCommand(cmd)) { - leavePara(); - append(Atom::FootnoteRight); - paraState = InMultiLineParagraph; // ### - } - break; - case CMD_ENDIF: - if (preprocessorSkipping.count() > 0) { - if (preprocessorSkipping.pop()) - --numPreprocessorSkipping; - (void)getRestOfLine(); // ### should ensure that it's empty - if (numPreprocessorSkipping) - skipToNextPreprocessorCommand(); - } - else { - location().warning(tr("Unexpected '\\%1'").arg(cmdName(CMD_ENDIF))); - } - break; - case CMD_ENDLEGALESE: - if (closeCommand(cmd)) { - leavePara(); - append(Atom::LegaleseRight); - } - break; - case CMD_ENDLINK: - if (closeCommand(cmd)) { - if (priv->text.lastAtom()->type() == Atom::String - && priv->text.lastAtom()->string().endsWith(QLatin1Char(' '))) - priv->text.lastAtom()->chopString(); - append(Atom::FormattingRight, ATOM_FORMATTING_LINK); - } - break; - case CMD_ENDLIST: - if (closeCommand(cmd)) { - leavePara(); - if (openedLists.top().isStarted()) { - append(Atom::ListItemRight, - openedLists.top().styleString()); - append(Atom::ListRight, - openedLists.top().styleString()); - } - openedLists.pop(); - } - break; - case CMD_ENDMAPREF: - case CMD_ENDTOPICREF: - if (closeCommand(cmd)) { - ditarefs_.pop(); // zzz - } - break; - case CMD_ENDOMIT: - closeCommand(cmd); - break; - case CMD_ENDPART: - endSection(Doc::Part, cmd); - break; - case CMD_ENDQUOTATION: - if (closeCommand(cmd)) { - leavePara(); - append(Atom::QuotationRight); - } - break; - case CMD_ENDRAW: - location().warning(tr("Unexpected '\\%1'").arg(cmdName(CMD_ENDRAW))); - break; - case CMD_ENDSECTION1: - endSection(Doc::Section1, cmd); - break; - case CMD_ENDSECTION2: - endSection(Doc::Section2, cmd); - break; - case CMD_ENDSECTION3: - endSection(Doc::Section3, cmd); - break; - case CMD_ENDSECTION4: - endSection(Doc::Section4, cmd); - break; - case CMD_ENDSIDEBAR: - if (closeCommand(cmd)) { - leavePara(); - append(Atom::SidebarRight); - } - break; - case CMD_ENDTABLE: - if (closeCommand(cmd)) { - leaveTableRow(); - append(Atom::TableRight); - } - break; - case CMD_FOOTNOTE: - if (openCommand(cmd)) { - enterPara(); - append(Atom::FootnoteLeft); - paraState = OutsideParagraph; // ### - } - break; - case CMD_ANNOTATEDLIST: - append(Atom::AnnotatedList, getArgument()); - break; - case CMD_SINCELIST: - append(Atom::SinceList, getRestOfLine().simplified()); - break; - case CMD_GENERATELIST: - { - QString arg1 = getArgument(); - QString arg2 = getOptionalArgument(); - if (!arg2.isEmpty()) - arg1 += " " + arg2; - append(Atom::GeneratedList, arg1); - } - break; - case CMD_GRANULARITY: - priv->constructExtra(); - priv->extra->granularity_ = getSectioningUnit(); - break; - case CMD_HEADER: - if (openedCommands.top() == CMD_TABLE) { - leaveTableRow(); - append(Atom::TableHeaderLeft); - inTableHeader = true; - } - else { - if (openedCommands.contains(CMD_TABLE)) { - location().warning(tr("Cannot use '\\%1' within '\\%2'") - .arg(cmdName(CMD_HEADER)) - .arg(cmdName(openedCommands.top()))); - } - else { - location().warning(tr("Cannot use '\\%1' outside of '\\%2'") - .arg(cmdName(CMD_HEADER)) - .arg(cmdName(CMD_TABLE))); - } - } - break; - case CMD_I: - location().warning(tr("'\\i' is deprecated. Use '\\e' for italic or '\\li' for list item")); - case CMD_E: - startFormat(ATOM_FORMATTING_ITALIC, cmd); - break; - case CMD_HR: - leavePara(); - append(Atom::HR); - break; - case CMD_IF: - preprocessorSkipping.push(!Tokenizer::isTrue(getRestOfLine())); - if (preprocessorSkipping.top()) - ++numPreprocessorSkipping; - if (numPreprocessorSkipping) - skipToNextPreprocessorCommand(); - break; - case CMD_IMAGE: - leaveValueList(); - append(Atom::Image, getArgument()); - append(Atom::ImageText, getRestOfLine()); - break; - case CMD_IMPORTANT: - leavePara(); - enterPara(Atom::ImportantLeft, Atom::ImportantRight); - break; - case CMD_INCLUDE: - case CMD_INPUT: - { - QString fileName = getArgument(); - QString identifier = getRestOfLine(); - include(fileName, identifier); - } - break; - case CMD_INLINEIMAGE: - enterPara(); - append(Atom::InlineImage, getArgument()); - append(Atom::ImageText, getRestOfLine()); - append(Atom::String, " "); - break; - case CMD_INDEX: - if (paraState == OutsideParagraph) { - enterPara(); - indexStartedPara = true; - } - else { - const Atom *last = priv->text.lastAtom(); - if (indexStartedPara && - (last->type() != Atom::FormattingRight || - last->string() != ATOM_FORMATTING_INDEX)) - indexStartedPara = false; - } - startFormat(ATOM_FORMATTING_INDEX, cmd); - break; - case CMD_KEYWORD: - insertTarget(getRestOfLine(),true); - break; - case CMD_L: - enterPara(); - if (isLeftBracketAhead()) { - p2 = getBracketedArgument(); - } - if (isLeftBraceAhead()) { - p1 = getArgument(); - append(p1, p2); - if (!p2.isEmpty() && !(priv->text.lastAtom()->error().isEmpty())) { - location().warning(tr("Check parameter in '[ ]' of '\\l' command: '%1', " - "possible misspelling, or unrecognized module name") - .arg(priv->text.lastAtom()->error())); - } - if (isLeftBraceAhead()) { - currentLinkAtom = priv->text.lastAtom(); - startFormat(ATOM_FORMATTING_LINK, cmd); - } - else { - append(Atom::FormattingLeft, ATOM_FORMATTING_LINK); - append(Atom::String, cleanLink(p1)); - append(Atom::FormattingRight, ATOM_FORMATTING_LINK); - } - } - else { - p1 = getArgument(); - append(p1, p2); - if (!p2.isEmpty() && !(priv->text.lastAtom()->error().isEmpty())) { - location().warning(tr("Check parameter in '[ ]' of '\\l' command: '%1', " - "possible misspelling, or unrecognized module name") - .arg(priv->text.lastAtom()->error())); - } - append(Atom::FormattingLeft, ATOM_FORMATTING_LINK); - append(Atom::String, cleanLink(p1)); - append(Atom::FormattingRight, ATOM_FORMATTING_LINK); - } - p2.clear(); - break; - case CMD_LEGALESE: - leavePara(); - if (openCommand(cmd)) - append(Atom::LegaleseLeft); - docPrivate->hasLegalese = true; - break; - case CMD_LINK: - if (openCommand(cmd)) { - enterPara(); - p1 = getArgument(); - append(p1); - append(Atom::FormattingLeft, ATOM_FORMATTING_LINK); - skipSpacesOrOneEndl(); - } - break; - case CMD_LIST: - if (openCommand(cmd)) { - leavePara(); - openedLists.push(OpenedList(location(), - getOptionalArgument())); - } - break; - case CMD_TOPICREF: - case CMD_MAPREF: - if (openCommand(cmd)) { - DitaRef* t = 0; - if (cmd == CMD_MAPREF) - t = new MapRef(); - else - t = new TopicRef(); - t->setNavtitle(getArgument(true)); - if (cmd == CMD_MAPREF) - t->setHref(getArgument()); - else - t->setHref(getOptionalArgument()); - if (ditarefs_.isEmpty()) - priv->ditamap_.append(t); - else - ditarefs_.top()->appendSubref(t); - ditarefs_.push(t); - } - break; - case CMD_META: - priv->constructExtra(); - p1 = getArgument(); - priv->extra->metaMap_.insert(p1, getArgument()); - break; - case CMD_NEWCODE: - location().warning(tr("Unexpected '\\%1'").arg(cmdName(CMD_NEWCODE))); - break; - case CMD_NOTE: - leavePara(); - enterPara(Atom::NoteLeft, Atom::NoteRight); - break; - case CMD_O: - location().warning(tr("'\\o' is deprecated. Use '\\li'")); - case CMD_LI: - leavePara(); - if (openedCommands.top() == CMD_LIST) { - if (openedLists.top().isStarted()) { - append(Atom::ListItemRight, - openedLists.top().styleString()); - } - else { - append(Atom::ListLeft, - openedLists.top().styleString()); - } - openedLists.top().next(); - append(Atom::ListItemNumber, - openedLists.top().numberString()); - append(Atom::ListItemLeft, - openedLists.top().styleString()); - enterPara(); - } - else if (openedCommands.top() == CMD_TABLE) { - p1 = "1,1"; - p2.clear(); - if (isLeftBraceAhead()) { - p1 = getArgument(); - if (isLeftBraceAhead()) { - p2 = getArgument(); - } - } - - if (!inTableHeader && !inTableRow) { - location().warning(tr("Missing '\\%1' or '\\%2' before '\\%3'") - .arg(cmdName(CMD_HEADER)) - .arg(cmdName(CMD_ROW)) - .arg(cmdName(CMD_LI))); - append(Atom::TableRowLeft); - inTableRow = true; - } - else if (inTableItem) { - append(Atom::TableItemRight); - inTableItem = false; - } - - append(Atom::TableItemLeft, p1, p2); - inTableItem = true; - } - else { - location().warning(tr("Command '\\%1' outside of '\\%2' and '\\%3'") - .arg(cmdName(cmd)) - .arg(cmdName(CMD_LIST)) - .arg(cmdName(CMD_TABLE))); - } - break; - case CMD_OLDCODE: - leavePara(); - append(Atom::CodeOld, getCode(CMD_OLDCODE, marker)); - append(Atom::CodeNew, getCode(CMD_NEWCODE, marker)); - break; - case CMD_OMIT: - getUntilEnd(cmd); - break; - case CMD_OMITVALUE: - p1 = getArgument(); - if (!priv->enumItemList.contains(p1)) - priv->enumItemList.append(p1); - if (!priv->omitEnumItemList.contains(p1)) - priv->omitEnumItemList.append(p1); - break; - case CMD_PART: - startSection(Doc::Part, cmd); - break; - case CMD_PRINTLINE: - leavePara(); - if (!quoting) - appendToCode(quoter.quoteLine(location(), cmdStr, - getRestOfLine())); - else { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, getRestOfLine()); - } - break; - case CMD_PRINTTO: - leavePara(); - if (!quoting) - appendToCode(quoter.quoteTo(location(), cmdStr, - getRestOfLine())); - else { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, getRestOfLine()); - } - break; - case CMD_PRINTUNTIL: - leavePara(); - if (!quoting) - appendToCode(quoter.quoteUntil(location(), cmdStr, - getRestOfLine())); - else { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, getRestOfLine()); - } - break; - case CMD_QUOTATION: - if (openCommand(cmd)) { - leavePara(); - append(Atom::QuotationLeft); - } - break; - case CMD_QUOTEFILE: - { - leavePara(); - QString fileName = getArgument(); - Doc::quoteFromFile(location(), quoter, fileName); - if (!quoting) { - append(Atom::Code, - quoter.quoteTo(location(), cmdStr, QString())); - quoter.reset(); - } - else { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, fileName); - } - break; - } - case CMD_QUOTEFROMFILE: - leavePara(); - if (!quoting) - quoteFromFile(); - else { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, getArgument()); - } - break; - case CMD_QUOTEFUNCTION: - leavePara(); - marker = quoteFromFile(); - p1 = getRestOfLine(); - if (!quoting) { - quoter.quoteTo(location(), cmdStr, - slashed(marker->functionBeginRegExp(p1))); - append(Atom::Code, - quoter.quoteUntil(location(), cmdStr, - slashed(marker->functionEndRegExp(p1)))); - quoter.reset(); - } - else { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, slashed(marker->functionEndRegExp(p1))); - } - break; - case CMD_RAW: - leavePara(); - p1 = getRestOfLine(); - if (p1.isEmpty()) - location().warning(tr("Missing format name after '\\%1'") - .arg(cmdName(CMD_RAW))); - append(Atom::FormatIf, p1); - append(Atom::RawString, untabifyEtc(getUntilEnd(cmd))); - append(Atom::FormatElse); - append(Atom::FormatEndif); - break; - case CMD_ROW: - if (openedCommands.top() == CMD_TABLE) { - p1.clear(); - if (isLeftBraceAhead()) - p1 = getArgument(true); - leaveTableRow(); - append(Atom::TableRowLeft,p1); - inTableRow = true; - } - else { - if (openedCommands.contains(CMD_TABLE)) { - location().warning(tr("Cannot use '\\%1' within '\\%2'") - .arg(cmdName(CMD_ROW)) - .arg(cmdName(openedCommands.top()))); - } - else { - location().warning(tr("Cannot use '\\%1' outside of '\\%2'") - .arg(cmdName(CMD_ROW)) - .arg(cmdName(CMD_TABLE))); - } - } - break; - case CMD_SA: - parseAlso(); - break; - case CMD_SECTION1: - startSection(Doc::Section1, cmd); - break; - case CMD_SECTION2: - startSection(Doc::Section2, cmd); - break; - case CMD_SECTION3: - startSection(Doc::Section3, cmd); - break; - case CMD_SECTION4: - startSection(Doc::Section4, cmd); - break; - case CMD_SIDEBAR: - if (openCommand(cmd)) { - leavePara(); - append(Atom::SidebarLeft); - } - break; - case CMD_SKIPLINE: - leavePara(); - if (!quoting) - quoter.quoteLine(location(), - cmdStr, - getRestOfLine()); - else { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, getRestOfLine()); - } - break; - case CMD_SKIPTO: - leavePara(); - if (!quoting) - quoter.quoteTo(location(), - cmdStr, - getRestOfLine()); - else { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, getRestOfLine()); - } - break; - case CMD_SKIPUNTIL: - leavePara(); - if (!quoting) - quoter.quoteUntil(location(), - cmdStr, - getRestOfLine()); - else { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, getRestOfLine()); - } - break; - case CMD_SPAN: - p1 = ATOM_FORMATTING_SPAN + getArgument(true); - startFormat(p1, cmd); - break; - case CMD_SNIPPET: - leavePara(); - { - QString snippet = getArgument(); - QString identifier = getRestOfLine(); - if (quoting) { - append(Atom::SnippetCommand, cmdStr); - append(Atom::SnippetLocation, snippet); - append(Atom::SnippetIdentifier, identifier); - } - else { - marker = Doc::quoteFromFile(location(),quoter,snippet); - appendToCode(quoter.quoteSnippet(location(), identifier), marker->atomType()); - } - } - break; - case CMD_SUB: - startFormat(ATOM_FORMATTING_SUBSCRIPT, cmd); - break; - case CMD_SUP: - startFormat(ATOM_FORMATTING_SUPERSCRIPT, cmd); - break; - case CMD_TABLE: - //p1 = getRestOfLine(); - p1 = getOptionalArgument(); - p2 = getOptionalArgument(); - if (openCommand(cmd)) { - leavePara(); - append(Atom::TableLeft, p1, p2); - inTableHeader = false; - inTableRow = false; - inTableItem = false; - } - break; - case CMD_TABLEOFCONTENTS: - p1 = "1"; - if (isLeftBraceAhead()) - p1 = getArgument(); - p1 += QLatin1Char(','); - p1 += QString::number((int)getSectioningUnit()); - append(Atom::TableOfContents, p1); - break; - case CMD_TARGET: - insertTarget(getRestOfLine(),false); - break; - case CMD_TT: - startFormat(ATOM_FORMATTING_TELETYPE, cmd); - break; - case CMD_UICONTROL: - startFormat(ATOM_FORMATTING_UICONTROL, cmd); - break; - case CMD_UNDERLINE: - startFormat(ATOM_FORMATTING_UNDERLINE, cmd); - break; - case CMD_UNICODE: - enterPara(); - p1 = getArgument(); - { - bool ok; - uint unicodeChar = p1.toUInt(&ok, 0); - if (!ok || - (unicodeChar == 0x0000) || - (unicodeChar > 0xFFFE)) { - location().warning(tr("Invalid Unicode character '%1' specified " - "with '%2'") - .arg(p1, cmdName(CMD_UNICODE))); - } - else { - append(Atom::String, QChar(unicodeChar)); - } - } - break; - case CMD_VALUE: - leaveValue(); - if (openedLists.top().style() == OpenedList::Value) { - p1 = getArgument(); - if (!priv->enumItemList.contains(p1)) - priv->enumItemList.append(p1); - - openedLists.top().next(); - append(Atom::ListTagLeft, ATOM_LIST_VALUE); - append(Atom::String, p1); - append(Atom::ListTagRight, ATOM_LIST_VALUE); - append(Atom::ListItemLeft, ATOM_LIST_VALUE); - - skipSpacesOrOneEndl(); - if (isBlankLine()) - append(Atom::Nop); - } - else { - // ### problems - } - break; - case CMD_WARNING: - leavePara(); - enterPara(); - append(Atom::FormattingLeft, ATOM_FORMATTING_BOLD); - append(Atom::String, "Warning:"); - append(Atom::FormattingRight, ATOM_FORMATTING_BOLD); - append(Atom::String, " "); - break; - case CMD_OVERLOAD: - priv->metacommandsUsed.insert(cmdStr); - p1.clear(); - if (!isBlankLine()) - p1 = getRestOfLine(); - if (!p1.isEmpty()) { - append(Atom::ParaLeft); - append(Atom::String, "This function overloads "); - append(Atom::AutoLink,p1); - append(Atom::String, "."); - append(Atom::ParaRight); - } - else { - append(Atom::ParaLeft); - append(Atom::String,"This is an overloaded function."); - append(Atom::ParaRight); - p1 = getMetaCommandArgument(cmdStr); - } - priv->metaCommandMap[cmdStr].append(ArgLocPair(p1,location())); - break; - case NOT_A_CMD: - if (metaCommandSet.contains(cmdStr)) { - priv->metacommandsUsed.insert(cmdStr); - QString arg = getMetaCommandArgument(cmdStr); - priv->metaCommandMap[cmdStr].append(ArgLocPair(arg,location())); - if (possibleTopics.contains(cmdStr)) { - priv->topics_.append(Topic(cmdStr,arg)); - } - } - else if (macroHash()->contains(cmdStr)) { - const Macro ¯o = macroHash()->value(cmdStr); - int numPendingFi = 0; - QStringMap::ConstIterator d; - d = macro.otherDefs.constBegin(); - while (d != macro.otherDefs.constEnd()) { - append(Atom::FormatIf, d.key()); - expandMacro(cmdStr, *d, macro.numParams); - ++d; - - if (d == macro.otherDefs.constEnd()) { - append(Atom::FormatEndif); - } - else { - append(Atom::FormatElse); - numPendingFi++; - } - } - while (numPendingFi-- > 0) - append(Atom::FormatEndif); - - if (!macro.defaultDef.isEmpty()) { - if (!macro.otherDefs.isEmpty()) { - macro.defaultDefLocation.warning( - tr("Macro cannot have both " - "format-specific and qdoc- " - "syntax definitions")); - } - else { - location().push(macro.defaultDefLocation.filePath()); - in.insert(pos, expandMacroToString(cmdStr, macro.defaultDef, macro.numParams)); - len = in.length(); - openedInputs.push(pos + macro.defaultDef.length()); - } - } - } - else { - location().warning( - tr("Unknown command '\\%1'").arg(cmdStr), - detailsUnknownCommand(metaCommandSet,cmdStr)); - enterPara(); - append(Atom::UnknownCommand, cmdStr); - } - } - } - } - break; - case '{': - enterPara(); - appendChar('{'); - braceDepth++; - pos++; - break; - case '}': - { - braceDepth--; - pos++; - - QMap<int, QString>::Iterator f = pendingFormats.find(braceDepth); - if (f == pendingFormats.end()) { - enterPara(); - appendChar('}'); - } - else { - append(Atom::FormattingRight, *f); - if (*f == ATOM_FORMATTING_INDEX) { - if (indexStartedPara) - skipAllSpaces(); - } - else if (*f == ATOM_FORMATTING_LINK) { - // hack for C++ to support links like - // \l{QString::}{count()} - if (currentLinkAtom && - currentLinkAtom->string().endsWith("::")) { - QString suffix = Text::subText(currentLinkAtom, - priv->text.lastAtom()).toString(); - currentLinkAtom->appendString(suffix); - } - currentLinkAtom = 0; - } - pendingFormats.erase(f); - } - } - break; - default: - { - bool newWord; - switch (priv->text.lastAtom()->type()) { - case Atom::ParaLeft: - newWord = true; - break; - default: - newWord = false; - } - - if (paraState == OutsideParagraph) { - if (ch.isSpace()) { - ++pos; - newWord = false; - } - else { - enterPara(); - newWord = true; - } - } - else { - if (ch.isSpace()) { - ++pos; - if ((ch == '\n') && - (paraState == InSingleLineParagraph || - isBlankLine())) { - leavePara(); - newWord = false; - } - else { - appendChar(' '); - newWord = true; - } - } - else { - newWord = true; - } - } - - if (newWord) { - int startPos = pos; - int numInternalUppercase = 0; - int numLowercase = 0; - int numStrangeSymbols = 0; - - while (pos < len) { - unsigned char latin1Ch = in.at(pos).toLatin1(); - if (islower(latin1Ch)) { - ++numLowercase; - ++pos; - } - else if (isupper(latin1Ch)) { - if (pos > startPos) - ++numInternalUppercase; - ++pos; - } - else if (isdigit(latin1Ch)) { - if (pos > startPos) { - ++pos; - } - else { - break; - } - } - else if (latin1Ch == '_' || latin1Ch == '@') { - ++numStrangeSymbols; - ++pos; - } - else if (latin1Ch == ':' && pos < len - 1 - && in.at(pos + 1) == QLatin1Char(':')) { - ++numStrangeSymbols; - pos += 2; - } - else if (latin1Ch == '(') { - if (pos > startPos) { - if (pos < len - 1 && - in.at(pos + 1) == QLatin1Char(')')) { - ++numStrangeSymbols; - pos += 2; - break; - } - else { - // ### handle functions with signatures - // and function calls - break; - } - } - else { - break; - } - } - else { - break; - } - } - - if (pos == startPos) { - if (!ch.isSpace()) { - appendChar(ch); - ++pos; - } - } - else { - QString word = in.mid(startPos, pos - startPos); - // is word a C++ symbol or an English word? - if ((numInternalUppercase >= 1 && numLowercase >= 2) - || numStrangeSymbols > 0) { - if (word.startsWith(QString("__"))) - appendWord(word); - else - append(Atom::AutoLink, word); - } - else - appendWord(word); - } - } - } - } - } - leaveValueList(); - - // for compatibility - if (openedCommands.top() == CMD_LEGALESE) { - append(Atom::LegaleseRight); - openedCommands.pop(); - } - - if (openedCommands.top() != CMD_OMIT) { - location().warning(tr("Missing '\\%1'").arg(endCmdName(openedCommands.top()))); - } - else if (preprocessorSkipping.count() > 0) { - location().warning(tr("Missing '\\%1'").arg(cmdName(CMD_ENDIF))); - } - - if (currentSection > Doc::NoSection) { - append(Atom::SectionRight, QString::number(currentSection)); - currentSection = Doc::NoSection; - } - - if (priv->extra && priv->extra->granularity_ < priv->extra->section_) - priv->extra->granularity_ = priv->extra->section_; - priv->text.stripFirstAtom(); -} - -/*! - Returns the current location. - */ -Location &DocParser::location() -{ - while (!openedInputs.isEmpty() && openedInputs.top() <= pos) { - cachedLoc.pop(); - cachedPos = openedInputs.pop(); - } - while (cachedPos < pos) - cachedLoc.advance(in.at(cachedPos++)); - return cachedLoc; -} - -QString DocParser::detailsUnknownCommand(const QSet<QString> &metaCommandSet, - const QString &str) -{ - QSet<QString> commandSet = metaCommandSet; - int i = 0; - while (cmds[i].english != 0) { - commandSet.insert(*cmds[i].alias); - i++; - } - - if (aliasMap()->contains(str)) - return tr("The command '\\%1' was renamed '\\%2' by the configuration" - " file. Use the new name.") - .arg(str).arg((*aliasMap())[str]); - - QString best = nearestName(str, commandSet); - if (best.isEmpty()) - return QString(); - return tr("Maybe you meant '\\%1'?").arg(best); -} - -void DocParser::insertTarget(const QString &target, bool keyword) -{ - if (targetMap_.contains(target)) { - location().warning(tr("Duplicate target name '%1'").arg(target)); - targetMap_[target].warning(tr("(The previous occurrence is here)")); - } - else { - targetMap_.insert(target, location()); - priv->constructExtra(); - if (keyword) { - append(Atom::Keyword, target); - priv->extra->keywords_.append(priv->text.lastAtom()); - } - else { - append(Atom::Target, target); - priv->extra->targets_.append(priv->text.lastAtom()); - } - } -} - -void DocParser::include(const QString& fileName, const QString& identifier) -{ - if (location().depth() > 16) - location().fatal(tr("Too many nested '\\%1's").arg(cmdName(CMD_INCLUDE))); - - QString userFriendlyFilePath; - QString filePath = Doc::config()->getIncludeFilePath(fileName); -#if 0 - QString filePath = Config::findFile(location(), - sourceFiles, - sourceDirs, - fileName, - userFriendlyFilePath); -#endif - if (filePath.isEmpty()) { - location().warning(tr("Cannot find qdoc include file '%1'").arg(fileName)); - } - else { - QFile inFile(filePath); - if (!inFile.open(QFile::ReadOnly)) { - location().warning(tr("Cannot open qdoc include file '%1'") - .arg(userFriendlyFilePath)); - } - else { - location().push(userFriendlyFilePath); - - QTextStream inStream(&inFile); - QString includedStuff = inStream.readAll(); - inFile.close(); - - if (identifier.isEmpty()) { - in.insert(pos, includedStuff); - len = in.length(); - openedInputs.push(pos + includedStuff.length()); - } - else { - QStringList lineBuffer = includedStuff.split(QLatin1Char('\n')); - int i = 0; - int startLine = -1; - while (i < lineBuffer.size()) { - if (lineBuffer[i].startsWith("//!")) { - if (lineBuffer[i].contains(identifier)) { - startLine = i+1; - break; - } - } - ++i; - } - if (startLine < 0) { - location().warning(tr("Cannot find '%1' in '%2'") - .arg(identifier) - .arg(userFriendlyFilePath)); - return; - - } - QString result; - i = startLine; - do { - if (lineBuffer[i].startsWith("//!")) { - if (i<lineBuffer.size()) { - if (lineBuffer[i].contains(identifier)) { - break; - } - } - } - else - result += lineBuffer[i] + QLatin1Char('\n'); - ++i; - } while (i < lineBuffer.size()); - if (result.isEmpty()) { - location().warning(tr("Empty qdoc snippet '%1' in '%2'") - .arg(identifier) - .arg(userFriendlyFilePath)); - } - else { - in.insert(pos, result); - len = in.length(); - openedInputs.push(pos + result.length()); - } - } - } - } -} - -void DocParser::startFormat(const QString& format, int cmd) -{ - enterPara(); - - QMap<int, QString>::ConstIterator f = pendingFormats.constBegin(); - while (f != pendingFormats.constEnd()) { - if (*f == format) { - location().warning(tr("Cannot nest '\\%1' commands") - .arg(cmdName(cmd))); - return; - } - ++f; - } - - append(Atom::FormattingLeft, format); - - if (isLeftBraceAhead()) { - skipSpacesOrOneEndl(); - pendingFormats.insert(braceDepth, format); - ++braceDepth; - ++pos; - } - else { - append(Atom::String, getArgument()); - append(Atom::FormattingRight, format); - if (format == ATOM_FORMATTING_INDEX && indexStartedPara) { - skipAllSpaces(); - indexStartedPara = false; - } - } -} - -bool DocParser::openCommand(int cmd) -{ - int outer = openedCommands.top(); - bool ok = true; - - if (cmd != CMD_LINK) { - if (outer == CMD_LIST) { - ok = (cmd == CMD_FOOTNOTE || cmd == CMD_LIST); - } - else if (outer == CMD_SIDEBAR) { - ok = (cmd == CMD_LIST || - cmd == CMD_QUOTATION || - cmd == CMD_SIDEBAR); - } - else if (outer == CMD_QUOTATION) { - ok = (cmd == CMD_LIST); - } - else if (outer == CMD_TABLE) { - ok = (cmd == CMD_LIST || - cmd == CMD_FOOTNOTE || - cmd == CMD_QUOTATION); - } - else if (outer == CMD_FOOTNOTE || outer == CMD_LINK) { - ok = false; - } - else if (outer == CMD_TOPICREF) - ok = (cmd == CMD_TOPICREF || cmd == CMD_MAPREF); - else if (outer == CMD_MAPREF) - ok = false; - } - - if (ok) { - openedCommands.push(cmd); - } - else { - location().warning(tr("Can't use '\\%1' in '\\%2'").arg(cmdName(cmd)).arg(cmdName(outer))); - } - return ok; -} - -bool DocParser::closeCommand(int endCmd) -{ - if (endCmdFor(openedCommands.top()) == endCmd && openedCommands.size() > 1) { - openedCommands.pop(); - return true; - } - else { - bool contains = false; - QStack<int> opened2 = openedCommands; - while (opened2.size() > 1) { - if (endCmdFor(opened2.top()) == endCmd) { - contains = true; - break; - } - opened2.pop(); - } - - if (contains) { - while (endCmdFor(openedCommands.top()) != endCmd && openedCommands.size() > 1) { - location().warning(tr("Missing '\\%1' before '\\%2'") - .arg(endCmdName(openedCommands.top())) - .arg(cmdName(endCmd))); - openedCommands.pop(); - } - } - else { - location().warning(tr("Unexpected '\\%1'").arg(cmdName(endCmd))); - } - return false; - } -} - -void DocParser::startSection(Doc::Sections unit, int cmd) -{ - leaveValueList(); - - if (currentSection == Doc::NoSection) { - currentSection = (Doc::Sections) (unit); - priv->constructExtra(); - priv->extra->section_ = currentSection; - } - else - endSection(unit,cmd); - - append(Atom::SectionLeft, QString::number(unit)); - priv->constructExtra(); - priv->extra->tableOfContents_.append(priv->text.lastAtom()); - priv->extra->tableOfContentsLevels_.append(unit); - enterPara(Atom::SectionHeadingLeft, - Atom::SectionHeadingRight, - QString::number(unit)); - currentSection = unit; - -} - -void DocParser::endSection(int , int) // (int unit, int endCmd) -{ - leavePara(); - append(Atom::SectionRight, QString::number(currentSection)); - currentSection = (Doc::NoSection); -} - -void DocParser::parseAlso() -{ - leavePara(); - skipSpacesOnLine(); - while (pos < len && in[pos] != '\n') { - QString target; - QString str; - - if (in[pos] == '{') { - target = getArgument(); - skipSpacesOnLine(); - if (in[pos] == '{') { - str = getArgument(); - - // hack for C++ to support links like \l{QString::}{count()} - if (target.endsWith("::")) - target += str; - } - else { - str = target; - } -#ifdef QDOC2_COMPAT - } - else if (in[pos] == '\\' && in.mid(pos, 5) == "\\link") { - pos += 6; - target = getArgument(); - int endPos = in.indexOf("\\endlink", pos); - if (endPos != -1) { - str = in.mid(pos, endPos - pos).trimmed(); - pos = endPos + 8; - } -#endif - } - else { - target = getArgument(); - str = cleanLink(target); - } - - Text also; - also << Atom(Atom::Link, target) - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << str - << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); - priv->addAlso(also); - - skipSpacesOnLine(); - if (pos < len && in[pos] == ',') { - pos++; - skipSpacesOrOneEndl(); - } - else if (in[pos] != '\n') { - location().warning(tr("Missing comma in '\\%1'").arg(cmdName(CMD_SA))); - } - } -} - -void DocParser::append(Atom::AtomType type, const QString &string) -{ - Atom::AtomType lastType = priv->text.lastAtom()->type(); - if ((lastType == Atom::Code) && priv->text.lastAtom()->string().endsWith(QLatin1String("\n\n"))) - priv->text.lastAtom()->chopString(); - priv->text << Atom(type, string); -} - -void DocParser::append(const QString &string) -{ - Atom::AtomType lastType = priv->text.lastAtom()->type(); - if ((lastType == Atom::Code) && priv->text.lastAtom()->string().endsWith(QLatin1String("\n\n"))) - priv->text.lastAtom()->chopString(); - priv->text << Atom(string); // The Atom type is Link. -} - -void DocParser::append(Atom::AtomType type, const QString& p1, const QString& p2) -{ - Atom::AtomType lastType = priv->text.lastAtom()->type(); - if ((lastType == Atom::Code) && priv->text.lastAtom()->string().endsWith(QLatin1String("\n\n"))) - priv->text.lastAtom()->chopString(); - priv->text << Atom(type, p1, p2); -} - -void DocParser::append(const QString& p1, const QString& p2) -{ - Atom::AtomType lastType = priv->text.lastAtom()->type(); - if ((lastType == Atom::Code) && priv->text.lastAtom()->string().endsWith(QLatin1String("\n\n"))) - priv->text.lastAtom()->chopString(); - if (p2.isEmpty()) - priv->text << Atom(p1); // The Atom type is Link. - else - priv->text << LinkAtom(p1, p2); -} - -void DocParser::appendChar(QChar ch) -{ - if (priv->text.lastAtom()->type() != Atom::String) - append(Atom::String); - Atom *atom = priv->text.lastAtom(); - if (ch == QLatin1Char(' ')) { - if (!atom->string().endsWith(QLatin1Char(' '))) - atom->appendChar(QLatin1Char(' ')); - } - else - atom->appendChar(ch); -} - -void DocParser::appendWord(const QString &word) -{ - if (priv->text.lastAtom()->type() != Atom::String) { - append(Atom::String, word); - } - else - priv->text.lastAtom()->appendString(word); -} - -void DocParser::appendToCode(const QString& markedCode) -{ - Atom::AtomType lastType = priv->text.lastAtom()->type(); - if (lastType != Atom::Qml && lastType != Atom::Code && lastType != Atom::JavaScript) - append(Atom::Qml); - priv->text.lastAtom()->appendString(markedCode); -} - -void DocParser::appendToCode(const QString &markedCode, Atom::AtomType defaultType) -{ - Atom::AtomType lastType = priv->text.lastAtom()->type(); - if (lastType != Atom::Qml && lastType != Atom::Code && lastType != Atom::JavaScript) - append(defaultType, markedCode); - else - priv->text.lastAtom()->appendString(markedCode); -} - -void DocParser::startNewPara() -{ - leavePara(); - enterPara(); -} - -void DocParser::enterPara(Atom::AtomType leftType, - Atom::AtomType rightType, - const QString& string) -{ - if (paraState == OutsideParagraph) { - - if ((priv->text.lastAtom()->type() != Atom::ListItemLeft) && - (priv->text.lastAtom()->type() != Atom::DivLeft)) { - leaveValueList(); - } - - append(leftType, string); - indexStartedPara = false; - pendingParaLeftType = leftType; - pendingParaRightType = rightType; - pendingParaString = string; - if (leftType == Atom::SectionHeadingLeft) { - paraState = InSingleLineParagraph; - } - else { - paraState = InMultiLineParagraph; - } - skipSpacesOrOneEndl(); - } -} - -void DocParser::leavePara() -{ - if (paraState != OutsideParagraph) { - if (!pendingFormats.isEmpty()) { - location().warning(tr("Missing '}'")); - pendingFormats.clear(); - } - - if (priv->text.lastAtom()->type() == pendingParaLeftType) { - priv->text.stripLastAtom(); - } - else { - if (priv->text.lastAtom()->type() == Atom::String && - priv->text.lastAtom()->string().endsWith(QLatin1Char(' '))) { - priv->text.lastAtom()->chopString(); - } - append(pendingParaRightType, pendingParaString); - } - paraState = OutsideParagraph; - indexStartedPara = false; - pendingParaRightType = Atom::Nop; - pendingParaString.clear(); - } -} - -void DocParser::leaveValue() -{ - leavePara(); - if (openedLists.isEmpty()) { - openedLists.push(OpenedList(OpenedList::Value)); - append(Atom::ListLeft, ATOM_LIST_VALUE); - } - else { - if (priv->text.lastAtom()->type() == Atom::Nop) - priv->text.stripLastAtom(); - append(Atom::ListItemRight, ATOM_LIST_VALUE); - } -} - -void DocParser::leaveValueList() -{ - leavePara(); - if (!openedLists.isEmpty() && - (openedLists.top().style() == OpenedList::Value)) { - if (priv->text.lastAtom()->type() == Atom::Nop) - priv->text.stripLastAtom(); - append(Atom::ListItemRight, ATOM_LIST_VALUE); - append(Atom::ListRight, ATOM_LIST_VALUE); - openedLists.pop(); - } -} - -void DocParser::leaveTableRow() -{ - if (inTableItem) { - leavePara(); - append(Atom::TableItemRight); - inTableItem = false; - } - if (inTableHeader) { - append(Atom::TableHeaderRight); - inTableHeader = false; - } - if (inTableRow) { - append(Atom::TableRowRight); - inTableRow = false; - } -} - -CodeMarker *DocParser::quoteFromFile() -{ - return Doc::quoteFromFile(location(), quoter, getArgument()); -} - -void DocParser::expandMacro(const QString &name, - const QString &def, - int numParams) -{ - if (numParams == 0) { - append(Atom::RawString, def); - } - else { - QStringList args; - QString rawString; - - for (int i = 0; i < numParams; i++) { - if (numParams == 1 || isLeftBraceAhead()) { - args << getArgument(true); - } - else { - location().warning(tr("Macro '\\%1' invoked with too few" - " arguments (expected %2, got %3)") - .arg(name).arg(numParams).arg(i)); - break; - } - } - - int j = 0; - while (j < def.size()) { - int paramNo; - if (((paramNo = def[j].unicode()) >= 1) && - (paramNo <= numParams)) { - if (!rawString.isEmpty()) { - append(Atom::RawString, rawString); - rawString.clear(); - } - append(Atom::String, args[paramNo - 1]); - j += 1; - } - else { - rawString += def[j++]; - } - } - if (!rawString.isEmpty()) - append(Atom::RawString, rawString); - } -} - -QString DocParser::expandMacroToString(const QString &name, const QString &def, int numParams) -{ - if (numParams == 0) { - return def; - } - else { - QStringList args; - QString rawString; - - for (int i = 0; i < numParams; i++) { - if (numParams == 1 || isLeftBraceAhead()) { - args << getArgument(true); - } - else { - location().warning(tr("Macro '\\%1' invoked with too few" - " arguments (expected %2, got %3)") - .arg(name).arg(numParams).arg(i)); - break; - } - } - - int j = 0; - while (j < def.size()) { - int paramNo; - if (((paramNo = def[j].unicode()) >= 1) && - (paramNo <= numParams)) { - rawString += args[paramNo - 1]; - j += 1; - } - else { - rawString += def[j++]; - } - } - return rawString; - } -} - -Doc::Sections DocParser::getSectioningUnit() -{ - QString name = getOptionalArgument(); - - if (name == "part") { - return Doc::Part; - } - else if (name == "chapter") { - return Doc::Chapter; - } - else if (name == "section1") { - return Doc::Section1; - } - else if (name == "section2") { - return Doc::Section2; - } - else if (name == "section3") { - return Doc::Section3; - } - else if (name == "section4") { - return Doc::Section4; - } - else if (name.isEmpty()) { - return Doc::NoSection; - } - else { - location().warning(tr("Invalid section '%1'").arg(name)); - return Doc::NoSection; - } -} - -/*! - Gets an argument that is enclosed in braces and returns it - without the enclosing braces. On entry, the current character - is the left brace. On exit, the current character is the one - that comes after the right brace. - - If \a verbatim is true, extra whitespace is retained in the - returned string. Otherwise, extra whitespace is removed. - */ -QString DocParser::getBracedArgument(bool verbatim) -{ - QString arg; - int delimDepth = 0; - if (pos < (int) in.length() && in[pos] == '{') { - pos++; - while (pos < (int) in.length() && delimDepth >= 0) { - switch (in[pos].unicode()) { - case '{': - delimDepth++; - arg += QLatin1Char('{'); - pos++; - break; - case '}': - delimDepth--; - if (delimDepth >= 0) - arg += QLatin1Char('}'); - pos++; - break; - case '\\': - if (verbatim) { - arg += in[pos]; - pos++; - } - else { - pos++; - if (pos < (int) in.length()) { - if (in[pos].isLetterOrNumber()) - break; - arg += in[pos]; - if (in[pos].isSpace()) { - skipAllSpaces(); - } - else { - pos++; - } - } - } - break; - default: - if (in[pos].isSpace() && !verbatim) - arg += QChar(' '); - else - arg += in[pos]; - pos++; - } - } - if (delimDepth > 0) - location().warning(tr("Missing '}'")); - } - return arg; -} - -/*! - Typically, an argument ends at the next white-space. However, - braces can be used to group words: - - {a few words} - - Also, opening and closing parentheses have to match. Thus, - - printf("%d\n", x) - - is an argument too, although it contains spaces. Finally, - trailing punctuation is not included in an argument, nor is 's. -*/ -QString DocParser::getArgument(bool verbatim) -{ - skipSpacesOrOneEndl(); - - int delimDepth = 0; - int startPos = pos; - QString arg = getBracedArgument(verbatim); - if (arg.isEmpty()) { - while ((pos < in.length()) && - ((delimDepth > 0) || ((delimDepth == 0) && !in[pos].isSpace()))) { - switch (in[pos].unicode()) { - case '(': - case '[': - case '{': - delimDepth++; - arg += in[pos]; - pos++; - break; - case ')': - case ']': - case '}': - delimDepth--; - if (pos == startPos || delimDepth >= 0) { - arg += in[pos]; - pos++; - } - break; - case '\\': - if (verbatim) { - arg += in[pos]; - pos++; - } - else { - pos++; - if (pos < (int) in.length()) { - if (in[pos].isLetterOrNumber()) - break; - arg += in[pos]; - if (in[pos].isSpace()) { - skipAllSpaces(); - } - else { - pos++; - } - } - } - break; - default: - arg += in[pos]; - pos++; - } - } - if ((arg.length() > 1) && - (QString(".,:;!?").indexOf(in[pos - 1]) != -1) && - !arg.endsWith("...")) { - arg.truncate(arg.length() - 1); - pos--; - } - if (arg.length() > 2 && in.mid(pos - 2, 2) == "'s") { - arg.truncate(arg.length() - 2); - pos -= 2; - } - } - return arg.simplified(); -} - -/*! - Gets an argument that is enclosed in brackets and returns it - without the enclosing brackets. On entry, the current character - is the left bracket. On exit, the current character is the one - that comes after the right bracket. - */ -QString DocParser::getBracketedArgument() -{ - QString arg; - int delimDepth = 0; - skipSpacesOrOneEndl(); - if (pos < in.length() && in[pos] == '[') { - pos++; - while (pos < in.length() && delimDepth >= 0) { - switch (in[pos].unicode()) { - case '[': - delimDepth++; - arg += QLatin1Char('['); - pos++; - break; - case ']': - delimDepth--; - if (delimDepth >= 0) - arg += QLatin1Char(']'); - pos++; - break; - case '\\': - arg += in[pos]; - pos++; - break; - default: - arg += in[pos]; - pos++; - } - } - if (delimDepth > 0) - location().warning(tr("Missing ']'")); - } - return arg; -} - -QString DocParser::getOptionalArgument() -{ - skipSpacesOrOneEndl(); - if (pos + 1 < (int) in.length() && in[pos] == '\\' && - in[pos + 1].isLetterOrNumber()) { - return QString(); - } - else { - return getArgument(); - } -} - -QString DocParser::getRestOfLine() -{ - QString t; - - skipSpacesOnLine(); - - bool trailingSlash = false; - - do { - int begin = pos; - - while (pos < in.size() && in[pos] != '\n') { - if (in[pos] == '\\' && !trailingSlash) { - trailingSlash = true; - ++pos; - while ((pos < in.size()) && - in[pos].isSpace() && - (in[pos] != '\n')) - ++pos; - } - else { - trailingSlash = false; - ++pos; - } - } - - if (!t.isEmpty()) - t += QLatin1Char(' '); - t += in.mid(begin, pos - begin).simplified(); - - if (trailingSlash) { - t.chop(1); - t = t.simplified(); - } - if (pos < in.size()) - ++pos; - } while (pos < in.size() && trailingSlash); - - return t; -} - -/*! - The metacommand argument is normally the remaining text to - the right of the metacommand itself. The extra blanks are - stripped and the argument string is returned. - */ -QString DocParser::getMetaCommandArgument(const QString &cmdStr) -{ - skipSpacesOnLine(); - - int begin = pos; - int parenDepth = 0; - - while (pos < in.size() && (in[pos] != '\n' || parenDepth > 0)) { - if (in.at(pos) == '(') - ++parenDepth; - else if (in.at(pos) == ')') - --parenDepth; - - ++pos; - } - if (pos == in.size() && parenDepth > 0) { - pos = begin; - location().warning(tr("Unbalanced parentheses in '%1'").arg(cmdStr)); - } - - QString t = in.mid(begin, pos - begin).simplified(); - skipSpacesOnLine(); - return t; -} - -QString DocParser::getUntilEnd(int cmd) -{ - int endCmd = endCmdFor(cmd); - QRegExp rx("\\\\" + cmdName(endCmd) + "\\b"); - QString t; - int end = rx.indexIn(in, pos); - - if (end == -1) { - location().warning(tr("Missing '\\%1'").arg(cmdName(endCmd))); - pos = in.length(); - } - else { - t = in.mid(pos, end - pos); - pos = end + rx.matchedLength(); - } - return t; -} - -QString DocParser::getCode(int cmd, CodeMarker *marker) -{ - QString code = untabifyEtc(getUntilEnd(cmd)); - int indent = indentLevel(code); - if (indent < minIndent) - minIndent = indent; - code = unindent(minIndent, code); - if (!marker) - marker = CodeMarker::markerForCode(code); - return marker->markedUpCode(code, 0, location()); -} - -/*! - Was used only for generating doxygen output. - */ -QString DocParser::getUnmarkedCode(int cmd) -{ - QString code = getUntilEnd(cmd); - return code; -} - -bool DocParser::isBlankLine() -{ - int i = pos; - - while (i < len && in[i].isSpace()) { - if (in[i] == '\n') - return true; - i++; - } - return false; -} - -bool DocParser::isLeftBraceAhead() -{ - int numEndl = 0; - int i = pos; - - while (i < len && in[i].isSpace() && numEndl < 2) { - // ### bug with '\\' - if (in[i] == '\n') - numEndl++; - i++; - } - return numEndl < 2 && i < len && in[i] == '{'; -} - -bool DocParser::isLeftBracketAhead() -{ - int numEndl = 0; - int i = pos; - - while (i < len && in[i].isSpace() && numEndl < 2) { - // ### bug with '\\' - if (in[i] == '\n') - numEndl++; - i++; - } - return numEndl < 2 && i < len && in[i] == '['; -} - -/*! - Skips to the next non-space character or EOL. - */ -void DocParser::skipSpacesOnLine() -{ - while ((pos < in.length()) && - in[pos].isSpace() && - (in[pos].unicode() != '\n')) - ++pos; -} - -/*! - Skips spaces and on EOL. - */ -void DocParser::skipSpacesOrOneEndl() -{ - int firstEndl = -1; - while (pos < (int) in.length() && in[pos].isSpace()) { - QChar ch = in[pos]; - if (ch == '\n') { - if (firstEndl == -1) { - firstEndl = pos; - } - else { - pos = firstEndl; - break; - } - } - pos++; - } -} - -void DocParser::skipAllSpaces() -{ - while (pos < len && in[pos].isSpace()) - pos++; -} - -void DocParser::skipToNextPreprocessorCommand() -{ - QRegExp rx("\\\\(?:" + cmdName(CMD_IF) + QLatin1Char('|') + - cmdName(CMD_ELSE) + QLatin1Char('|') + - cmdName(CMD_ENDIF) + ")\\b"); - int end = rx.indexIn(in, pos + 1); // ### + 1 necessary? - - if (end == -1) - pos = in.length(); - else - pos = end; -} - -int DocParser::endCmdFor(int cmd) -{ - switch (cmd) { - case CMD_BADCODE: - return CMD_ENDCODE; - case CMD_CHAPTER: - return CMD_ENDCHAPTER; - case CMD_CODE: - return CMD_ENDCODE; - case CMD_DIV: - return CMD_ENDDIV; - case CMD_QML: - return CMD_ENDQML; - case CMD_QMLTEXT: - return CMD_ENDQMLTEXT; - case CMD_JS: - return CMD_ENDJS; - case CMD_FOOTNOTE: - return CMD_ENDFOOTNOTE; - case CMD_LEGALESE: - return CMD_ENDLEGALESE; - case CMD_LINK: - return CMD_ENDLINK; - case CMD_LIST: - return CMD_ENDLIST; - case CMD_NEWCODE: - return CMD_ENDCODE; - case CMD_OLDCODE: - return CMD_NEWCODE; - case CMD_OMIT: - return CMD_ENDOMIT; - case CMD_PART: - return CMD_ENDPART; - case CMD_QUOTATION: - return CMD_ENDQUOTATION; - case CMD_RAW: - return CMD_ENDRAW; - case CMD_SECTION1: - return CMD_ENDSECTION1; - case CMD_SECTION2: - return CMD_ENDSECTION2; - case CMD_SECTION3: - return CMD_ENDSECTION3; - case CMD_SECTION4: - return CMD_ENDSECTION4; - case CMD_SIDEBAR: - return CMD_ENDSIDEBAR; - case CMD_TABLE: - return CMD_ENDTABLE; - case CMD_TOPICREF: - return CMD_ENDTOPICREF; - case CMD_MAPREF: - return CMD_ENDMAPREF; - default: - return cmd; - } -} - -QString DocParser::cmdName(int cmd) -{ - return *cmds[cmd].alias; -} - -QString DocParser::endCmdName(int cmd) -{ - return cmdName(endCmdFor(cmd)); -} - -QString DocParser::untabifyEtc(const QString& str) -{ - QString result; - result.reserve(str.length()); - int column = 0; - - for (int i = 0; i < str.length(); i++) { - const QChar c = str.at(i); - if (c == QLatin1Char('\r')) - continue; - if (c == QLatin1Char('\t')) { - result += &" "[column % tabSize]; - column = ((column / tabSize) + 1) * tabSize; - continue; - } - if (c == QLatin1Char('\n')) { - while (result.endsWith(QLatin1Char(' '))) - result.chop(1); - result += c; - column = 0; - continue; - } - result += c; - column++; - } - - while (result.endsWith("\n\n")) - result.truncate(result.length() - 1); - while (result.startsWith(QLatin1Char('\n'))) - result = result.mid(1); - - return result; -} - -int DocParser::indentLevel(const QString& str) -{ - int minIndent = INT_MAX; - int column = 0; - - for (int i = 0; i < (int) str.length(); i++) { - if (str[i] == '\n') { - column = 0; - } - else { - if (str[i] != ' ' && column < minIndent) - minIndent = column; - column++; - } - } - return minIndent; -} - -QString DocParser::unindent(int level, const QString& str) -{ - if (level == 0) - return str; - - QString t; - int column = 0; - - for (int i = 0; i < (int) str.length(); i++) { - if (str[i] == QLatin1Char('\n')) { - t += '\n'; - column = 0; - } - else { - if (column >= level) - t += str[i]; - column++; - } - } - return t; -} - -QString DocParser::slashed(const QString& str) -{ - QString result = str; - result.replace(QLatin1Char('/'), "\\/"); - return QLatin1Char('/') + result + QLatin1Char('/'); -} - -/*! - Parse the qdoc comment \a source. Build up a list of all the topic - commands found including their arguments. This constructor is used - when there can be more than one topic command in theqdoc comment. - Normally, there is only one topic command in a qdoc comment, but in - QML documentation, there is the case where the qdoc \e{qmlproperty} - command can appear multiple times in a qdoc comment. - */ -Doc::Doc(const Location& start_loc, - const Location& end_loc, - const QString& source, - const QSet<QString>& metaCommandSet, - const QSet<QString>& topics) -{ - priv = new DocPrivate(start_loc,end_loc,source); - DocParser parser; - parser.parse(source,priv,metaCommandSet,topics); -} - -Doc::Doc(const Doc& doc) - : priv(0) -{ - operator=(doc); -} - -Doc::~Doc() -{ - if (priv && priv->deref()) - delete priv; -} - -Doc &Doc::operator=(const Doc& doc) -{ - if (doc.priv) - doc.priv->ref(); - if (priv && priv->deref()) - delete priv; - priv = doc.priv; - return *this; -} - -void Doc::renameParameters(const QStringList &oldNames, - const QStringList &newNames) -{ - if (priv && oldNames != newNames) { - detach(); - - priv->params = newNames.toSet(); - - Atom *atom = priv->text.firstAtom(); - while (atom) { - if (atom->type() == Atom::FormattingLeft - && atom->string() == ATOM_FORMATTING_PARAMETER) { - atom = atom->next(); - if (!atom) - return; - int index = oldNames.indexOf(atom->string()); - if (index != -1 && index < newNames.count()) - atom->setString(newNames.at(index)); - } - atom = atom->next(); - } - } -} - -void Doc::simplifyEnumDoc() -{ - if (priv) { - if (priv->isEnumDocSimplifiable()) { - detach(); - - Text newText; - - Atom *atom = priv->text.firstAtom(); - while (atom) { - if ((atom->type() == Atom::ListLeft) && - (atom->string() == ATOM_LIST_VALUE)) { - while (atom && ((atom->type() != Atom::ListRight) || - (atom->string() != ATOM_LIST_VALUE))) - atom = atom->next(); - if (atom) - atom = atom->next(); - } - else { - newText << *atom; - atom = atom->next(); - } - } - priv->text = newText; - } - } -} - -void Doc::setBody(const Text &text) -{ - detach(); - priv->text = text; -} - -/*! - Returns the starting location of a qdoc comment. - */ -const Location &Doc::location() const -{ - static const Location dummy; - return priv == 0 ? dummy : priv->start_loc; -} - -/*! - Returns the starting location of a qdoc comment. - */ -const Location& Doc::startLocation() const -{ - return location(); -} - -/*! - Returns the ending location of a qdoc comment. - */ -const Location& Doc::endLocation() const -{ - static const Location dummy; - return priv == 0 ? dummy : priv->end_loc; -} - -const QString &Doc::source() const -{ - static QString null; - return priv == 0 ? null : priv->src; -} - -bool Doc::isEmpty() const -{ - return priv == 0 || priv->src.isEmpty(); -} - -const Text& Doc::body() const -{ - static const Text dummy; - return priv == 0 ? dummy : priv->text; -} - -Text Doc::briefText(bool inclusive) const -{ - return body().subText(Atom::BriefLeft, Atom::BriefRight, 0, inclusive); -} - -Text Doc::trimmedBriefText(const QString &className) const -{ - QString classNameOnly = className; - if (className.contains("::")) - classNameOnly = className.split("::").last(); - - Text originalText = briefText(); - Text resultText; - const Atom *atom = originalText.firstAtom(); - if (atom) { - QString briefStr; - QString whats; - /* - This code is really ugly. The entire \brief business - should be rethought. - */ - while (atom) { - if (atom->type() == Atom::AutoLink || atom->type() == Atom::String) { - briefStr += atom->string(); - } - atom = atom->next(); - } - - QStringList w = briefStr.split(QLatin1Char(' ')); - if (!w.isEmpty() && w.first() == "Returns") { - } - else { - if (!w.isEmpty() && w.first() == "The") - w.removeFirst(); - - if (!w.isEmpty() && (w.first() == className || w.first() == classNameOnly)) - w.removeFirst(); - - if (!w.isEmpty() && ((w.first() == "class") || - (w.first() == "function") || - (w.first() == "macro") || - (w.first() == "widget") || - (w.first() == "namespace") || - (w.first() == "header"))) - w.removeFirst(); - - if (!w.isEmpty() && (w.first() == "is" || w.first() == "provides")) - w.removeFirst(); - - if (!w.isEmpty() && (w.first() == "a" || w.first() == "an")) - w.removeFirst(); - } - - whats = w.join(' '); - - if (whats.endsWith(QLatin1Char('.'))) - whats.truncate(whats.length() - 1); - - if (!whats.isEmpty()) - whats[0] = whats[0].toUpper(); - - // ### move this once \brief is abolished for properties - resultText << whats; - } - return resultText; -} - -Text Doc::legaleseText() const -{ - if (priv == 0 || !priv->hasLegalese) - return Text(); - else - return body().subText(Atom::LegaleseLeft, Atom::LegaleseRight); -} - -Doc::Sections Doc::granularity() const -{ - if (priv == 0 || priv->extra == 0) { - return DocPrivateExtra().granularity_; - } - else { - return priv->extra->granularity_; - } -} - -const QSet<QString> &Doc::parameterNames() const -{ - return priv == 0 ? *null_Set_QString() : priv->params; -} - -const QStringList &Doc::enumItemNames() const -{ - return priv == 0 ? *null_QStringList() : priv->enumItemList; -} - -const QStringList &Doc::omitEnumItemNames() const -{ - return priv == 0 ? *null_QStringList() : priv->omitEnumItemList; -} - -const QSet<QString> &Doc::metaCommandsUsed() const -{ - return priv == 0 ? *null_Set_QString() : priv->metacommandsUsed; -} - -/*! - Returns a reference to the list of topic commands used in the - current qdoc comment. Normally there is only one, but there - can be multiple \e{qmlproperty} commands, for example. - */ -const TopicList& Doc::topicsUsed() const -{ - return priv == 0 ? *nullTopicList() : priv->topics_; -} - -ArgList Doc::metaCommandArgs(const QString& metacommand) const -{ - return priv == 0 ? ArgList() : priv->metaCommandMap.value(metacommand); -} - -const QList<Text> &Doc::alsoList() const -{ - return priv == 0 ? *null_QList_Text() : priv->alsoList; -} - -bool Doc::hasTableOfContents() const -{ - return priv && priv->extra && !priv->extra->tableOfContents_.isEmpty(); -} - -bool Doc::hasKeywords() const -{ - return priv && priv->extra && !priv->extra->keywords_.isEmpty(); -} - -bool Doc::hasTargets() const -{ - return priv && priv->extra && !priv->extra->targets_.isEmpty(); -} - -const QList<Atom *> &Doc::tableOfContents() const -{ - priv->constructExtra(); - return priv->extra->tableOfContents_; -} - -const QVector<int> &Doc::tableOfContentsLevels() const -{ - priv->constructExtra(); - return priv->extra->tableOfContentsLevels_; -} - -const QList<Atom *> &Doc::keywords() const -{ - priv->constructExtra(); - return priv->extra->keywords_; -} - -const QList<Atom *> &Doc::targets() const -{ - priv->constructExtra(); - return priv->extra->targets_; -} - -const QStringMultiMap &Doc::metaTagMap() const -{ - return priv && priv->extra ? priv->extra->metaMap_ : *null_QStringMultiMap(); -} - -const Config* Doc::config_ = 0; - -void Doc::initialize(const Config& config) -{ - DocParser::tabSize = config.getInt(CONFIG_TABSIZE); - DocParser::exampleFiles = config.getCanonicalPathList(CONFIG_EXAMPLES); - DocParser::exampleDirs = config.getCanonicalPathList(CONFIG_EXAMPLEDIRS); - DocParser::sourceFiles = config.getCanonicalPathList(CONFIG_SOURCES); - DocParser::sourceDirs = config.getCanonicalPathList(CONFIG_SOURCEDIRS); - DocParser::quoting = config.getBool(CONFIG_QUOTINGINFORMATION); - - QmlTypeNode::qmlOnly = config.getBool(CONFIG_QMLONLY); - QStringMap reverseAliasMap; - config_ = &config; - - QSet<QString> commands = config.subVars(CONFIG_ALIAS); - QSet<QString>::ConstIterator c = commands.constBegin(); - while (c != commands.constEnd()) { - QString alias = config.getString(CONFIG_ALIAS + Config::dot + *c); - if (reverseAliasMap.contains(alias)) { - config.lastLocation().warning(tr("Command name '\\%1' cannot stand" - " for both '\\%2' and '\\%3'") - .arg(alias) - .arg(reverseAliasMap[alias]) - .arg(*c)); - } - else { - reverseAliasMap.insert(alias, *c); - } - aliasMap()->insert(*c, alias); - ++c; - } - - int i = 0; - while (cmds[i].english) { - cmds[i].alias = new QString(alias(cmds[i].english)); - cmdHash()->insert(*cmds[i].alias, cmds[i].no); - - if (cmds[i].no != i) - Location::internalError(tr("command %1 missing").arg(i)); - i++; - } - - QSet<QString> macroNames = config.subVars(CONFIG_MACRO); - QSet<QString>::ConstIterator n = macroNames.constBegin(); - while (n != macroNames.constEnd()) { - QString macroDotName = CONFIG_MACRO + Config::dot + *n; - Macro macro; - macro.numParams = -1; - macro.defaultDef = config.getString(macroDotName); - if (!macro.defaultDef.isEmpty()) { - macro.defaultDefLocation = config.lastLocation(); - macro.numParams = Config::numParams(macro.defaultDef); - } - bool silent = false; - - QSet<QString> formats = config.subVars(macroDotName); - QSet<QString>::ConstIterator f = formats.constBegin(); - while (f != formats.constEnd()) { - QString def = config.getString(macroDotName + Config::dot + *f); - if (!def.isEmpty()) { - macro.otherDefs.insert(*f, def); - int m = Config::numParams(def); - if (macro.numParams == -1) { - macro.numParams = m; - } - else if (macro.numParams != m) { - if (!silent) { - QString other = tr("default"); - if (macro.defaultDef.isEmpty()) - other = macro.otherDefs.constBegin().key(); - config.lastLocation().warning(tr("Macro '\\%1' takes" - " inconsistent number" - " of arguments (%2" - " %3, %4 %5)") - .arg(*n) - .arg(*f) - .arg(m) - .arg(other) - .arg(macro.numParams)); - silent = true; - } - if (macro.numParams < m) - macro.numParams = m; - } - } - ++f; - } - - if (macro.numParams != -1) - macroHash()->insert(*n, macro); - ++n; - } -} - -/*! - All the heap allocated variables are deleted. - */ -void Doc::terminate() -{ - DocParser::exampleFiles.clear(); - DocParser::exampleDirs.clear(); - DocParser::sourceFiles.clear(); - DocParser::sourceDirs.clear(); - aliasMap()->clear(); - cmdHash()->clear(); - macroHash()->clear(); - - int i = 0; - while (cmds[i].english) { - delete cmds[i].alias; - cmds[i].alias = 0; - ++i; - } -} - -QString Doc::alias(const QString &english) -{ - return aliasMap()->value(english, english); -} - -/*! - Trims the deadwood out of \a str. i.e., this function - cleans up \a str. - */ -void Doc::trimCStyleComment(Location& location, QString& str) -{ - QString cleaned; - Location m = location; - bool metAsterColumn = true; - int asterColumn = location.columnNo() + 1; - int i; - - for (i = 0; i < (int) str.length(); i++) { - if (m.columnNo() == asterColumn) { - if (str[i] != '*') - break; - cleaned += ' '; - metAsterColumn = true; - } - else { - if (str[i] == '\n') { - if (!metAsterColumn) - break; - metAsterColumn = false; - } - cleaned += str[i]; - } - m.advance(str[i]); - } - if (cleaned.length() == str.length()) - str = cleaned; - - for (int i = 0; i < 3; i++) - location.advance(str[i]); - str = str.mid(3, str.length() - 5); -} - -CodeMarker *Doc::quoteFromFile(const Location &location, - Quoter "er, - const QString &fileName) -{ - quoter.reset(); - - QString code; - - QString userFriendlyFilePath; - QString filePath = Config::findFile(location, - DocParser::exampleFiles, - DocParser::exampleDirs, - fileName, userFriendlyFilePath); - if (filePath.isEmpty()) { - QString details = QLatin1String("Example directories: ") + DocParser::exampleDirs.join(QLatin1Char(' ')); - if (!DocParser::exampleFiles.isEmpty()) - details += QLatin1String(", example files: ") + DocParser::exampleFiles.join(QLatin1Char(' ')); - location.warning(tr("Cannot find file to quote from: '%1'").arg(fileName), details); - } - else { - QFile inFile(filePath); - if (!inFile.open(QFile::ReadOnly)) { - location.warning(tr("Cannot open file to quote from: '%1'").arg(userFriendlyFilePath)); - } - else { - QTextStream inStream(&inFile); - code = DocParser::untabifyEtc(inStream.readAll()); - } - } - - QString dirPath = QFileInfo(filePath).path(); - CodeMarker *marker = CodeMarker::markerForFileName(fileName); - quoter.quoteFromFile(userFriendlyFilePath, code, marker->markedUpCode(code, 0, location)); - return marker; -} - -QString Doc::canonicalTitle(const QString &title) -{ - // The code below is equivalent to the following chunk, but _much_ - // faster (accounts for ~10% of total running time) - // - // QRegExp attributeExpr("[^A-Za-z0-9]+"); - // QString result = title.toLower(); - // result.replace(attributeExpr, " "); - // result = result.simplified(); - // result.replace(QLatin1Char(' '), QLatin1Char('-')); - - QString result; - result.reserve(title.size()); - - bool dashAppended = false; - bool begun = false; - int lastAlnum = 0; - for (int i = 0; i != title.size(); ++i) { - uint c = title.at(i).unicode(); - if (c >= 'A' && c <= 'Z') - c += 'a' - 'A'; - bool alnum = (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'); - if (alnum) { - result += QLatin1Char(c); - begun = true; - dashAppended = false; - lastAlnum = result.size(); - } - else if (!dashAppended) { - if (begun) - result += QLatin1Char('-'); - dashAppended = true; - } - } - result.truncate(lastAlnum); - return result; -} - -void Doc::detach() -{ - if (!priv) { - priv = new DocPrivate; - return; - } - if (priv->count == 1) - return; - - --priv->count; - - DocPrivate *newPriv = new DocPrivate(*priv); - newPriv->count = 1; - if (priv->extra) - newPriv->extra = new DocPrivateExtra(*priv->extra); - - priv = newPriv; -} - -/*! - The destructor deletes all the sub-TopicRefs. - */ -TopicRef::~TopicRef() -{ - foreach (DitaRef* t, subrefs_) { - delete t; - } -} - -/*! - Returns a reference to the structure that will be used - for generating a DITA mao. - */ -const DitaRefList& Doc::ditamap() const { return priv->ditamap_; } - -QT_END_NAMESPACE |