add variants of atoi etc. for std::string
[ardour.git] / libs / pbd / convert.cc
1 /*
2     Copyright (C) 2006 Paul Davis 
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 <cmath>
21 #include <stdint.h>
22 #include <stdlib.h>
23 #include <cstdio>
24 #ifndef __STDC_FORMAT_MACROS
25 #define __STDC_FORMAT_MACROS
26 #endif
27 #include <inttypes.h>
28
29 #include "pbd/convert.h"
30
31 #include "i18n.h"
32
33 using std::string;
34 using std::vector;
35 using Glib::ustring;
36
37 namespace PBD {
38
39 string
40 short_version (string orig, string::size_type target_length)
41 {
42         /* this tries to create a recognizable abbreviation
43            of "orig" by removing characters until we meet
44            a certain target length.
45
46            note that we deliberately leave digits in the result
47            without modification.
48         */
49
50
51         string::size_type pos;
52
53         /* remove white-space and punctuation, starting at end */
54
55         while (orig.length() > target_length) {
56                 if ((pos = orig.find_last_of (_("\"\n\t ,<.>/?:;'[{}]~`!@#$%^&*()_-+="))) == string::npos) {
57                         break;
58                 }
59                 orig.replace (pos, 1, "");
60         }
61
62         /* remove lower-case vowels, starting at end */
63
64         while (orig.length() > target_length) {
65                 if ((pos = orig.find_last_of (_("aeiou"))) == string::npos) {
66                         break;
67                 }
68                 orig.replace (pos, 1, "");
69         }
70
71         /* remove upper-case vowels, starting at end */
72
73         while (orig.length() > target_length) {
74                 if ((pos = orig.find_last_of (_("AEIOU"))) == string::npos) {
75                         break;
76                 }
77                 orig.replace (pos, 1, "");
78         }
79
80         /* remove lower-case consonants, starting at end */
81
82         while (orig.length() > target_length) {
83                 if ((pos = orig.find_last_of (_("bcdfghjklmnpqrtvwxyz"))) == string::npos) {
84                         break;
85                 }
86                 orig.replace (pos, 1, "");
87         }
88
89         /* remove upper-case consonants, starting at end */
90
91         while (orig.length() > target_length) {
92                 if ((pos = orig.find_last_of (_("BCDFGHJKLMNPQRTVWXYZ"))) == string::npos) {
93                         break;
94                 }
95                 orig.replace (pos, 1, "");
96         }
97
98         /* whatever the length is now, use it */
99         
100         return orig;
101 }
102
103 int
104 atoi (const string& s)
105 {
106         return ::atoi (s.c_str());
107 }
108
109 int32_t
110 atol (const string& s)
111 {
112         return (int32_t) ::atol (s.c_str());
113 }
114
115 int64_t
116 atoll (const string& s)
117 {
118         return (int64_t) ::atoll (s.c_str());
119 }
120
121 double
122 atof (const string& s)
123 {
124         return ::atof (s.c_str());
125 }
126
127 vector<string>
128 internationalize (const char *package_name, const char **array)
129 {
130         vector<string> v;
131
132         for (uint32_t i = 0; array[i]; ++i) {
133                 v.push_back (dgettext(package_name, array[i]));
134         }
135
136         return v;
137 }
138
139 static int32_t 
140 int_from_hex (char hic, char loc) 
141 {
142         int hi;         /* hi byte */
143         int lo;         /* low byte */
144
145         hi = (int) hic;
146
147         if( ('0'<=hi) && (hi<='9') ) {
148                 hi -= '0';
149         } else if( ('a'<= hi) && (hi<= 'f') ) {
150                 hi -= ('a'-10);
151         } else if( ('A'<=hi) && (hi<='F') ) {
152                 hi -= ('A'-10);
153         }
154         
155         lo = (int) loc;
156         
157         if( ('0'<=lo) && (lo<='9') ) {
158                 lo -= '0';
159         } else if( ('a'<=lo) && (lo<='f') ) {
160                 lo -= ('a'-10);
161         } else if( ('A'<=lo) && (lo<='F') ) {
162                 lo -= ('A'-10);
163         }
164
165         return lo + (16 * hi);
166 }
167
168 void
169 url_decode (string& url)
170 {
171         string::iterator last;
172         string::iterator next;
173
174         for (string::iterator i = url.begin(); i != url.end(); ++i) {
175                 if ((*i) == '+') {
176                         *i = ' ';
177                 }
178         }
179
180         if (url.length() <= 3) {
181                 return;
182         }
183
184         last = url.end();
185
186         --last; /* points at last char */
187         --last; /* points at last char - 1 */
188
189         for (string::iterator i = url.begin(); i != last; ) {
190
191                 if (*i == '%') {
192
193                         next = i;
194
195                         url.erase (i);
196                         
197                         i = next;
198                         ++next;
199                         
200                         if (isxdigit (*i) && isxdigit (*next)) {
201                                 /* replace first digit with char */
202                                 *i = int_from_hex (*i,*next);
203                                 ++i; /* points at 2nd of 2 digits */
204                                 url.erase (i);
205                         }
206                 } else {
207                         ++i;
208                 }
209         }
210 }
211
212 void
213 url_decode (ustring& url)
214 {
215         ustring::iterator last;
216         ustring::iterator next;
217
218         for (ustring::iterator i = url.begin(); i != url.end(); ++i) {
219                 if ((*i) == '+') {
220                         next = i;
221                         ++next;
222                         url.replace (i, next, 1, ' ');
223                 }
224         }
225
226         if (url.length() <= 3) {
227                 return;
228         }
229
230         last = url.end();
231
232         --last; /* points at last char */
233         --last; /* points at last char - 1 */
234
235         for (ustring::iterator i = url.begin(); i != last; ) {
236
237                 if (*i == '%') {
238
239                         next = i;
240
241                         url.erase (i);
242                         
243                         i = next;
244                         ++next;
245                         
246                         if (isxdigit (*i) && isxdigit (*next)) {
247                                 /* replace first digit with char */
248                                 url.replace (i, next, 1, (gunichar) int_from_hex (*i,*next));
249                                 ++i; /* points at 2nd of 2 digits */
250                                 url.erase (i);
251                         }
252                 } else {
253                         ++i;
254                 }
255         }
256 }
257
258 #if 0
259 string
260 length2string (const int32_t frames, const float sample_rate)
261 {
262     int32_t secs = (int32_t) (frames / sample_rate);
263     int32_t hrs =  secs / 3600;
264     secs -= (hrs * 3600);
265     int32_t mins = secs / 60;
266     secs -= (mins * 60);
267
268     int32_t total_secs = (hrs * 3600) + (mins * 60) + secs;
269     int32_t frames_remaining = (int) floor (frames - (total_secs * sample_rate));
270     float fractional_secs = (float) frames_remaining / sample_rate;
271
272     char duration_str[32];
273     sprintf (duration_str, "%02" PRIi32 ":%02" PRIi32 ":%05.2f", hrs, mins, (float) secs + fractional_secs);
274
275     return duration_str;
276 }
277 #endif
278
279 string
280 length2string (const int64_t frames, const double sample_rate)
281 {
282         int64_t secs = (int64_t) floor (frames / sample_rate);
283         int64_t hrs =  secs / 3600LL;
284         secs -= (hrs * 3600LL);
285         int64_t mins = secs / 60LL;
286         secs -= (mins * 60LL);
287         
288         int64_t total_secs = (hrs * 3600LL) + (mins * 60LL) + secs;
289         int64_t frames_remaining = (int64_t) floor (frames - (total_secs * sample_rate));
290         float fractional_secs = (float) frames_remaining / sample_rate;
291         
292         char duration_str[64];
293         sprintf (duration_str, "%02" PRIi64 ":%02" PRIi64 ":%05.2f", hrs, mins, (float) secs + fractional_secs);
294         
295         return duration_str;
296 }
297
298 static bool 
299 chars_equal_ignore_case(char x, char y)
300 {
301         /* app should have called setlocale() if its wants this comparison to be
302            locale sensitive.
303         */
304         return toupper (x) == toupper (y);
305 }
306
307 bool 
308 strings_equal_ignore_case (const string& a, const string& b)
309 {
310         if (a.length() == b.length()) {
311                 return std::equal (a.begin(), a.end(), b.begin(), chars_equal_ignore_case);
312         }
313         return false;
314 }
315
316
317 } // namespace PBD