aiff: handle id3 tags
[sox.git] / src / util.c
blob2d41dfda5841fbc9f68c8be5c313fe4b86f617c9
1 /* General purpose, i.e. non SoX specific, utility functions.
2 * Copyright (c) 2007-8 robs@users.sourceforge.net
4 * This library is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; either version 2.1 of the License, or (at
7 * your option) any later version.
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
12 * General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this library; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 #include "sox_i.h"
20 #include <ctype.h>
21 #include <stdio.h>
23 int lsx_strcasecmp(const char * s1, const char * s2)
25 #if defined(HAVE_STRCASECMP)
26 return strcasecmp(s1, s2);
27 #elif defined(_MSC_VER)
28 return _stricmp(s1, s2);
29 #else
30 while (*s1 && (toupper(*s1) == toupper(*s2)))
31 s1++, s2++;
32 return toupper(*s1) - toupper(*s2);
33 #endif
36 int lsx_strncasecmp(char const * s1, char const * s2, size_t n)
38 #if defined(HAVE_STRCASECMP)
39 return strncasecmp(s1, s2, n);
40 #elif defined(_MSC_VER)
41 return _strnicmp(s1, s2, n);
42 #else
43 while (--n && *s1 && (toupper(*s1) == toupper(*s2)))
44 s1++, s2++;
45 return toupper(*s1) - toupper(*s2);
46 #endif
49 sox_bool lsx_strends(char const * str, char const * end)
51 size_t str_len = strlen(str), end_len = strlen(end);
52 return str_len >= end_len && !strcmp(str + str_len - end_len, end);
55 char const * lsx_find_file_extension(char const * pathname)
57 /* First, chop off any path portions of filename. This
58 * prevents the next search from considering that part. */
59 char const * result = LAST_SLASH(pathname);
60 if (!result)
61 result = pathname;
63 /* Now look for an filename extension */
64 result = strrchr(result, '.');
65 if (result)
66 ++result;
67 return result;
70 lsx_enum_item const * lsx_find_enum_text(char const * text, lsx_enum_item const * enum_items, int flags)
72 lsx_enum_item const * result = NULL; /* Assume not found */
73 sox_bool sensitive = !!(flags & lsx_find_enum_item_case_sensitive);
75 while (enum_items->text) {
76 if ((!sensitive && !strcasecmp(text, enum_items->text)) ||
77 ( sensitive && ! strcmp(text, enum_items->text)))
78 return enum_items; /* Found exact match */
79 if ((!sensitive && !strncasecmp(text, enum_items->text, strlen(text))) ||
80 ( sensitive && ! strncmp(text, enum_items->text, strlen(text)))) {
81 if (result != NULL && result->value != enum_items->value)
82 return NULL; /* Found ambiguity */
83 result = enum_items; /* Found sub-string match */
85 ++enum_items;
87 return result;
90 lsx_enum_item const * lsx_find_enum_value(unsigned value, lsx_enum_item const * enum_items)
92 for (;enum_items->text; ++enum_items)
93 if (value == enum_items->value)
94 return enum_items;
95 return NULL;
98 int lsx_enum_option(int c, char const * arg, lsx_enum_item const * items)
100 lsx_enum_item const * p = lsx_find_enum_text(arg, items, sox_false);
101 if (p == NULL) {
102 size_t len = 1;
103 char * set = lsx_malloc(len);
104 *set = 0;
105 for (p = items; p->text; ++p) {
106 set = lsx_realloc(set, len += 2 + strlen(p->text));
107 strcat(set, ", "); strcat(set, p->text);
109 lsx_fail("-%c: `%s' is not one of: %s.", c, arg, set + 2);
110 free(set);
111 return INT_MAX;
113 return p->value;
116 char const * lsx_sigfigs3(double number)
118 static char const symbols[] = "\0kMGTPEZY";
119 static char string[16][10]; /* FIXME: not thread-safe */
120 static unsigned n; /* ditto */
121 unsigned a, b, c;
122 sprintf(string[n = (n+1) & 15], "%#.3g", number);
123 switch (sscanf(string[n], "%u.%ue%u", &a, &b, &c)) {
124 case 2: if (b) return string[n]; /* Can fall through */
125 case 1: c = 2; break;
126 case 3: a = 100*a + b; break;
128 if (c < array_length(symbols) * 3 - 3) switch (c%3) {
129 case 0: sprintf(string[n], "%u.%02u%c", a/100,a%100, symbols[c/3]); break;
130 case 1: sprintf(string[n], "%u.%u%c" , a/10 ,a%10 , symbols[c/3]); break;
131 case 2: sprintf(string[n], "%u%c" , a , symbols[c/3]); break;
133 return string[n];
136 char const * lsx_sigfigs3p(double percentage)
138 static char string[16][10];
139 static unsigned n;
140 sprintf(string[n = (n+1) & 15], "%.1f%%", percentage);
141 if (strlen(string[n]) < 5)
142 sprintf(string[n], "%.2f%%", percentage);
143 else if (strlen(string[n]) > 5)
144 sprintf(string[n], "%.0f%%", percentage);
145 return string[n];
148 int lsx_open_dllibrary(
149 int show_error_on_failure,
150 const char* library_description,
151 const char* const library_names[] UNUSED,
152 const lsx_dlfunction_info func_infos[],
153 lsx_dlptr selected_funcs[],
154 lsx_dlhandle* pdl)
156 int failed = 0;
157 lsx_dlhandle dl = NULL;
159 /* Track enough information to give a good error message about one failure.
160 * Let failed symbol load override failed library open, and let failed
161 * library open override missing static symbols.
163 const char* failed_libname = NULL;
164 const char* failed_funcname = NULL;
166 #ifdef HAVE_LIBLTDL
167 if (library_names && library_names[0])
169 const char* const* libname;
170 if (lt_dlinit())
172 lsx_fail(
173 "Unable to load %s - failed to initialize ltdl.",
174 library_description);
175 return 1;
178 for (libname = library_names; *libname; libname++)
180 lsx_debug("Attempting to open %s (%s).", library_description, *libname);
181 dl = lt_dlopenext(*libname);
182 if (dl)
184 size_t i;
185 lsx_debug("Opened %s (%s).", library_description, *libname);
186 for (i = 0; func_infos[i].name; i++)
188 union {lsx_dlptr fn; lt_ptr ptr;} func;
189 func.ptr = lt_dlsym(dl, func_infos[i].name);
190 selected_funcs[i] = func.fn ? func.fn : func_infos[i].stub_func;
191 if (!selected_funcs[i])
193 lt_dlclose(dl);
194 dl = NULL;
195 failed_libname = *libname;
196 failed_funcname = func_infos[i].name;
197 lsx_debug("Cannot use %s (%s) - missing function \"%s\".", library_description, failed_libname, failed_funcname);
198 break;
202 if (dl)
203 break;
205 else if (!failed_libname)
207 failed_libname = *libname;
211 if (!dl)
212 lt_dlexit();
214 #endif /* HAVE_LIBLTDL */
216 if (!dl)
218 size_t i;
219 for (i = 0; func_infos[i].name; i++)
221 selected_funcs[i] =
222 func_infos[i].static_func
223 ? func_infos[i].static_func
224 : func_infos[i].stub_func;
225 if (!selected_funcs[i])
227 if (!failed_libname)
229 failed_libname = "static";
230 failed_funcname = func_infos[i].name;
233 failed = 1;
234 break;
239 if (failed)
241 size_t i;
242 for (i = 0; func_infos[i].name; i++)
243 selected_funcs[i] = NULL;
244 #ifdef HAVE_LIBLTDL
245 #define LTDL_MISSING ""
246 #else
247 #define LTDL_MISSING " (Dynamic library support not configured.)"
248 #endif /* HAVE_LIBLTDL */
249 if (failed_funcname)
251 if (show_error_on_failure)
252 lsx_fail(
253 "Unable to load %s (%s) function \"%s\"." LTDL_MISSING,
254 library_description,
255 failed_libname,
256 failed_funcname);
257 else
258 lsx_report(
259 "Unable to load %s (%s) function \"%s\"." LTDL_MISSING,
260 library_description,
261 failed_libname,
262 failed_funcname);
264 else if (failed_libname)
266 if (show_error_on_failure)
267 lsx_fail(
268 "Unable to load %s (%s)." LTDL_MISSING,
269 library_description,
270 failed_libname);
271 else
272 lsx_report(
273 "Unable to load %s (%s)." LTDL_MISSING,
274 library_description,
275 failed_libname);
277 else
279 if (show_error_on_failure)
280 lsx_fail(
281 "Unable to load %s - no dynamic library names selected." LTDL_MISSING,
282 library_description);
283 else
284 lsx_report(
285 "Unable to load %s - no dynamic library names selected." LTDL_MISSING,
286 library_description);
290 *pdl = dl;
291 return failed;
294 void lsx_close_dllibrary(
295 lsx_dlhandle dl UNUSED)
297 #ifdef HAVE_LIBLTDL
298 if (dl)
300 lt_dlclose(dl);
301 lt_dlexit();
303 #endif /* HAVE_LIBLTDL */