Hello,

2013/5/28 Hans de Goede <hdego...@redhat.com>:
> 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.

In my case I will use libusb_strerror() to get a human readable
message in the log trace.
Since the log is for me (and not for the end user) I do not want to
get a message in Dutch so I will call libusb_set_strerror_locale("en")

libusb_set_strerror_locale("en") is not only used to avoid UTF-8 problems.

I have 2 comments bellow:

> 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

excepted -> accepted.


> + * "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;

The English version returns "Unknown error" instead of NULL. I would
not like to get a NULL pointer instead of a valid C-string.

I now understand why after reading the code of libusb_strerror().
Maybe "Unknown error" should also be translated. No?
Or maybe add a comment like /* fall back to English translation */
before the 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



--
 Dr. Ludovic Rousseau

------------------------------------------------------------------------------
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