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 */ 295 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 */ 304 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 */ 327 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 */ 359 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 */ 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 */ 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 */ 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 */ 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