Don't recurse into MacVST bundle-folders during plugin-scan
[ardour.git] / libs / pbd / string_convert.cc
1 /*
2     Copyright (C) 2015 Tim Mayberry
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include "pbd/string_convert.h"
21
22 #ifndef __STDC_FORMAT_MACROS
23 #define __STDC_FORMAT_MACROS
24 #endif
25 #include <inttypes.h>
26 #include <cerrno>
27 #include <cstdio>
28 #include <limits>
29
30 #include <glib.h>
31 #include <glib/gprintf.h>
32
33 #include "pbd/compose.h"
34 #include "pbd/debug.h"
35 #include "pbd/i18n.h"
36
37 #define DEBUG_SCONVERT(msg) DEBUG_TRACE (PBD::DEBUG::StringConvert, string_compose ("%1: %2\n", __LINE__, msg));
38
39 #define CONVERT_BUF_SIZE 32
40
41 namespace PBD {
42
43 bool string_to_bool (const std::string& str, bool& val)
44 {
45         if (str.empty ()) {
46                 return false;
47
48         } else if (str == X_("1")) {
49                 val = true;
50                 return true;
51
52         } else if (str == X_("0")) {
53                 val = false;
54                 return true;
55
56         } else if (str == X_("y")) {
57                 val = true;
58                 return true;
59
60         } else if (str == X_("n")) {
61                 val = false;
62                 return true;
63
64         } else if (g_ascii_strncasecmp (str.c_str(), X_("yes"), str.length()) == 0) {
65                 val = true;
66                 return true;
67
68         } else if (g_ascii_strncasecmp (str.c_str(), X_("no"), str.length()) == 0) {
69                 val = false;
70                 return true;
71
72         } else if (g_ascii_strncasecmp (str.c_str(), X_("true"), str.length()) == 0) {
73                 val = true;
74                 return true;
75
76         } else if (g_ascii_strncasecmp (str.c_str(), X_("false"), str.length()) == 0) {
77                 val = false;
78                 return true;
79         }
80
81         DEBUG_SCONVERT (
82             string_compose ("string_to_bool conversion failed for %1", str));
83
84         return false;
85 }
86
87 bool string_to_int16 (const std::string& str, int16_t& val)
88 {
89         if (sscanf (str.c_str (), "%" SCNi16, &val) != 1) {
90                 DEBUG_SCONVERT (
91                     string_compose ("string_to_int16 conversion failed for %1", str));
92                 return false;
93         }
94         return true;
95 }
96
97 bool string_to_uint16 (const std::string& str, uint16_t& val)
98 {
99         if (sscanf (str.c_str (), "%" SCNu16, &val) != 1) {
100                 DEBUG_SCONVERT (
101                     string_compose ("string_to_uint16 conversion failed for %1", str));
102                 return false;
103         }
104         return true;
105 }
106
107 bool string_to_int32 (const std::string& str, int32_t& val)
108 {
109         if (sscanf (str.c_str (), "%" SCNi32, &val) != 1) {
110                 DEBUG_SCONVERT (
111                     string_compose ("string_to_int32 conversion failed for %1", str));
112                 return false;
113         }
114         return true;
115 }
116
117 bool string_to_uint32 (const std::string& str, uint32_t& val)
118 {
119         if (sscanf (str.c_str (), "%" SCNu32, &val) != 1) {
120                 DEBUG_SCONVERT (
121                     string_compose ("string_to_uint32 conversion failed for %1", str));
122                 return false;
123         }
124         return true;
125 }
126
127 bool string_to_int64 (const std::string& str, int64_t& val)
128 {
129         if (sscanf (str.c_str (), "%" SCNi64, &val) != 1) {
130                 DEBUG_SCONVERT (
131                     string_compose ("string_to_int64 conversion failed for %1", str));
132                 return false;
133         }
134         return true;
135 }
136
137 bool string_to_uint64 (const std::string& str, uint64_t& val)
138 {
139         if (sscanf (str.c_str (), "%" SCNu64, &val) != 1) {
140                 DEBUG_SCONVERT (
141                     string_compose ("string_to_uint64 conversion failed for %1", str));
142                 return false;
143         }
144         return true;
145 }
146
147 template <class FloatType>
148 static bool
149 _string_to_infinity (const std::string& str, FloatType& val)
150 {
151         if (!g_ascii_strncasecmp (str.c_str (), X_ ("inf"), str.length ()) ||
152             !g_ascii_strncasecmp (str.c_str (), X_ ("+inf"), str.length ()) ||
153             !g_ascii_strncasecmp (str.c_str (), X_ ("INFINITY"), str.length ()) ||
154             !g_ascii_strncasecmp (str.c_str (), X_ ("+INFINITY"), str.length ())) {
155                 val = std::numeric_limits<FloatType>::infinity ();
156                 return true;
157         } else if (!g_ascii_strncasecmp (str.c_str (), X_ ("-inf"), str.length ()) ||
158                    !g_ascii_strncasecmp (str.c_str (), X_ ("-INFINITY"), str.length ())) {
159                 val = -std::numeric_limits<FloatType>::infinity ();
160                 return true;
161         }
162         return false;
163 }
164
165 bool
166 _string_to_double (const std::string& str, double& val)
167 {
168         val = g_ascii_strtod (str.c_str (), NULL);
169
170         // It is possible that the conversion was successful and another thread
171         // has set errno meanwhile but as most conversions are currently not
172         // checked for error conditions this is better than nothing.
173         if (errno == ERANGE) {
174                 DEBUG_SCONVERT (string_compose ("string_to_double possible conversion failure for %1", str));
175                 // There should not be any conversion failures as we control the string
176                 // contents so returning false here should not have any impact...
177                 return false;
178         }
179         return true;
180 }
181
182 bool string_to_float (const std::string& str, float& val)
183 {
184         double tmp;
185         if (_string_to_double (str, tmp)) {
186                 val = (float)tmp;
187                 return true;
188         }
189
190         if (_string_to_infinity (str, val)) {
191                 return true;
192         }
193
194         return false;
195 }
196
197 bool string_to_double (const std::string& str, double& val)
198 {
199         if (_string_to_double (str, val)) {
200                 return true;
201         }
202
203         if (_string_to_infinity (str, val)) {
204                 return true;
205         }
206
207         return false;
208 }
209
210 bool bool_to_string (bool val, std::string& str)
211 {
212         if (val) {
213                 str = X_("1");
214         } else {
215                 str = X_("0");
216         }
217         return true;
218 }
219
220 bool int16_to_string (int16_t val, std::string& str)
221 {
222         char buffer[CONVERT_BUF_SIZE];
223
224         int retval = g_snprintf (buffer, sizeof(buffer), "%" PRIi16, val);
225
226         if (retval <= 0 || retval >= (int)sizeof(buffer)) {
227                 DEBUG_SCONVERT (
228                     string_compose ("int16_to_string conversion failure for %1", val));
229                 return false;
230         }
231         str = buffer;
232         return true;
233 }
234
235 bool uint16_to_string (uint16_t val, std::string& str)
236 {
237         char buffer[CONVERT_BUF_SIZE];
238
239         int retval = g_snprintf (buffer, sizeof(buffer), "%" PRIu16, val);
240
241         if (retval <= 0 || retval >= (int)sizeof(buffer)) {
242                 DEBUG_SCONVERT (
243                     string_compose ("uint16_to_string conversion failure for %1", val));
244                 return false;
245         }
246         str = buffer;
247         return true;
248 }
249
250 bool int32_to_string (int32_t val, std::string& str)
251 {
252         char buffer[CONVERT_BUF_SIZE];
253
254         int retval = g_snprintf (buffer, sizeof(buffer), "%" PRIi32, val);
255
256         if (retval <= 0 || retval >= (int)sizeof(buffer)) {
257                 DEBUG_SCONVERT (
258                     string_compose ("int32_to_string conversion failure for %1", val));
259                 return false;
260         }
261         str = buffer;
262         return true;
263 }
264
265 bool uint32_to_string (uint32_t val, std::string& str)
266 {
267         char buffer[CONVERT_BUF_SIZE];
268
269         int retval = g_snprintf (buffer, sizeof(buffer), "%" PRIu32, val);
270
271         if (retval <= 0 || retval >= (int)sizeof(buffer)) {
272                 DEBUG_SCONVERT (
273                     string_compose ("uint32_to_string conversion failure for %1", val));
274                 return false;
275         }
276         str = buffer;
277         return true;
278 }
279
280 bool int64_to_string (int64_t val, std::string& str)
281 {
282         char buffer[CONVERT_BUF_SIZE];
283
284         int retval = g_snprintf (buffer, sizeof(buffer), "%" PRIi64, val);
285
286         if (retval <= 0 || retval >= (int)sizeof(buffer)) {
287                 DEBUG_SCONVERT (
288                     string_compose ("int64_to_string conversion failure for %1", val));
289                 return false;
290         }
291         str = buffer;
292         return true;
293 }
294
295 bool uint64_to_string (uint64_t val, std::string& str)
296 {
297         char buffer[CONVERT_BUF_SIZE];
298
299         int retval = g_snprintf (buffer, sizeof(buffer), "%" PRIu64, val);
300
301         if (retval <= 0 || retval >= (int)sizeof(buffer)) {
302                 DEBUG_SCONVERT (
303                     string_compose ("uint64_to_string conversion failure for %1", val));
304                 return false;
305         }
306         str = buffer;
307         return true;
308 }
309
310 template <class FloatType>
311 static bool
312 _infinity_to_string (FloatType val, std::string& str)
313 {
314         if (val == std::numeric_limits<FloatType>::infinity ()) {
315                 str = "inf";
316                 return true;
317         } else if (val == -std::numeric_limits<FloatType>::infinity ()) {
318                 str = "-inf";
319                 return true;
320         }
321         return false;
322 }
323
324 static bool
325 _double_to_string (double val, std::string& str)
326 {
327         char buffer[G_ASCII_DTOSTR_BUF_SIZE];
328
329         char* d_cstr = g_ascii_dtostr (buffer, sizeof(buffer), val);
330
331         if (d_cstr == NULL) {
332                 return false;
333         }
334         str = d_cstr;
335         return true;
336 }
337
338 bool float_to_string (float val, std::string& str)
339 {
340         if (_infinity_to_string (val, str)) {
341                 return true;
342         }
343
344         if (_double_to_string (val, str)) {
345                 return true;
346         }
347
348         DEBUG_SCONVERT (string_compose ("float_to_string conversion failure for %1", val));
349         return false;
350 }
351
352 bool double_to_string (double val, std::string& str)
353 {
354         if (_infinity_to_string (val, str)) {
355                 return true;
356         }
357
358         if (_double_to_string (val, str)) {
359                 return true;
360         }
361
362         DEBUG_SCONVERT (string_compose ("double_to_string conversion failure for %1", val));
363         return false;
364 }
365
366 } // namespace PBD