1 /****************************************************************************
2 **
3 ** Copyright (C) 2019 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the tools applications of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21 ** included in the packaging of this file. Please review the following
22 ** information to ensure the GNU General Public License requirements will
23 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 **
25 ** $QT_END_LICENSE$
26 **
27 ****************************************************************************/
28 
29 #include "atom.h"
30 
31 #include "location.h"
32 #include "qdocdatabase.h"
33 
34 #include <QtCore/qdebug.h>
35 #include <QtCore/qregexp.h>
36 
37 #include <stdio.h>
38 
39 QT_BEGIN_NAMESPACE
40 
41 /*! \class Atom
42     \brief The Atom class is the fundamental unit for representing
43     documents internally.
44 
45   Atoms have a \i type and are completed by a \i string whose
46   meaning depends on the \i type. For example, the string
47   \quotation
48       \i italic text looks nicer than \bold bold text
49   \endquotation
50   is represented by the following atoms:
51   \quotation
52       (FormattingLeft, ATOM_FORMATTING_ITALIC)
53       (String, "italic")
54       (FormattingRight, ATOM_FORMATTING_ITALIC)
55       (String, " text is more attractive than ")
56       (FormattingLeft, ATOM_FORMATTING_BOLD)
57       (String, "bold")
58       (FormattingRight, ATOM_FORMATTING_BOLD)
59       (String, " text")
60   \endquotation
61 
62   \also Text
63 */
64 
65 /*! \enum Atom::AtomType
66 
67   \value AnnotatedList
68   \value AutoLink
69   \value BaseName
70   \value BriefLeft
71   \value BriefRight
72   \value C
73   \value CaptionLeft
74   \value CaptionRight
75   \value Code
76   \value CodeBad
77   \value CodeNew
78   \value CodeOld
79   \value CodeQuoteArgument
80   \value CodeQuoteCommand
81   \value DivLeft
82   \value DivRight
83   \value EndQmlText
84   \value ExampleFileLink
85   \value ExampleImageLink
86   \value FormatElse
87   \value FormatEndif
88   \value FormatIf
89   \value FootnoteLeft
90   \value FootnoteRight
91   \value FormattingLeft
92   \value FormattingRight
93   \value GeneratedList
94   \value Image
95   \value ImageText
96   \value ImportantNote
97   \value InlineImage
98   \value JavaScript
99   \value EndJavaScript
100   \value Keyword
101   \value LineBreak
102   \value Link
103   \value LinkNode
104   \value ListLeft
105   \value ListItemNumber
106   \value ListTagLeft
107   \value ListTagRight
108   \value ListItemLeft
109   \value ListItemRight
110   \value ListRight
111   \value NavAutoLink
112   \value NavLink
113   \value Nop
114   \value Note
115   \value ParaLeft
116   \value ParaRight
117   \value Qml
118   \value QmlText
119   \value QuotationLeft
120   \value QuotationRight
121   \value RawString
122   \value SectionLeft
123   \value SectionRight
124   \value SectionHeadingLeft
125   \value SectionHeadingRight
126   \value SidebarLeft
127   \value SidebarRight
128   \value SinceList
129   \value SinceTagLeft
130   \value SinceTagRight
131   \value String
132   \value TableLeft
133   \value TableRight
134   \value TableHeaderLeft
135   \value TableHeaderRight
136   \value TableRowLeft
137   \value TableRowRight
138   \value TableItemLeft
139   \value TableItemRight
140   \value TableOfContents
141   \value Target
142   \value UnhandledFormat
143   \value UnknownCommand
144 */
145 
146 QString Atom::noError_ = QString();
147 
148 static const struct
149 {
150     const char *english;
151     int no;
152 } atms[] = { { "AnnotatedList", Atom::AnnotatedList },
153              { "AutoLink", Atom::AutoLink },
154              { "BaseName", Atom::BaseName },
155              { "br", Atom::BR },
156              { "BriefLeft", Atom::BriefLeft },
157              { "BriefRight", Atom::BriefRight },
158              { "C", Atom::C },
159              { "CaptionLeft", Atom::CaptionLeft },
160              { "CaptionRight", Atom::CaptionRight },
161              { "Code", Atom::Code },
162              { "CodeBad", Atom::CodeBad },
163              { "CodeNew", Atom::CodeNew },
164              { "CodeOld", Atom::CodeOld },
165              { "CodeQuoteArgument", Atom::CodeQuoteArgument },
166              { "CodeQuoteCommand", Atom::CodeQuoteCommand },
167              { "DivLeft", Atom::DivLeft },
168              { "DivRight", Atom::DivRight },
169              { "EndQmlText", Atom::EndQmlText },
170              { "ExampleFileLink", Atom::ExampleFileLink },
171              { "ExampleImageLink", Atom::ExampleImageLink },
172              { "FootnoteLeft", Atom::FootnoteLeft },
173              { "FootnoteRight", Atom::FootnoteRight },
174              { "FormatElse", Atom::FormatElse },
175              { "FormatEndif", Atom::FormatEndif },
176              { "FormatIf", Atom::FormatIf },
177              { "FormattingLeft", Atom::FormattingLeft },
178              { "FormattingRight", Atom::FormattingRight },
179              { "GeneratedList", Atom::GeneratedList },
180              { "hr", Atom::HR },
181              { "Image", Atom::Image },
182              { "ImageText", Atom::ImageText },
183              { "ImportantLeft", Atom::ImportantLeft },
184              { "ImportantRight", Atom::ImportantRight },
185              { "InlineImage", Atom::InlineImage },
186              { "JavaScript", Atom::JavaScript },
187              { "EndJavaScript", Atom::EndJavaScript },
188              { "Keyword", Atom::Keyword },
189              { "LegaleseLeft", Atom::LegaleseLeft },
190              { "LegaleseRight", Atom::LegaleseRight },
191              { "LineBreak", Atom::LineBreak },
192              { "Link", Atom::Link },
193              { "LinkNode", Atom::LinkNode },
194              { "ListLeft", Atom::ListLeft },
195              { "ListItemNumber", Atom::ListItemNumber },
196              { "ListTagLeft", Atom::ListTagLeft },
197              { "ListTagRight", Atom::ListTagRight },
198              { "ListItemLeft", Atom::ListItemLeft },
199              { "ListItemRight", Atom::ListItemRight },
200              { "ListRight", Atom::ListRight },
201              { "NavAutoLink", Atom::NavAutoLink },
202              { "NavLink", Atom::NavLink },
203              { "Nop", Atom::Nop },
204              { "NoteLeft", Atom::NoteLeft },
205              { "NoteRight", Atom::NoteRight },
206              { "ParaLeft", Atom::ParaLeft },
207              { "ParaRight", Atom::ParaRight },
208              { "Qml", Atom::Qml },
209              { "QmlText", Atom::QmlText },
210              { "QuotationLeft", Atom::QuotationLeft },
211              { "QuotationRight", Atom::QuotationRight },
212              { "RawString", Atom::RawString },
213              { "SectionLeft", Atom::SectionLeft },
214              { "SectionRight", Atom::SectionRight },
215              { "SectionHeadingLeft", Atom::SectionHeadingLeft },
216              { "SectionHeadingRight", Atom::SectionHeadingRight },
217              { "SidebarLeft", Atom::SidebarLeft },
218              { "SidebarRight", Atom::SidebarRight },
219              { "SinceList", Atom::SinceList },
220              { "SinceTagLeft", Atom::SinceTagLeft },
221              { "SinceTagRight", Atom::SinceTagRight },
222              { "SnippetCommand", Atom::SnippetCommand },
223              { "SnippetIdentifier", Atom::SnippetIdentifier },
224              { "SnippetLocation", Atom::SnippetLocation },
225              { "String", Atom::String },
226              { "TableLeft", Atom::TableLeft },
227              { "TableRight", Atom::TableRight },
228              { "TableHeaderLeft", Atom::TableHeaderLeft },
229              { "TableHeaderRight", Atom::TableHeaderRight },
230              { "TableRowLeft", Atom::TableRowLeft },
231              { "TableRowRight", Atom::TableRowRight },
232              { "TableItemLeft", Atom::TableItemLeft },
233              { "TableItemRight", Atom::TableItemRight },
234              { "TableOfContents", Atom::TableOfContents },
235              { "Target", Atom::Target },
236              { "UnhandledFormat", Atom::UnhandledFormat },
237              { "UnknownCommand", Atom::UnknownCommand },
238              { nullptr, 0 } };
239 
240 /*! \fn Atom::Atom(AtomType type, const QString &string)
241 
242   Constructs an atom of the specified \a type with the single
243   parameter \a string and does not put the new atom in a list.
244 */
245 
246 /*! \fn Atom::Atom(AtomType type, const QString &p1, const QString &p2)
247 
248   Constructs an atom of the specified \a type with the two
249   parameters \a p1 and \a p2 and does not put the new atom
250   in a list.
251 */
252 
253 /*! \fn Atom(Atom *previous, AtomType type, const QString &string)
254 
255   Constructs an atom of the specified \a type with the single
256   parameter \a string and inserts the new atom into the list
257   after the \a previous atom.
258 */
259 
260 /*! \fn Atom::Atom(Atom *previous, AtomType type, const QString &p1, const QString &p2)
261 
262   Constructs an atom of the specified \a type with the two
263   parameters \a p1 and \a p2 and inserts the new atom into
264   the list after the \a previous atom.
265 */
266 
267 /*! \fn void Atom::appendChar(QChar ch)
268 
269   Appends \a ch to the string parameter of this atom.
270 
271   \also string()
272 */
273 
274 /*! \fn void Atom::appendString(const QString &string)
275 
276   Appends \a string to the string parameter of this atom.
277 
278   \also string()
279 */
280 
281 /*! \fn void Atom::chopString()
282 
283   \also string()
284 */
285 
286 /*! \fn Atom *Atom::next()
287   Return the next atom in the atom list.
288   \also type(), string()
289 */
290 
291 /*!
292   Return the next Atom in the list if it is of AtomType \a t.
293   Otherwise return 0.
294  */
next(AtomType t) const295 const Atom *Atom::next(AtomType t) const
296 {
297     return (next_ && (next_->type() == t)) ? next_ : nullptr;
298 }
299 
300 /*!
301   Return the next Atom in the list if it is of AtomType \a t
302   and its string part is \a s. Otherwise return 0.
303  */
next(AtomType t,const QString & s) const304 const Atom *Atom::next(AtomType t, const QString &s) const
305 {
306     return (next_ && (next_->type() == t) && (next_->string() == s)) ? next_ : nullptr;
307 }
308 
309 /*! \fn const Atom *Atom::next() const
310   Return the next atom in the atom list.
311   \also type(), string()
312 */
313 
314 /*! \fn AtomType Atom::type() const
315   Return the type of this atom.
316   \also string(), next()
317 */
318 
319 /*!
320   Return the type of this atom as a string. Return "Invalid" if
321   type() returns an impossible value.
322 
323   This is only useful for debugging.
324 
325   \also type()
326 */
typeString() const327 QString Atom::typeString() const
328 {
329     static bool deja = false;
330 
331     if (!deja) {
332         int i = 0;
333         while (atms[i].english != nullptr) {
334             if (atms[i].no != i)
335                 Location::internalError(
336                         QCoreApplication::translate("QDoc::Atom", "atom %1 missing").arg(i));
337             ++i;
338         }
339         deja = true;
340     }
341 
342     int i = static_cast<int>(type());
343     if (i < 0 || i > static_cast<int>(Last))
344         return QLatin1String("Invalid");
345     return QLatin1String(atms[i].english);
346 }
347 
348 /*! \fn const QString &Atom::string() const
349 
350   Returns the string parameter that together with the type
351   characterizes this atom.
352 
353   \also type(), next()
354 */
355 
356 /*!
357   Dumps this Atom to stderr in printer friendly form.
358  */
dump() const359 void Atom::dump() const
360 {
361     QString str = string();
362     str.replace(QLatin1String("\\"), QLatin1String("\\\\"));
363     str.replace(QLatin1String("\""), QLatin1String("\\\""));
364     str.replace(QLatin1String("\n"), QLatin1String("\\n"));
365     str.replace(QRegExp(QLatin1String("[^\x20-\x7e]")), QLatin1String("?"));
366     if (!str.isEmpty())
367         str = QLatin1String(" \"") + str + QLatin1Char('"');
368     fprintf(stderr, "    %-15s%s\n", typeString().toLatin1().data(), str.toLatin1().data());
369 }
370 
371 /*!
372   The only constructor for LinkAtom. It creates an Atom of
373   type Atom::Link. \a p1 being the link target. \a p2 is the
374   parameters in square brackets. Normally there is just one
375   word in the square brackets, but there can be up to three
376   words separated by spaces. The constructor splits \a p2 on
377   the space character.
378  */
LinkAtom(const QString & p1,const QString & p2)379 LinkAtom::LinkAtom(const QString &p1, const QString &p2)
380     : Atom(Atom::Link, p1),
381       resolved_(false),
382       genus_(Node::DontCare),
383       goal_(Node::NoType),
384       domain_(nullptr),
385       squareBracketParams_(p2)
386 {
387     // nada.
388 }
389 
390 /*!
391   This function resolves the parameters that were enclosed in
392   square brackets. If the parameters have already been resolved,
393   it does nothing and returns immediately.
394  */
resolveSquareBracketParams()395 void LinkAtom::resolveSquareBracketParams()
396 {
397     if (resolved_)
398         return;
399     const QStringList params = squareBracketParams_.toLower().split(QLatin1Char(' '));
400     for (const auto &param : params) {
401         if (!domain_) {
402             domain_ = QDocDatabase::qdocDB()->findTree(param);
403             if (domain_) {
404                 continue;
405             }
406         }
407         if (goal_ == Node::NoType) {
408             goal_ = Node::goal(param);
409             if (goal_ != Node::NoType)
410                 continue;
411         }
412         if (param == "qml") {
413             genus_ = Node::QML;
414             continue;
415         }
416         if (param == "cpp") {
417             genus_ = Node::CPP;
418             continue;
419         }
420         if (param == "doc") {
421             genus_ = Node::DOC;
422             continue;
423         }
424         error_ = squareBracketParams_;
425         break;
426     }
427     resolved_ = true;
428 }
429 
430 /*!
431   Standard copy constructor of LinkAtom \a t.
432  */
LinkAtom(const LinkAtom & t)433 LinkAtom::LinkAtom(const LinkAtom &t)
434     : Atom(Link, t.string()),
435       resolved_(t.resolved_),
436       genus_(t.genus_),
437       goal_(t.goal_),
438       domain_(t.domain_),
439       error_(t.error_),
440       squareBracketParams_(t.squareBracketParams_)
441 {
442     // nothing
443 }
444 
445 /*!
446   Special copy constructor of LinkAtom \a t, where
447   where the new LinkAtom will not be the first one
448   in the list.
449  */
LinkAtom(Atom * previous,const LinkAtom & t)450 LinkAtom::LinkAtom(Atom *previous, const LinkAtom &t)
451     : Atom(previous, Link, t.string()),
452       resolved_(t.resolved_),
453       genus_(t.genus_),
454       goal_(t.goal_),
455       domain_(t.domain_),
456       error_(t.error_),
457       squareBracketParams_(t.squareBracketParams_)
458 {
459     previous->next_ = this;
460 }
461 
462 QT_END_NAMESPACE
463