1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2
3 /*
4 Rosegarden
5 A sequencer and musical notation editor.
6 Copyright 2000-2021 the Rosegarden development team.
7 See the AUTHORS file for more details.
8
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2 of the
12 License, or (at your option) any later version. See the file
13 COPYING included with this distribution for more information.
14 */
15
16 #include "Strings.h"
17
18 #include "base/Composition.h"
19 #include "base/Segment.h"
20 #include "base/Event.h"
21
22 #include <QTextCodec>
23 #include <QVariant>
24 #include <QString>
25
26 namespace Rosegarden
27 {
28
strtoqstr(const std::string & str)29 ROSEGARDENPRIVATE_EXPORT QString strtoqstr(const std::string &str)
30 {
31 return QString::fromUtf8(str.c_str());
32 }
33
strtoqstr(const Rosegarden::PropertyName & p)34 ROSEGARDENPRIVATE_EXPORT QString strtoqstr(const Rosegarden::PropertyName &p)
35 {
36 return QString::fromUtf8(p.getName().c_str());
37 }
38
qstrtostr(const QString & qstr)39 ROSEGARDENPRIVATE_EXPORT std::string qstrtostr(const QString &qstr)
40 {
41 return std::string(qstr.toUtf8().data());
42 }
43
qStrToStrUtf8(const QString & qstr)44 ROSEGARDENPRIVATE_EXPORT std::string qStrToStrUtf8(const QString &qstr)
45 {
46 return qstrtostr(qstr);
47 }
48
qStrToStrLocal8(const QString & qstr)49 ROSEGARDENPRIVATE_EXPORT std::string qStrToStrLocal8(const QString &qstr)
50 {
51 return std::string(qstr.toLocal8Bit().data());
52 }
53
54
55 /**
56 * Unlike strtod(3) or QString::toDouble(), this is locale-independent
57 * and always uses '.' as a decimal point. We use it when reading
58 * things like configuration values from XML files where we want to
59 * guarantee the same value is used regardless of surrounding locale.
60 */
strtodouble(const std::string & s)61 ROSEGARDENPRIVATE_EXPORT double strtodouble(const std::string &s)
62 {
63 int dp = 0;
64 int sign = 1;
65 size_t i = 0; //@@@
66 double result = 0.0;
67 size_t len = s.length();
68
69 result = 0.0;
70
71 while (i < len && isspace(s[i]))
72 ++i;
73
74 if (i < len && s[i] == '-')
75 sign = -1;
76
77 while (i < len) {
78
79 char c = s[i];
80
81 if (isdigit(c)) {
82
83 double d = c - '0';
84
85 if (dp > 0) {
86 for (int p = dp; p > 0; --p)
87 d /= 10.0;
88 ++dp;
89 } else {
90 result *= 10.0;
91 }
92
93 result += d;
94
95 } else if (c == '.') {
96 dp = 1;
97 }
98
99 ++i;
100 }
101
102 return result * sign;
103 }
104
qstrtodouble(const QString & s)105 ROSEGARDENPRIVATE_EXPORT double qstrtodouble(const QString &s)
106 {
107 return strtodouble(qstrtostr(s));
108 }
109
qStrToBool(const QVariant & v)110 ROSEGARDENPRIVATE_EXPORT bool qStrToBool(const QVariant &v)
111 {
112 QString tt = v.toString().toLower().trimmed();
113
114 if (tt == "1" || tt == "true" || tt == "yes" || tt == "on")
115 return true;
116
117 return false;
118 }
119
convertFromCodec(std::string text,QTextCodec * codec)120 ROSEGARDENPRIVATE_EXPORT std::string convertFromCodec(std::string text, QTextCodec *codec)
121 {
122 if (codec)
123 return qstrtostr(codec->toUnicode(text.c_str(), text.length()));
124 else
125 return text;
126 }
127
operator <<(std::ostream & target,const QString & str)128 ROSEGARDENPRIVATE_EXPORT std::ostream &operator<<(std::ostream &target, const QString &str)
129 {
130 return target << str.toLocal8Bit().data();
131 }
132
operator <<(QTextStream & target,const std::string & str)133 ROSEGARDENPRIVATE_EXPORT QTextStream &operator<<(QTextStream &target, const std::string &str)
134 {
135 return target << QString(str.c_str());
136 }
137
splitQuotedString(QString s)138 ROSEGARDENPRIVATE_EXPORT QStringList splitQuotedString(QString s)
139 {
140 QStringList tokens;
141 QString tok;
142
143 enum { sep, unq, q1, q2 } mode = sep;
144
145 for (int i = 0; i < s.length(); ++i) {
146
147 QChar c = s[i];
148
149 if (c == '\'') {
150 switch (mode) {
151 case sep: mode = q1; break;
152 case unq: case q2: tok += c; break;
153 case q1: mode = sep; tokens << tok; tok = ""; break;
154 }
155
156 } else if (c == '"') {
157 switch (mode) {
158 case sep: mode = q2; break;
159 case unq: case q1: tok += c; break;
160 case q2: mode = sep; tokens << tok; tok = ""; break;
161 }
162
163 } else if (c.isSpace()) {
164 switch (mode) {
165 case sep: break;
166 case unq: mode = sep; tokens << tok; tok = ""; break;
167 case q1: case q2: tok += c; break;
168 }
169
170 } else if (c == '\\') {
171 if (++i < s.length()) {
172 c = s[i];
173 switch (mode) {
174 case sep: mode = unq; tok += c; break;
175
176 // All fall thru to default.
177 case unq:
178 case q1:
179 case q2:
180 default: tok += c; break;
181 }
182 }
183
184 } else {
185 switch (mode) {
186 case sep: mode = unq; tok += c; break;
187
188 // All fall thru to default.
189 case unq:
190 case q1:
191 case q2:
192 default: tok += c; break;
193 }
194 }
195 }
196
197 if (tok != "" || mode != sep) tokens << tok;
198 return tokens;
199 }
200
201 /*
202
203 void testSplit()
204 {
205 QStringList tests;
206 tests << "a b c d";
207 tests << "a \"b c\" d";
208 tests << "a 'b c' d";
209 tests << "a \"b c\\\" d\"";
210 tests << "a 'b c\\' d'";
211 tests << "a \"b c' d\"";
212 tests << "a 'b c\" d'";
213 tests << "aa 'bb cc\" dd'";
214 tests << "a'a 'bb' \\\"cc\" dd\\\"";
215 tests << " a'a \\\' 'bb' \' \\\"cc\" ' dd\\\" '";
216
217 for (int j = 0; j < tests.size(); ++j) {
218 cout << endl;
219 cout << tests[j].toStdString() << endl;
220 cout << "->" << endl << "(";
221 QStringList l = splitQuoted(tests[j]);
222 for (int i = 0; i < l.size(); ++i) {
223 if (i > 0) cout << ";";
224 cout << l[i].toStdString();
225 }
226 cout << ")" << endl;
227 }
228 }
229
230 */
231
232 /*
233 Results:
234
235 a b c d
236 ->
237 (a;b;c;d)
238
239 a "b c" d
240 ->
241 (a;b c;d)
242
243 a 'b c' d
244 ->
245 (a;b c;d)
246
247 a "b c\" d"
248 ->
249 (a;b c" d)
250
251 a 'b c\' d'
252 ->
253 (a;b c' d)
254
255 a "b c' d"
256 ->
257 (a;b c' d)
258
259 a 'b c" d'
260 ->
261 (a;b c" d)
262
263 aa 'bb cc" dd'
264 ->
265 (aa;bb cc" dd)
266
267 a'a 'bb' \"cc" dd\"
268 ->
269 (a'a;bb;"cc";dd")
270
271 a'a \' 'bb' ' \"cc" ' dd\" '
272 ->
273 (a'a;';bb; "cc" ;dd";)
274
275 */
276
277 }
278
279