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.
  Apps which don't want to deal with encoding can opt-out with a simple:
  libusb_set_strerror_locale("en") call, after which the messages returned by
  libusb_strerror are guaranteed to be pure ASCII.

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.h       |  11 ++-
 libusb/strerror.c     | 250 ++++++++++++++++++++++++++++++++++++++++++++++++++
 libusb/version_nano.h |   2 +-
 4 files changed, 261 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.h b/libusb/libusb.h
index 7b68917..c768551 100644
--- a/libusb/libusb.h
+++ b/libusb/libusb.h
@@ -1032,8 +1032,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) */
@@ -1075,8 +1076,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,
@@ -1287,6 +1288,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_set_strerror_locale(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..15c748b
--- /dev/null
+++ b/libusb/strerror.c
@@ -0,0 +1,250 @@
+/*
+ * 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 strerror_locale_enum {
+       LANG_EN,
+       LANG_NL,
+};
+
+struct locale_str_to_locale_enum {
+       const char *locale_str;
+       enum strerror_locale_enum locale_enum;
+};
+#endif
+
+/* Windows has a gazillion ways to set the same language, see:
+ * http://msdn.microsoft.com/en-us/library/39cwe7zf%28v=vs.80%29.aspx */
+static struct locale_str_to_locale_enum locale_to_enum[] = {
+       { "C",                  LANG_EN },
+       { "POSIX",              LANG_EN },
+       { "en",                 LANG_EN },
+       { "English",            LANG_EN },
+       { "english",            LANG_EN },
+       { "australian",         LANG_EN },
+       { "ena",                LANG_EN },
+       { "english-aus",        LANG_EN },
+       { "canadian",           LANG_EN },
+       { "enc",                LANG_EN },
+       { "english-can",        LANG_EN },
+       { "english-nz",         LANG_EN },
+       { "enz",                LANG_EN },
+       { "eng",                LANG_EN },
+       { "english-uk",         LANG_EN },
+       { "uk",                 LANG_EN },
+       { "american",           LANG_EN },
+       { "american english",   LANG_EN },
+       { "american-english",   LANG_EN },
+       { "english-american",   LANG_EN },
+       { "english-us",         LANG_EN },
+       { "english-usa",        LANG_EN },
+       { "enu",                LANG_EN },
+       { "us",                 LANG_EN },
+       { "usa",                LANG_EN },
+       { "nl",                 LANG_NL },
+       { "Dutch",              LANG_NL },
+       { "dutch",              LANG_NL },
+       { "nld",                LANG_NL },
+       { "belgian",            LANG_NL },
+       { "dutch-belgian",      LANG_NL },
+       { "nlb",                LANG_NL },
+       { NULL }
+};
+
+static usbi_mutex_static_t strerror_locale_lock = USBI_MUTEX_INITIALIZER;
+static int strerror_locale = -1;
+
+static int libusb_set_strerror_locale_unlocked(const char *locale)
+{
+       char *lang;
+       int i, ret = LIBUSB_SUCCESS;
+
+       lang = malloc(strlen(locale) + 1); /* no strdup under windows */
+       if (!lang)
+               return LIBUSB_ERROR_NO_MEM;
+
+       strcpy(lang, locale);
+       for (i = 0; lang[i] && lang[i] != '_' && lang[i] != '.'; i++) {}
+       lang[i] = 0;
+
+       for (i = 0; locale_to_enum[i].locale_str; i++) {
+               if (strcmp(lang, locale_to_enum[i].locale_str) == 0)
+                       break;
+       }
+
+       if (locale_to_enum[i].locale_str) {
+               strerror_locale = locale_to_enum[i].locale_enum;
+       } else {
+               usbi_warn(NULL, "Unsupported language: %s", lang);
+               strerror_locale = LANG_EN;
+               ret = LIBUSB_ERROR_NOT_FOUND;
+       }
+
+       free(lang);
+       return ret;
+}
+
+/** \ingroup misc
+ * Set the language, and only the language, not the encoding! used for
+ * libusb_strerror messages. This takes a locale string in the default
+ * setlocale format. Both Windows and Posix locale strings are excepted, ie
+ * "English" or "en_US.utf8". Note the optional codeset part is ignored,
+ * as libusb_strerror always returns UTF-8 strings!
+ *
+ * \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 libusb_set_strerror_locale(const char *locale)
+{
+       int ret;
+
+       usbi_mutex_static_lock(&strerror_locale_lock);
+       ret = libusb_set_strerror_locale_unlocked(locale);
+       usbi_mutex_static_unlock(&strerror_locale_lock);
+
+       return ret;
+}
+
+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;
+       }
+}
+
+/** \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_set_strerror_locale().
+ *
+ * If libusb_set_strerror_locale() has not been called before calling
+ * libusb_strerror(), libusb_strerror() will call
+ * libusb_set_strerror_locale(setlocale(LC_MESSAGES, NULL)), to set it to
+ * the current locale.
+ *
+ * The returned string is encoded in UTF-8, except for English messages, which
+ * are guaranteed to be limited to ASCII. So if your app cannot handle UTF-8,
+ * it should call libusb_set_strerror_locale("English") before using
+ * libusb_strerror().
+ *
+ * The messages always start with a capital letter and ends 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;
+
+       usbi_mutex_static_lock(&strerror_locale_lock);
+       if (strerror_locale == -1)
+               libusb_set_strerror_locale_unlocked(
+                                               setlocale(LC_MESSAGES, NULL));
+       switch (strerror_locale) {
+               case LANG_EN:
+                       msg = libusb_strerror_en(errcode);
+                       break;
+               case LANG_NL:
+                       msg = libusb_strerror_nl(errcode);
+                       break;
+       }
+       usbi_mutex_static_unlock(&strerror_locale_lock);
+
+       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..520a082 100644
--- a/libusb/version_nano.h
+++ b/libusb/version_nano.h
@@ -1 +1 @@
-#define LIBUSB_NANO 10728
+#define LIBUSB_NANO 10729
-- 
1.8.2.1


------------------------------------------------------------------------------
Try New Relic Now & We'll Send You this Cool Shirt
New Relic is the only SaaS-based application performance monitoring service 
that delivers powerful full stack analytics. Optimize and monitor your
browser, app, & servers with just a few lines of code. Try New Relic
and get this awesome Nerd Life shirt! http://p.sf.net/sfu/newrelic_d2d_may
_______________________________________________
libusbx-devel mailing list
libusbx-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libusbx-devel

Reply via email to