blob: b3e3b410683551b9c6ead277c6756406a8a37c12 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the tools applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** 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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
/*
text.cpp
*/
#include "text.h"
#include <QtCore/qregexp.h>
#include <stdio.h>
QT_BEGIN_NAMESPACE
Text::Text() : first(nullptr), last(nullptr) {}
Text::Text(const QString &str) : first(nullptr), last(nullptr)
{
operator<<(str);
}
Text::Text(const Text &text) : first(nullptr), last(nullptr)
{
operator=(text);
}
Text::~Text()
{
clear();
}
Text &Text::operator=(const Text &text)
{
if (this != &text) {
clear();
operator<<(text);
}
return *this;
}
Text &Text::operator<<(Atom::AtomType atomType)
{
return operator<<(Atom(atomType));
}
Text &Text::operator<<(const QString &string)
{
return operator<<(Atom(Atom::String, string));
}
Text &Text::operator<<(const Atom &atom)
{
if (atom.count() < 2) {
if (first == nullptr) {
first = new Atom(atom.type(), atom.string());
last = first;
} else
last = new Atom(last, atom.type(), atom.string());
} else {
if (first == nullptr) {
first = new Atom(atom.type(), atom.string(), atom.string(1));
last = first;
} else
last = new Atom(last, atom.type(), atom.string(), atom.string(1));
}
return *this;
}
/*!
Special output operator for LinkAtom. It makes a copy of
the LinkAtom \a atom and connects the cop;y to the list
in this Text.
*/
Text &Text::operator<<(const LinkAtom &atom)
{
if (first == nullptr) {
first = new LinkAtom(atom);
last = first;
} else
last = new LinkAtom(last, atom);
return *this;
}
Text &Text::operator<<(const Text &text)
{
const Atom *atom = text.firstAtom();
while (atom != nullptr) {
operator<<(*atom);
atom = atom->next();
}
return *this;
}
void Text::stripFirstAtom()
{
if (first != nullptr) {
if (first == last)
last = nullptr;
Atom *oldFirst = first;
first = first->next();
delete oldFirst;
}
}
void Text::stripLastAtom()
{
if (last != nullptr) {
Atom *oldLast = last;
if (first == last) {
first = nullptr;
last = nullptr;
} else {
last = first;
while (last->next() != oldLast)
last = last->next();
last->setNext(nullptr);
}
delete oldLast;
}
}
/*!
This function traverses the atom list of the Text object,
extracting all the string parts. It concatenates them to
a result string and returns it.
*/
QString Text::toString() const
{
QString str;
const Atom *atom = firstAtom();
while (atom != nullptr) {
if (atom->type() == Atom::String || atom->type() == Atom::AutoLink
|| atom->type() == Atom::C)
str += atom->string();
atom = atom->next();
}
return str;
}
/*!
Returns true if this Text contains the substring \a str.
*/
bool Text::contains(const QString &str) const
{
const Atom *atom = firstAtom();
while (atom != nullptr) {
if (atom->type() == Atom::String || atom->type() == Atom::AutoLink
|| atom->type() == Atom::C)
if (atom->string().contains(str, Qt::CaseInsensitive))
return true;
atom = atom->next();
}
return false;
}
Text Text::subText(Atom::AtomType left, Atom::AtomType right, const Atom *from,
bool inclusive) const
{
const Atom *begin = from ? from : firstAtom();
const Atom *end;
while (begin != nullptr && begin->type() != left)
begin = begin->next();
if (begin != nullptr) {
if (!inclusive)
begin = begin->next();
}
end = begin;
while (end != nullptr && end->type() != right)
end = end->next();
if (end == nullptr)
begin = nullptr;
else if (inclusive)
end = end->next();
return subText(begin, end);
}
Text Text::sectionHeading(const Atom *sectionLeft)
{
if (sectionLeft != nullptr) {
const Atom *begin = sectionLeft;
while (begin != nullptr && begin->type() != Atom::SectionHeadingLeft)
begin = begin->next();
if (begin != nullptr)
begin = begin->next();
const Atom *end = begin;
while (end != nullptr && end->type() != Atom::SectionHeadingRight)
end = end->next();
if (end != nullptr)
return subText(begin, end);
}
return Text();
}
const Atom *Text::sectionHeadingAtom(const Atom *sectionLeft)
{
if (sectionLeft != nullptr) {
const Atom *begin = sectionLeft;
while (begin != nullptr && begin->type() != Atom::SectionHeadingLeft)
begin = begin->next();
if (begin != nullptr)
begin = begin->next();
return begin;
}
return nullptr;
}
void Text::dump() const
{
const Atom *atom = firstAtom();
while (atom != nullptr) {
QString str = atom->string();
str.replace("\\", "\\\\");
str.replace("\"", "\\\"");
str.replace("\n", "\\n");
str.replace(QRegExp("[^\x20-\x7e]"), "?");
if (!str.isEmpty())
str = " \"" + str + QLatin1Char('"');
fprintf(stderr, " %-15s%s\n", atom->typeString().toLatin1().data(),
str.toLatin1().data());
atom = atom->next();
}
}
Text Text::subText(const Atom *begin, const Atom *end)
{
Text text;
if (begin != nullptr) {
while (begin != end) {
text << *begin;
begin = begin->next();
}
}
return text;
}
void Text::clear()
{
while (first != nullptr) {
Atom *atom = first;
first = first->next();
delete atom;
}
first = nullptr;
last = nullptr;
}
int Text::compare(const Text &text1, const Text &text2)
{
if (text1.isEmpty())
return text2.isEmpty() ? 0 : -1;
if (text2.isEmpty())
return 1;
const Atom *atom1 = text1.firstAtom();
const Atom *atom2 = text2.firstAtom();
for (;;) {
if (atom1->type() != atom2->type())
return (int)atom1->type() - (int)atom2->type();
int cmp = QString::compare(atom1->string(), atom2->string());
if (cmp != 0)
return cmp;
if (atom1 == text1.lastAtom())
return atom2 == text2.lastAtom() ? 0 : -1;
if (atom2 == text2.lastAtom())
return 1;
atom1 = atom1->next();
atom2 = atom2->next();
}
}
QT_END_NAMESPACE