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