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 ¶m : 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