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