This patch adds the much requested libusb_strerror() function, taking into account all issues people raised wrt previous attempts.
Criteria / Decisions underlying this implementation: -Must support translated messages -Must not use gettext as that does not work well in combination with Windows (when building with Visual C, or for Windows CE) -API compatible with FreeBSD and various patched libusb-s floating around -KISS: -Do not add any (other) library dependencies -Do not try to deal with message encodings (iconv), simply always return UTF-8 making encoding the problem of the application using libusb_strerror. -Defaults to English, so apps which don't want translated messages, don't need to do anything special -Defaults to English (with pure ASCII messages), so apps which don't call libusb_setlocale() don't need to worry about encoding This patch includes a Dutch tranlation for the messages to show how further languages can be added in a simple manner. Signed-off-by: Hans de Goede <hdego...@redhat.com> --- libusb/Makefile.am | 5 +- libusb/libusb-1.0.def | 4 + libusb/libusb.h | 11 ++- libusb/strerror.c | 205 ++++++++++++++++++++++++++++++++++++++++++++++++++ libusb/version_nano.h | 2 +- 5 files changed, 220 insertions(+), 7 deletions(-) create mode 100644 libusb/strerror.c diff --git a/libusb/Makefile.am b/libusb/Makefile.am index cd6db9c..7f9c1f9 100644 --- a/libusb/Makefile.am +++ b/libusb/Makefile.am @@ -59,9 +59,10 @@ endif libusb_1_0_la_CFLAGS = $(AM_CFLAGS) libusb_1_0_la_LDFLAGS = $(LTLDFLAGS) -libusb_1_0_la_SOURCES = libusbi.h core.c descriptor.c io.c sync.c $(OS_SRC) \ +libusb_1_0_la_SOURCES = libusbi.h core.c descriptor.c io.c strerror.c sync.c \ os/linux_usbfs.h os/darwin_usb.h os/windows_usb.h os/windows_common.h \ - hotplug.h hotplug.c $(THREADS_SRC) os/poll_posix.h os/poll_windows.h + hotplug.h hotplug.c $(THREADS_SRC) $(OS_SRC) \ + os/poll_posix.h os/poll_windows.h hdrdir = $(includedir)/libusb-1.0 hdr_HEADERS = libusb.h diff --git a/libusb/libusb-1.0.def b/libusb/libusb-1.0.def index 7166d47..9d1dd80 100644 --- a/libusb/libusb-1.0.def +++ b/libusb/libusb-1.0.def @@ -134,8 +134,12 @@ EXPORTS libusb_set_debug@8 = libusb_set_debug libusb_set_interface_alt_setting libusb_set_interface_alt_setting@12 = libusb_set_interface_alt_setting + libusb_set_locale + libusb_set_locale@4 = libusb_set_locale libusb_set_pollfd_notifiers libusb_set_pollfd_notifiers@16 = libusb_set_pollfd_notifiers + libusb_strerror + libusb_strerror@4 = libusb_strerror libusb_submit_transfer libusb_submit_transfer@4 = libusb_submit_transfer libusb_try_lock_events diff --git a/libusb/libusb.h b/libusb/libusb.h index d733c46..311d7f2 100644 --- a/libusb/libusb.h +++ b/libusb/libusb.h @@ -1044,8 +1044,9 @@ enum libusb_bos_type { /** \ingroup misc * Error codes. Most libusbx functions return 0 on success or one of these * codes on failure. - * You can call \ref libusb_error_name() to retrieve a string representation - * of an error code. + * You can call libusb_error_name() to retrieve a string representation of an + * error code or libusb_strerror() to get an end-user suitable description of + * an error code. */ enum libusb_error { /** Success (no error) */ @@ -1087,8 +1088,8 @@ enum libusb_error { /** Operation not supported or unimplemented on this platform */ LIBUSB_ERROR_NOT_SUPPORTED = -12, - /* NB! Remember to update libusb_error_name() - when adding new error codes here. */ + /* NB! Remember to update libusb_error_name() and + libusb_strerror() when adding new error codes here. */ /** Other error */ LIBUSB_ERROR_OTHER = -99, @@ -1299,6 +1300,8 @@ void LIBUSB_CALL libusb_set_debug(libusb_context *ctx, int level); const struct libusb_version * LIBUSB_CALL libusb_get_version(void); int LIBUSB_CALL libusb_has_capability(uint32_t capability); const char * LIBUSB_CALL libusb_error_name(int errcode); +int LIBUSB_CALL libusb_setlocale(const char *locale); +const char * LIBUSB_CALL libusb_strerror(enum libusb_error errcode); ssize_t LIBUSB_CALL libusb_get_device_list(libusb_context *ctx, libusb_device ***list); diff --git a/libusb/strerror.c b/libusb/strerror.c new file mode 100644 index 0000000..bea75a3 --- /dev/null +++ b/libusb/strerror.c @@ -0,0 +1,205 @@ +/* + * libusb strerror code + * Copyright © 2013 Hans de Goede <hdego...@redhat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "config.h" + +#include <locale.h> +#include <stdlib.h> +#include <string.h> + +#include "libusb.h" +#include "libusbi.h" + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +enum libusb_locale_enum { + LANG_EN, + LANG_NL, +}; +#endif + +static int libusb_locale = LANG_EN; + +/** \ingroup misc + * Set the language, and only the language, not the encoding! used for + * translatable libusb messages. + * + * This takes a locale string in the default setlocale format: + * lang[_country_region][.codeset]. Only the lang part of the string is used, + * and only 2 letter ISO 639-1 codes are accepted, ie "en". The optional + * country_regio and codeset parts are ignored. This means that functions + * which return translatable strings will NOT honor the specified encoding. + * If lang is en, then all translatable strings will be pure ASCII, for all + * other languages they will be encoded as UTF-8 strings! + * + * If libusb_setlocale() is not called, all messages will be in English. + * + * The following functions return translatable strings: libusb_strerror(). + * Note that the libusb log messages controlled through libusb_set_debug() + * are not translated, they are always in English. + * + * For POSIX UTF-8 environments if you want libusb to follow the standard + * locale settings, call libusb_setlocale(setlocale(LC_MESSAGES, NULL)), + * after your app has done its locale setup. + * + * \param locale locale-string in the form of lang[_country_region][.codeset] + * \returns 0 on success + * \returns LIBUSB_ERROR_NOT_FOUND if the requested language is not supported + * \returns a LIBUSB_ERROR code on other errors + */ +int API_EXPORTED libusb_setlocale(const char *locale) +{ + const char * const iso639[] = { + /* Note the order here MUST match the libusb_locale_enum */ + "en", /* LANG_EN */ + "nl", /* LANG_NL */ + NULL + }; + char lang[3] = { 0, }; + int i; + + for (i = 0; + i < 3 && locale[i] && locale[i] != '_' && locale[i] != '.'; + i++) + lang[i] = locale[i]; + + if (lang[2] != 0) { + usbi_warn(NULL, "Unrecognized locale format: %s", locale); + return LIBUSB_ERROR_INVALID_PARAM; + } + + for (i = 0; iso639[i]; i++) { + if (strcmp(lang, iso639[i]) == 0) + break; + } + if (!iso639[i]) { + usbi_warn(NULL, "Unsupported language: %s", lang); + return LIBUSB_ERROR_NOT_FOUND; + } + + libusb_locale = i; + + return LIBUSB_SUCCESS; +} + +static const char *libusb_strerror_en(enum libusb_error errcode) +{ + switch (errcode) { + case LIBUSB_SUCCESS: + return "Success"; + case LIBUSB_ERROR_IO: + return "Input/output error"; + case LIBUSB_ERROR_INVALID_PARAM: + return "Invalid parameter"; + case LIBUSB_ERROR_ACCESS: + return "Access denied (insufficient permissions)"; + case LIBUSB_ERROR_NO_DEVICE: + return "No such device (it may have been disconnected)"; + case LIBUSB_ERROR_NOT_FOUND: + return "Entity not found"; + case LIBUSB_ERROR_BUSY: + return "Resource busy"; + case LIBUSB_ERROR_TIMEOUT: + return "Operation timed out"; + case LIBUSB_ERROR_OVERFLOW: + return "Overflow"; + case LIBUSB_ERROR_PIPE: + return "Pipe error"; + case LIBUSB_ERROR_INTERRUPTED: + return "System call interrupted (perhaps due to signal)"; + case LIBUSB_ERROR_NO_MEM: + return "Insufficient memory"; + case LIBUSB_ERROR_NOT_SUPPORTED: + return "Operation not supported or unimplemented on this platform"; + case LIBUSB_ERROR_OTHER: + return "Other error"; + default: + return "Unknown error"; + } +} + +static const char *libusb_strerror_nl(enum libusb_error errcode) +{ + switch (errcode) { + case LIBUSB_SUCCESS: + return "Gelukt"; + case LIBUSB_ERROR_IO: + return "Invoer-/uitvoerfout"; + case LIBUSB_ERROR_INVALID_PARAM: + return "Ongeldig argument"; + case LIBUSB_ERROR_ACCESS: + return "Toegang geweigerd (onvoldoende toegangsrechten)"; + case LIBUSB_ERROR_NO_DEVICE: + return "Apparaat bestaat niet (verbinding met apparaat verbroken?)"; + case LIBUSB_ERROR_NOT_FOUND: + return "Niet gevonden"; + case LIBUSB_ERROR_BUSY: + return "Apparaat of hulpbron is bezig"; + case LIBUSB_ERROR_TIMEOUT: + return "Bewerking verlopen"; + case LIBUSB_ERROR_OVERFLOW: + return "Waarde is te groot"; + case LIBUSB_ERROR_PIPE: + return "Gebroken pijp"; + case LIBUSB_ERROR_INTERRUPTED: + return "Onderbroken systeemaanroep"; + case LIBUSB_ERROR_NO_MEM: + return "Onvoldoende geheugen beschikbaar"; + case LIBUSB_ERROR_NOT_SUPPORTED: + return "Bewerking wordt niet ondersteund"; + case LIBUSB_ERROR_OTHER: + return "Andere fout"; + default: + return NULL; /* fall back to English translation */ + } +} + +/** \ingroup misc + * Returns a constant string with a short description of the given error code, + * this description is intended for displaying to the end user and will be in + * the language set by libusb_setlocale(). + * + * The returned string is encoded in ASCII for English messages (the default + * if libusb_setlocale() is not called). For all other languages it is + * encoded in UTF-8! + * + * The messages always start with a capital letter and end without any dot. + * The caller must not free() the returned string. + * + * \param errcode the error code whose description is desired + * \returns a short description of the error code in UTF-8 encoding + */ +DEFAULT_VISIBILITY const char* libusb_strerror(enum libusb_error errcode) +{ + const char *msg = NULL; + + switch (libusb_locale) { + case LANG_EN: + msg = libusb_strerror_en(errcode); + break; + case LANG_NL: + msg = libusb_strerror_nl(errcode); + break; + } + + if (!msg) { + /* No translated msg for this errcode, fall back to English */ + msg = libusb_strerror_en(errcode); + } + + return msg; +} diff --git a/libusb/version_nano.h b/libusb/version_nano.h index 2804c7d..69bc4ae 100644 --- a/libusb/version_nano.h +++ b/libusb/version_nano.h @@ -1 +1 @@ -#define LIBUSB_NANO 10728 +#define LIBUSB_NANO 10730 -- 1.8.2.1 ------------------------------------------------------------------------------ How ServiceNow helps IT people transform IT departments: 1. A cloud service to automate IT design, transition and operations 2. Dashboards that offer high-level views of enterprise services 3. A single system of record for all IT processes http://p.sf.net/sfu/servicenow-d2d-j _______________________________________________ libusbx-devel mailing list libusbx-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/libusbx-devel