1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "metastrings.h"
5
6namespace {
7using namespace Qt::Literals::StringLiterals;
8
9static constexpr QLatin1String CppMagicComment = "TRANSLATOR"_L1;
10} // namespace
11
12QT_BEGIN_NAMESPACE
13
14bool MetaStrings::parse(QString &string)
15{
16 const QChar *ptr = string.unicode();
17 if (*ptr == u':' && ptr[1].isSpace()) {
18 string.remove(i: 0, len: 2);
19 m_extracomment += string;
20 if (!m_extracomment.endsWith(c: u'\n'))
21 m_extracomment.push_back(c: u'\n');
22 m_extracomment.detach();
23 } else if (*ptr == u'=' && ptr[1].isSpace()) {
24 string.remove(i: 0, len: 2);
25 m_msgid = string.simplified();
26 m_msgid.detach();
27 } else if (*ptr == u'~' && ptr[1].isSpace()) {
28 string.remove(i: 0, len: 2);
29 const QString trimmed = string.trimmed();
30 int k = trimmed.indexOf(ch: u' ');
31 if (k > -1) {
32 QString commentvalue = trimmed.mid(position: k + 1).trimmed();
33 if (commentvalue.startsWith(c: u'"') && commentvalue.endsWith(c: u'"')
34 && commentvalue.size() != 1) {
35 commentvalue = commentvalue.sliced(pos: 1, n: commentvalue.size() - 2);
36 }
37 m_extra.insert(key: trimmed.left(n: k), value: commentvalue);
38 }
39 } else if (*ptr == u'%' && ptr[1].isSpace()) {
40 m_sourcetext.reserve(asize: m_sourcetext.size() + string.size() - 2);
41 ushort *ptr = (ushort *)m_sourcetext.data() + m_sourcetext.size();
42 int p = 2, c;
43 forever {
44 if (p >= string.size())
45 break;
46 c = string.unicode()[p++].unicode();
47 if (isspace(c))
48 continue;
49 if (c != '"') {
50 m_error = "Unexpected character in meta string\n"_L1;
51 break;
52 }
53 forever {
54 if (p >= string.size()) {
55 whoops:
56 m_error = "Unterminated meta string\n"_L1;
57 break;
58 }
59 c = string.unicode()[p++].unicode();
60 if (c == '"')
61 break;
62 if (c == '\\') {
63 if (p >= string.size())
64 goto whoops;
65 c = string.unicode()[p++].unicode();
66 if (c == '\n')
67 goto whoops;
68 *ptr++ = '\\';
69 }
70 *ptr++ = c;
71 }
72 }
73 m_sourcetext.resize(size: ptr - (ushort *)m_sourcetext.data());
74 } else if (*ptr == u'@' && ptr[1].isSpace()) {
75 string.remove(i: 0, len: 2);
76 m_label = string.trimmed().simplified();
77 m_label.detach();
78 } else if (const QString trimmed = string.trimmed(); trimmed.startsWith(s: CppMagicComment)) {
79 qsizetype idx = CppMagicComment.size();
80 QString comment =
81 QString::fromRawData(unicode: trimmed.unicode() + idx, size: trimmed.size() - idx).simplified();
82 if (int k = comment.indexOf(ch: u' '); k != -1) {
83 QString context = comment.left(n: k);
84 comment.remove(i: 0, len: k + 1);
85 m_magicComment.emplace(args: MagicComment{ .context: std::move(context), .comment: std::move(comment) });
86 }
87 }
88
89 return m_error.isEmpty();
90}
91
92void MetaStrings::clear()
93{
94 m_magicComment.reset();
95 m_extracomment.clear();
96 m_msgid.clear();
97 m_label.clear();
98 m_sourcetext.clear();
99 m_extra.clear();
100}
101
102bool MetaStrings::hasData() const
103{
104 return !m_msgid.isEmpty() || m_magicComment || !m_sourcetext.isEmpty()
105 || !m_extracomment.isEmpty() || !m_extra.isEmpty() || !m_label.isEmpty();
106}
107
108QT_END_NAMESPACE
109

source code of qttools/src/linguist/lupdate/metastrings.cpp