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 /*
30 text.cpp
31 */
32
33 #include "text.h"
34
35 #include <QtCore/qregexp.h>
36
37 #include <stdio.h>
38
39 QT_BEGIN_NAMESPACE
40
Text()41 Text::Text() : first(nullptr), last(nullptr) {}
42
Text(const QString & str)43 Text::Text(const QString &str) : first(nullptr), last(nullptr)
44 {
45 operator<<(str);
46 }
47
Text(const Text & text)48 Text::Text(const Text &text) : first(nullptr), last(nullptr)
49 {
50 operator=(text);
51 }
52
~Text()53 Text::~Text()
54 {
55 clear();
56 }
57
operator =(const Text & text)58 Text &Text::operator=(const Text &text)
59 {
60 if (this != &text) {
61 clear();
62 operator<<(text);
63 }
64 return *this;
65 }
66
operator <<(Atom::AtomType atomType)67 Text &Text::operator<<(Atom::AtomType atomType)
68 {
69 return operator<<(Atom(atomType));
70 }
71
operator <<(const QString & string)72 Text &Text::operator<<(const QString &string)
73 {
74 return operator<<(Atom(Atom::String, string));
75 }
76
operator <<(const Atom & atom)77 Text &Text::operator<<(const Atom &atom)
78 {
79 if (atom.count() < 2) {
80 if (first == nullptr) {
81 first = new Atom(atom.type(), atom.string());
82 last = first;
83 } else
84 last = new Atom(last, atom.type(), atom.string());
85 } else {
86 if (first == nullptr) {
87 first = new Atom(atom.type(), atom.string(), atom.string(1));
88 last = first;
89 } else
90 last = new Atom(last, atom.type(), atom.string(), atom.string(1));
91 }
92 return *this;
93 }
94
95 /*!
96 Special output operator for LinkAtom. It makes a copy of
97 the LinkAtom \a atom and connects the cop;y to the list
98 in this Text.
99 */
operator <<(const LinkAtom & atom)100 Text &Text::operator<<(const LinkAtom &atom)
101 {
102 if (first == nullptr) {
103 first = new LinkAtom(atom);
104 last = first;
105 } else
106 last = new LinkAtom(last, atom);
107 return *this;
108 }
109
operator <<(const Text & text)110 Text &Text::operator<<(const Text &text)
111 {
112 const Atom *atom = text.firstAtom();
113 while (atom != nullptr) {
114 operator<<(*atom);
115 atom = atom->next();
116 }
117 return *this;
118 }
119
stripFirstAtom()120 void Text::stripFirstAtom()
121 {
122 if (first != nullptr) {
123 if (first == last)
124 last = nullptr;
125 Atom *oldFirst = first;
126 first = first->next();
127 delete oldFirst;
128 }
129 }
130
stripLastAtom()131 void Text::stripLastAtom()
132 {
133 if (last != nullptr) {
134 Atom *oldLast = last;
135 if (first == last) {
136 first = nullptr;
137 last = nullptr;
138 } else {
139 last = first;
140 while (last->next() != oldLast)
141 last = last->next();
142 last->setNext(nullptr);
143 }
144 delete oldLast;
145 }
146 }
147
148 /*!
149 This function traverses the atom list of the Text object,
150 extracting all the string parts. It concatenates them to
151 a result string and returns it.
152 */
toString() const153 QString Text::toString() const
154 {
155 QString str;
156 const Atom *atom = firstAtom();
157 while (atom != nullptr) {
158 if (atom->type() == Atom::String || atom->type() == Atom::AutoLink
159 || atom->type() == Atom::C)
160 str += atom->string();
161 atom = atom->next();
162 }
163 return str;
164 }
165
166 /*!
167 Returns true if this Text contains the substring \a str.
168 */
contains(const QString & str) const169 bool Text::contains(const QString &str) const
170 {
171 const Atom *atom = firstAtom();
172 while (atom != nullptr) {
173 if (atom->type() == Atom::String || atom->type() == Atom::AutoLink
174 || atom->type() == Atom::C)
175 if (atom->string().contains(str, Qt::CaseInsensitive))
176 return true;
177 atom = atom->next();
178 }
179 return false;
180 }
181
subText(Atom::AtomType left,Atom::AtomType right,const Atom * from,bool inclusive) const182 Text Text::subText(Atom::AtomType left, Atom::AtomType right, const Atom *from,
183 bool inclusive) const
184 {
185 const Atom *begin = from ? from : firstAtom();
186 const Atom *end;
187
188 while (begin != nullptr && begin->type() != left)
189 begin = begin->next();
190 if (begin != nullptr) {
191 if (!inclusive)
192 begin = begin->next();
193 }
194
195 end = begin;
196 while (end != nullptr && end->type() != right)
197 end = end->next();
198 if (end == nullptr)
199 begin = nullptr;
200 else if (inclusive)
201 end = end->next();
202 return subText(begin, end);
203 }
204
sectionHeading(const Atom * sectionLeft)205 Text Text::sectionHeading(const Atom *sectionLeft)
206 {
207 if (sectionLeft != nullptr) {
208 const Atom *begin = sectionLeft;
209 while (begin != nullptr && begin->type() != Atom::SectionHeadingLeft)
210 begin = begin->next();
211 if (begin != nullptr)
212 begin = begin->next();
213
214 const Atom *end = begin;
215 while (end != nullptr && end->type() != Atom::SectionHeadingRight)
216 end = end->next();
217
218 if (end != nullptr)
219 return subText(begin, end);
220 }
221 return Text();
222 }
223
sectionHeadingAtom(const Atom * sectionLeft)224 const Atom *Text::sectionHeadingAtom(const Atom *sectionLeft)
225 {
226 if (sectionLeft != nullptr) {
227 const Atom *begin = sectionLeft;
228 while (begin != nullptr && begin->type() != Atom::SectionHeadingLeft)
229 begin = begin->next();
230 if (begin != nullptr)
231 begin = begin->next();
232
233 return begin;
234 }
235 return nullptr;
236 }
237
dump() const238 void Text::dump() const
239 {
240 const Atom *atom = firstAtom();
241 while (atom != nullptr) {
242 QString str = atom->string();
243 str.replace("\\", "\\\\");
244 str.replace("\"", "\\\"");
245 str.replace("\n", "\\n");
246 str.replace(QRegExp("[^\x20-\x7e]"), "?");
247 if (!str.isEmpty())
248 str = " \"" + str + QLatin1Char('"');
249 fprintf(stderr, " %-15s%s\n", atom->typeString().toLatin1().data(),
250 str.toLatin1().data());
251 atom = atom->next();
252 }
253 }
254
subText(const Atom * begin,const Atom * end)255 Text Text::subText(const Atom *begin, const Atom *end)
256 {
257 Text text;
258 if (begin != nullptr) {
259 while (begin != end) {
260 text << *begin;
261 begin = begin->next();
262 }
263 }
264 return text;
265 }
266
clear()267 void Text::clear()
268 {
269 while (first != nullptr) {
270 Atom *atom = first;
271 first = first->next();
272 delete atom;
273 }
274 first = nullptr;
275 last = nullptr;
276 }
277
compare(const Text & text1,const Text & text2)278 int Text::compare(const Text &text1, const Text &text2)
279 {
280 if (text1.isEmpty())
281 return text2.isEmpty() ? 0 : -1;
282 if (text2.isEmpty())
283 return 1;
284
285 const Atom *atom1 = text1.firstAtom();
286 const Atom *atom2 = text2.firstAtom();
287
288 for (;;) {
289 if (atom1->type() != atom2->type())
290 return (int)atom1->type() - (int)atom2->type();
291 int cmp = QString::compare(atom1->string(), atom2->string());
292 if (cmp != 0)
293 return cmp;
294
295 if (atom1 == text1.lastAtom())
296 return atom2 == text2.lastAtom() ? 0 : -1;
297 if (atom2 == text2.lastAtom())
298 return 1;
299 atom1 = atom1->next();
300 atom2 = atom2->next();
301 }
302 }
303
304 QT_END_NAMESPACE
305