X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fstrerror_r.c;h=be76b0d37a42c30e6607ebf2812ed3b15b235b02;hb=9b71dd21dd3425978a8b121335bfca267a45a617;hp=d0c7be953e3a05cbc171672e49f1576ed819d148;hpb=23b18247253c80345d5fcf7173c5b734b0b8f434;p=gnulib.git diff --git a/lib/strerror_r.c b/lib/strerror_r.c index d0c7be953..be76b0d37 100644 --- a/lib/strerror_r.c +++ b/lib/strerror_r.c @@ -1,6 +1,6 @@ /* strerror_r.c --- POSIX compatible system error routine - Copyright (C) 2010-2011 Free Software Foundation, Inc. + Copyright (C) 2010-2012 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 @@ -86,6 +86,27 @@ gl_lock_define_initialized(static, strerror_lock) #endif +/* On MSVC, there is no snprintf() function, just a _snprintf(). + It is of lower quality, but sufficient for the simple use here. + We only have to make sure to NUL terminate the result (_snprintf + does not NUL terminate, like strncpy). */ +#if !HAVE_SNPRINTF +static int +local_snprintf (char *buf, size_t buflen, const char *format, ...) +{ + va_list args; + int result; + + va_start (args, format); + result = _vsnprintf (buf, buflen, format, args); + va_end (args); + if (buflen > 0 && (result < 0 || result >= buflen)) + buf[buflen - 1] = '\0'; + return result; +} +# define snprintf local_snprintf +#endif + /* Copy as much of MSG into BUF as possible, without corrupting errno. Return 0 if MSG fit in BUFLEN, otherwise return ERANGE. */ static int @@ -175,17 +196,11 @@ strerror_r (int errnum, char *buf, size_t buflen) ret = strerror_r (errnum, buf, buflen); } # else - /* Solaris 10 does not populate buf on ERANGE. */ ret = strerror_r (errnum, buf, buflen); - if (ret == ERANGE && !*buf) - { - char stackbuf[STACKBUF_LEN]; - if (strerror_r (errnum, stackbuf, sizeof stackbuf) == ERANGE) - /* STACKBUF_LEN should have been large enough. */ - abort (); - safe_copy (buf, buflen, stackbuf); - } + /* Some old implementations may return (-1, EINVAL) instead of EINVAL. */ + if (ret < 0) + ret = errno; # endif # ifdef _AIX @@ -203,28 +218,36 @@ strerror_r (int errnum, char *buf, size_t buflen) if (buflen <= len) ret = ERANGE; } -# endif - - /* Some old implementations may return (-1, EINVAL) instead of EINVAL. */ - if (ret < 0) - ret = errno; +# else + /* Solaris 10 does not populate buf on ERANGE. OpenBSD 4.7 + truncates early on ERANGE rather than return a partial integer. + We prefer the maximal string. We set buf[0] earlier, and we + know of no implementation that modifies buf to be an + unterminated string, so this strlen should be portable in + practice (rather than pulling in a safer strnlen). */ + if (ret == ERANGE && strlen (buf) < buflen - 1) + { + char stackbuf[STACKBUF_LEN]; - /* FreeBSD rejects 0; see http://austingroupbugs.net/view.php?id=382. */ - if (errnum == 0 && ret == EINVAL) - ret = safe_copy (buf, buflen, "Success"); + /* STACKBUF_LEN should have been large enough. */ + if (strerror_r (errnum, stackbuf, sizeof stackbuf) == ERANGE) + abort (); + safe_copy (buf, buflen, stackbuf); + } +# endif #else /* USE_SYSTEM_STRERROR */ /* Try to do what strerror (errnum) does, but without clobbering the buffer used by strerror(). */ -# if defined __NetBSD__ || defined __hpux || ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) || defined __CYGWIN__ /* NetBSD, HP-UX, native Win32, Cygwin */ +# if defined __NetBSD__ || defined __hpux || ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) || defined __CYGWIN__ /* NetBSD, HP-UX, native Windows, Cygwin */ - /* NetBSD: sys_nerr, sys_errlist are declared through _NETBSD_SOURCE - and above. - HP-UX: sys_nerr, sys_errlist are declared explicitly above. - native Win32: sys_nerr, sys_errlist are declared in . - Cygwin: sys_nerr, sys_errlist are declared in . */ + /* NetBSD: sys_nerr, sys_errlist are declared through _NETBSD_SOURCE + and above. + HP-UX: sys_nerr, sys_errlist are declared explicitly above. + native Windows: sys_nerr, sys_errlist are declared in . + Cygwin: sys_nerr, sys_errlist are declared in . */ if (errnum >= 0 && errnum < sys_nerr) { # if HAVE_CATGETS && (defined __NetBSD__ || defined __hpux)