changeset 10429:69d9922a5bd2

Extend strerror to cover the added errno values.
author Bruno Haible <bruno@clisp.org>
date Sun, 14 Sep 2008 04:18:44 +0200
parents 23529d9499fd
children 1e129af73cb0
files ChangeLog doc/posix-functions/strerror.texi lib/strerror.c m4/strerror.m4 modules/strerror tests/test-strerror.c
diffstat 6 files changed, 304 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2008-09-13  Bruno Haible  <bruno@clisp.org>
+
+	Extend strerror to cover the added errno values.
+	* lib/strerror.c: Include errno.h and winsock2.h if it exists.
+	(rpl_strerror): Provide error messages for the added errno values and
+	for the WSA* values.
+	* m4/strerror.m4 (gl_FUNC_STRERROR): Test REPLACE_STRERROR.
+	(gl_FUNC_STRERROR_SEPARATE): If errno.h is replaced, always replace
+	strerror.
+	(gl_PREREQ_STRERROR): Test whether winsock2.h exists.
+	* modules/strerror (Depends-on): Add errno.
+	* doc/posix-functions/strerror.texi: Document the change.
+	* tests/test-strerror.c (main): Check also the string for ETIMEDOUT
+	and EOVERFLOW.
+
 2008-09-13  Bruno Haible  <bruno@clisp.org>
 
 	* modules/EOVERFLOW: Remove file.
--- a/doc/posix-functions/strerror.texi
+++ b/doc/posix-functions/strerror.texi
@@ -10,7 +10,10 @@
 @itemize
 @item
 This function is missing on some old platforms.
-
+@item
+This function does not support the error values that are specified by POSIX
+but not defined by the system, on some platforms:
+OpenBSD 4.0, OSF/1 4.0, mingw.
 @item
 This function fails to return a string for out-of-range integers on
 some platforms:
--- a/lib/strerror.c
+++ b/lib/strerror.c
@@ -1,6 +1,6 @@
 /* strerror.c --- POSIX compatible system error routine
 
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007-2008 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -21,8 +21,15 @@
 
 #if REPLACE_STRERROR
 
+# include <errno.h>
 # include <stdio.h>
 
+# if GNULIB_defined_ESOCK /* native Windows platforms */
+#  if HAVE_WINSOCK2_H
+#   include <winsock2.h>
+#  endif
+# endif
+
 # include "intprops.h"
 
 # undef strerror
@@ -33,17 +40,235 @@
 char *
 rpl_strerror (int n)
 {
-  char *result = strerror (n);
-
-  if (result == NULL || result[0] == '\0')
+  /* These error messages are taken from glibc/sysdeps/gnu/errlist.c.  */
+  switch (n)
     {
-      static char const fmt[] = "Unknown error (%d)";
-      static char mesg[sizeof fmt + INT_STRLEN_BOUND (n)];
-      sprintf (mesg, fmt, n);
-      return mesg;
+# if GNULIB_defined_ETXTBSY
+    case ETXTBSY:
+      return "Text file busy";
+# endif
+
+# if GNULIB_defined_ESOCK /* native Windows platforms */
+    case EWOULDBLOCK:
+      return "Operation would block";
+    case EINPROGRESS:
+      return "Operation now in progress";
+    case EALREADY:
+      return "Operation already in progress";
+    case ENOTSOCK:
+      return "Socket operation on non-socket";
+    case EDESTADDRREQ:
+      return "Destination address required";
+    case EMSGSIZE:
+      return "Message too long";
+    case EPROTOTYPE:
+      return "Protocol wrong type for socket";
+    case ENOPROTOOPT:
+      return "Protocol not available";
+    case EPROTONOSUPPORT:
+      return "Protocol not supported";
+    case ESOCKTNOSUPPORT:
+      return "Socket type not supported";
+    case EOPNOTSUPP:
+      return "Operation not supported";
+    case EPFNOSUPPORT:
+      return "Protocol family not supported";
+    case EAFNOSUPPORT:
+      return "Address family not supported by protocol";
+    case EADDRINUSE:
+      return "Address already in use";
+    case EADDRNOTAVAIL:
+      return "Cannot assign requested address";
+    case ENETDOWN:
+      return "Network is down";
+    case ENETUNREACH:
+      return "Network is unreachable";
+    case ENETRESET:
+      return "Network dropped connection on reset";
+    case ECONNABORTED:
+      return "Software caused connection abort";
+    case ECONNRESET:
+      return "Connection reset by peer";
+    case ENOBUFS:
+      return "No buffer space available";
+    case EISCONN:
+      return "Transport endpoint is already connected";
+    case ENOTCONN:
+      return "Transport endpoint is not connected";
+    case ESHUTDOWN:
+      return "Cannot send after transport endpoint shutdown";
+    case ETOOMANYREFS:
+      return "Too many references: cannot splice";
+    case ETIMEDOUT:
+      return "Connection timed out";
+    case ECONNREFUSED:
+      return "Connection refused";
+    case ELOOP:
+      return "Too many levels of symbolic links";
+    case EHOSTDOWN:
+      return "Host is down";
+    case EHOSTUNREACH:
+      return "No route to host";
+    case EPROCLIM:
+      return "Too many processes";
+    case EUSERS:
+      return "Too many users";
+    case EDQUOT:
+      return "Disk quota exceeded";
+    case ESTALE:
+      return "Stale NFS file handle";
+    case EREMOTE:
+      return "Object is remote";
+#  if HAVE_WINSOCK2_H
+    /* WSA_INVALID_HANDLE maps to EBADF */
+    /* WSA_NOT_ENOUGH_MEMORY maps to ENOMEM */
+    /* WSA_INVALID_PARAMETER maps to EINVAL */
+    case WSA_OPERATION_ABORTED:
+      return "Overlapped operation aborted";
+    case WSA_IO_INCOMPLETE:
+      return "Overlapped I/O event object not in signaled state";
+    case WSA_IO_PENDING:
+      return "Overlapped operations will complete later";
+    /* WSAEINTR maps to EINTR */
+    /* WSAEBADF maps to EBADF */
+    /* WSAEACCES maps to EACCES */
+    /* WSAEFAULT maps to EFAULT */
+    /* WSAEINVAL maps to EINVAL */
+    /* WSAEMFILE maos to EMFILE */
+    /* WSAEWOULDBLOCK is EWOULDBLOCK */
+    /* WSAEINPROGRESS is EINPROGRESS */
+    /* WSAEALREADY is EALREADY */
+    /* WSAENOTSOCK is ENOTSOCK */
+    /* WSAEDESTADDRREQ is EDESTADDRREQ */
+    /* WSAEMSGSIZE is EMSGSIZE */
+    /* WSAEPROTOTYPE is EPROTOTYPE */
+    /* WSAENOPROTOOPT is ENOPROTOOPT */
+    /* WSAEPROTONOSUPPORT is EPROTONOSUPPORT */
+    /* WSAESOCKTNOSUPPORT is ESOCKTNOSUPPORT */
+    /* WSAEOPNOTSUPP is EOPNOTSUPP */
+    /* WSAEPFNOSUPPORT is EPFNOSUPPORT */
+    /* WSAEAFNOSUPPORT is EAFNOSUPPORT */
+    /* WSAEADDRINUSE is EADDRINUSE */
+    /* WSAEADDRNOTAVAIL is EADDRNOTAVAIL */
+    /* WSAENETDOWN is ENETDOWN */
+    /* WSAENETUNREACH is ENETUNREACH */
+    /* WSAENETRESET is ENETRESET */
+    /* WSAECONNABORTED is ECONNABORTED */
+    /* WSAECONNRESET is ECONNRESET */
+    /* WSAENOBUFS is ENOBUFS */
+    /* WSAEISCONN is EISCONN */
+    /* WSAENOTCONN is ENOTCONN */
+    /* WSAESHUTDOWN is ESHUTDOWN */
+    /* WSAETOOMANYREFS is ETOOMANYREFS */
+    /* WSAETIMEDOUT is ETIMEDOUT */
+    /* WSAECONNREFUSED is ECONNREFUSED */
+    /* WSAELOOP is ELOOP */
+    /* WSAENAMETOOLONG maps to ENAMETOOLONG */
+    /* WSAEHOSTDOWN is EHOSTDOWN */
+    /* WSAEHOSTUNREACH is EHOSTUNREACH */
+    /* WSAENOTEMPTY maps to ENOTEMPTY */
+    /* WSAEPROCLIM is EPROCLIM */
+    /* WSAEUSERS is EUSERS */
+    /* WSAEDQUOT is EDQUOT */
+    /* WSAESTALE is ESTALE */
+    /* WSAEREMOTE is EREMOTE */
+    case WSASYSNOTREADY:
+      return "Network subsystem is unavailable";
+    case WSAVERNOTSUPPORTED:
+      return "Winsock.dll version out of range";
+    case WSANOTINITIALISED:
+      return "Successful WSAStartup not yet performed";
+    case WSAEDISCON:
+      return "Graceful shutdown in progress";
+    case WSAENOMORE: case WSA_E_NO_MORE:
+      return "No more results";
+    case WSAECANCELLED: case WSA_E_CANCELLED:
+      return "Call was canceled";
+    case WSAEINVALIDPROCTABLE:
+      return "Procedure call table is invalid";
+    case WSAEINVALIDPROVIDER:
+      return "Service provider is invalid";
+    case WSAEPROVIDERFAILEDINIT:
+      return "Service provider failed to initialize";
+    case WSASYSCALLFAILURE:
+      return "System call failure";
+    case WSASERVICE_NOT_FOUND:
+      return "Service not found";
+    case WSATYPE_NOT_FOUND:
+      return "Class type not found";
+    case WSAEREFUSED:
+      return "Database query was refused";
+    case WSAHOST_NOT_FOUND:
+      return "Host not found";
+    case WSATRY_AGAIN:
+      return "Nonauthoritative host not found";
+    case WSANO_RECOVERY:
+      return "Nonrecoverable error";
+    case WSANO_DATA:
+      return "Valid name, no data record of requested type";
+    /* WSA_QOS_* omitted */
+#  endif
+# endif
+
+# if GNULIB_defined_ENOMSG
+    case ENOMSG:
+      return "No message of desired type";
+# endif
+
+# if GNULIB_defined_EIDRM
+    case EIDRM:
+      return "Identifier removed";
+# endif
+
+# if GNULIB_defined_ENOLINK
+    case ENOLINK:
+      return "Link has been severed";
+# endif
+
+# if GNULIB_defined_EPROTO
+    case EPROTO:
+      return "Protocol error";
+# endif
+
+# if GNULIB_defined_EMULTIHOP
+    case EMULTIHOP:
+      return "Multihop attempted";
+# endif
+
+# if GNULIB_defined_EBADMSG
+    case EBADMSG:
+      return "Bad message";
+# endif
+
+# if GNULIB_defined_EOVERFLOW
+    case EOVERFLOW:
+      return "Value too large for defined data type";
+# endif
+
+# if GNULIB_defined_ENOTSUP
+    case ENOTSUP:
+      return "Not supported";
+# endif
+
+# if GNULIB_defined_
+    case ECANCELED:
+      return "Operation canceled";
+# endif
     }
 
-  return result;
+  {
+    char *result = strerror (n);
+
+    if (result == NULL || result[0] == '\0')
+      {
+	static char const fmt[] = "Unknown error (%d)";
+	static char mesg[sizeof fmt + INT_STRLEN_BOUND (n)];
+	sprintf (mesg, fmt, n);
+	return mesg;
+      }
+
+    return result;
+  }
 }
 
 #endif
--- a/m4/strerror.m4
+++ b/m4/strerror.m4
@@ -1,4 +1,4 @@
-# strerror.m4 serial 8
+# strerror.m4 serial 9
 dnl Copyright (C) 2002, 2007-2008 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -7,7 +7,7 @@
 AC_DEFUN([gl_FUNC_STRERROR],
 [
   AC_REQUIRE([gl_FUNC_STRERROR_SEPARATE])
-  if test $gl_cv_func_working_strerror = no; then
+  if test $REPLACE_STRERROR = 1; then
     AC_LIBOBJ([strerror])
     AC_DEFINE_UNQUOTED([REPLACE_STRERROR], [$REPLACE_STRERROR],
       [Define this to 1 if strerror is broken.])
@@ -18,25 +18,38 @@
 AC_DEFUN([gl_FUNC_STRERROR_SEPARATE],
 [
   AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS])
-  AC_CACHE_CHECK([for working strerror function],
-   [gl_cv_func_working_strerror],
-   [AC_RUN_IFELSE(
-      [AC_LANG_PROGRAM(
-	 [[#include <string.h>
-	 ]],
-	 [[return !*strerror (-2);]])],
-      [gl_cv_func_working_strerror=yes],
-      [gl_cv_func_working_strerror=no],
-      [dnl Assume crossbuild works if it compiles.
-       AC_COMPILE_IFELSE(
-	 [AC_LANG_PROGRAM(
-	    [[#include <string.h>
-	    ]],
-	    [[return !*strerror (-2);]])],
-	 [gl_cv_func_working_strerror=yes],
-	 [gl_cv_func_working_strerror=no])])])
-  if test $gl_cv_func_working_strerror = no ; then
+  AC_REQUIRE([gl_HEADER_ERRNO_H])
+  if test -z "$ERRNO_H"; then
+    AC_CACHE_CHECK([for working strerror function],
+     [gl_cv_func_working_strerror],
+     [AC_RUN_IFELSE(
+        [AC_LANG_PROGRAM(
+           [[#include <string.h>
+           ]],
+           [[return !*strerror (-2);]])],
+        [gl_cv_func_working_strerror=yes],
+        [gl_cv_func_working_strerror=no],
+        [dnl Assume crossbuild works if it compiles.
+         AC_COMPILE_IFELSE(
+           [AC_LANG_PROGRAM(
+              [[#include <string.h>
+              ]],
+              [[return !*strerror (-2);]])],
+           [gl_cv_func_working_strerror=yes],
+           [gl_cv_func_working_strerror=no])
+      ])
+    ])
+    if test $gl_cv_func_working_strerror = no; then
+      dnl The system's strerror() fails to return a string for out-of-range
+      dnl integers. Replace it.
+      REPLACE_STRERROR=1
+    fi
+  else
+    dnl The system's strerror() cannot know about the new errno values we add
+    dnl to <errno.h>. Replace it.
     REPLACE_STRERROR=1
+  fi
+  if test $REPLACE_STRERROR = 1; then
     gl_PREREQ_STRERROR
   fi
 ])
@@ -44,4 +57,12 @@
 # Prerequisites of lib/strerror.c.
 AC_DEFUN([gl_PREREQ_STRERROR], [
   AC_CHECK_DECLS([strerror])
+  AC_CHECK_HEADERS_ONCE([sys/socket.h])
+  if test $ac_cv_header_sys_socket_h != yes; then
+    dnl We cannot use AC_CHECK_HEADERS_ONCE here, because that would make
+    dnl the check for those headers unconditional; yet cygwin reports
+    dnl that the headers are present but cannot be compiled (since on
+    dnl cygwin, all socket information should come from sys/socket.h).
+    AC_CHECK_HEADERS([winsock2.h])
+  fi
 ])
--- a/modules/strerror
+++ b/modules/strerror
@@ -6,6 +6,7 @@
 m4/strerror.m4
 
 Depends-on:
+errno
 intprops
 string
 
--- a/tests/test-strerror.c
+++ b/tests/test-strerror.c
@@ -40,10 +40,19 @@
 main (int argc, char **argv)
 {
   char *str;
+
   str = strerror (EACCES);
   ASSERT (str);
   ASSERT (*str);
 
+  str = strerror (ETIMEDOUT);
+  ASSERT (str);
+  ASSERT (*str);
+
+  str = strerror (EOVERFLOW);
+  ASSERT (str);
+  ASSERT (*str);
+
   str = strerror (0);
   ASSERT (str);
   ASSERT (*str);