summaryrefslogtreecommitdiff
path: root/src/strerror.c
diff options
context:
space:
mode:
authorMarcus Brinkmann <mb@g10code.com>2003-09-13 21:27:34 +0000
committerMarcus Brinkmann <mb@g10code.com>2003-09-13 21:27:34 +0000
commitc88b9b0c6cae2ba87760b340e7378641c14bfc22 (patch)
treea9fb08c9ee67de9b61efd88d30724b72ff344d6e /src/strerror.c
parentd19a256bcf34b5176980bc2d0e21242d2d2570a8 (diff)
downloadlibgpg-error-c88b9b0c6cae2ba87760b340e7378641c14bfc22.tar.gz
2003-09-13 Marcus Brinkmann <marcus@g10code.de>
* configure.ac: Invoke AC_FUNC_STRERROR_R. * src/gpg-error.h (gpg_strerror_r): New prototype. * src/strerror.c (system_strerror_r): New function. (gpg_strerror_r): New function.
Diffstat (limited to 'src/strerror.c')
-rw-r--r--src/strerror.c208
1 files changed, 207 insertions, 1 deletions
diff --git a/src/strerror.c b/src/strerror.c
index 0498b48..a8a5a63 100644
--- a/src/strerror.c
+++ b/src/strerror.c
@@ -22,6 +22,7 @@
#include <config.h>
#endif
+#include <stdlib.h>
#include <string.h>
#include <gpg-error.h>
@@ -30,7 +31,7 @@
#include "err-codes.h"
/* Return a pointer to a string containing a description of the error
- code in the error value ERR. */
+ code in the error value ERR. This function is not thread-safe. */
const char *
gpg_strerror (gpg_error_t err)
{
@@ -46,3 +47,208 @@ gpg_strerror (gpg_error_t err)
}
return dgettext (PACKAGE, msgstr + msgidx[msgidxof (code)]);
}
+
+
+#ifdef HAVE_STRERROR_R
+#ifdef STRERROR_R_CHAR_P
+/* The GNU C library and probably some other systems have this weird
+ variant of strerror_r. */
+
+/* Return a dynamically allocated string in *STR describing the system
+ error NO. If this call succeeds, return 1. If this call fails due
+ to a resource shortage, set *STR to NULL and return 1. If this
+ call fails because the error number is not valid, don't set *STR
+ and return 0. */
+int
+system_strerror_r (int no, char **str)
+{
+ int err;
+ char *buffer;
+ size_t buffer_len = 128;
+
+ buffer = malloc (buffer_len);
+ if (!buffer)
+ {
+ *str = NULL;
+ return 1;
+ }
+
+ do
+ {
+ char *msg = strerror_r (no, buffer, buffer_len);
+
+ if (!msg)
+ {
+ /* Possibly this means that the error code is unknown. */
+ free (buffer);
+ return 0;
+ }
+ else if (msg != buffer)
+ {
+ free (buffer);
+ *str = strdup (msg);
+ return 1;
+ }
+
+ buffer[buffer_len - 1] = '\0';
+ if (strlen (buffer) == buffer_len - 1)
+ {
+ /* We might need more space. */
+ size_t new_buffer_len = buffer_len * 2;
+ char *new_buffer;
+
+ if (new_buffer_len < buffer_len)
+ {
+ /* Overflow. Now, this is serious. */
+ free (buffer);
+ *str = NULL;
+ return 1;
+ }
+
+ new_buffer = realloc (buffer, 2 * buffer_len);
+ if (!new_buffer)
+ {
+ free (buffer);
+ *str = NULL;
+ return 1;
+ }
+ buffer = new_buffer;
+ buffer_len = new_buffer_len;
+ }
+ else
+ {
+ *str = buffer;
+ return 1;
+ }
+ }
+ while (1);
+}
+
+#else /* STRERROR_R_CHAR_P */
+/* Now the POSIX version. */
+
+/* Return a dynamically allocated string in *STR describing the system
+ error NO. If this call succeeds, return 1. If this call fails due
+ to a resource shortage, set *STR to NULL and return 1. If this
+ call fails because the error number is not valid, don't set *STR
+ and return 0. */
+int
+system_strerror_r (int no, char **str)
+{
+ int err;
+ char *buffer;
+ size_t buffer_len = 128;
+
+ buffer = malloc (buffer_len);
+ if (!buffer)
+ {
+ *str = NULL;
+ return 1;
+ }
+
+ do
+ {
+ err = strerror_r (no, buffer, buffer_len);
+
+ if (err == ERANGE)
+ {
+ size_t new_buffer_len = buffer_len * 2;
+ char *new_buffer;
+
+ if (new_buffer_len < buffer_len)
+ {
+ /* Overflow. Now, this is serious. */
+ free (buffer);
+ *str = NULL;
+ return 1;
+ }
+
+ new_buffer = realloc (buffer, 2 * buffer_len);
+ if (!new_buffer)
+ {
+ free (buffer);
+ *str = NULL;
+ return 1;
+ }
+ buffer = new_buffer;
+ buffer_len = new_buffer_len;
+ }
+ }
+ while (err == ERANGE);
+
+ if (err == EINVAL)
+ {
+ /* This system error is not known. */
+ free (buffer);
+ return 0;
+ }
+ else if (err)
+ {
+ /* strerror_r() failed, but we don't know why. */
+ free (buffer);
+ *str = NULL;
+ return 1;
+ }
+
+ *str = buffer;
+ return 1;
+}
+#endif /* STRERROR_R_CHAR_P */
+
+#else /* HAVE_STRERROR_H */
+/* Without strerror_r(), we can still provide a non-thread-safe
+ version. Maybe we are even lucky and the system's strerror() is
+ already thread-safe. */
+
+/* Return a dynamically allocated string in *STR describing the system
+ error NO. If this call succeeds, return 1. If this call fails due
+ to a resource shortage, set *STR to NULL and return 1. If this
+ call fails because the error number is not valid, don't set *STR
+ and return 0. */
+int
+system_strerror_r (int no, char **str)
+{
+ char *msg = strerror (no);
+
+ if (!msg)
+ {
+ if (errno == EINVAL)
+ return 0;
+ else
+ {
+ *str = NULL;
+ return 1;
+ }
+ }
+ else
+ {
+ *str = strdup (msg);
+ return 1;
+ }
+}
+#endif
+
+
+/* Return a pointer to a string containing a description of the error
+ code in the error value ERR. The buffer for the string is
+ allocated with malloc(), and has to be released by the user. On
+ error, NULL is returned. */
+char *
+gpg_strerror_r (gpg_error_t err)
+{
+ gpg_err_code_t code = gpg_err_code (err);
+
+ if (code & GPG_ERR_SYSTEM_ERROR)
+ {
+ int no = gpg_err_code_to_errno (code);
+ if (no)
+ {
+ char *str;
+
+ if (system_strerror_r (no, &str))
+ return str;
+ }
+ code = GPG_ERR_UNKNOWN_ERRNO;
+ }
+ return strdup (dgettext (PACKAGE, msgstr + msgidx[msgidxof (code)]));
+}