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