Re: Allowing printf("%m") only where it actually works - Mailing list pgsql-hackers

From Tom Lane
Subject Re: Allowing printf("%m") only where it actually works
Date
Msg-id 1304.1536774001@sss.pgh.pa.us
Whole thread Raw
In response to Re: Allowing printf("%m") only where it actually works  (Michael Paquier <michael@paquier.xyz>)
Responses Re: Allowing printf("%m") only where it actually works
List pgsql-hackers
Michael Paquier <michael@paquier.xyz> writes:
> I would have liked to look at this patch in details, but it failed to
> apply.  Could you rebase?

Ah, yeah, the dlopen patch touched a couple of the same places.
Rebase attached --- no substantive changes.

            regards, tom lane

diff --git a/configure b/configure
index dd77742..1aefc57 100755
*** a/configure
--- b/configure
*************** esac
*** 15602,15620 ****

  fi

- ac_fn_c_check_func "$LINENO" "strerror" "ac_cv_func_strerror"
- if test "x$ac_cv_func_strerror" = xyes; then :
-   $as_echo "#define HAVE_STRERROR 1" >>confdefs.h
-
- else
-   case " $LIBOBJS " in
-   *" strerror.$ac_objext "* ) ;;
-   *) LIBOBJS="$LIBOBJS strerror.$ac_objext"
-  ;;
- esac
-
- fi
-
  ac_fn_c_check_func "$LINENO" "strlcat" "ac_cv_func_strlcat"
  if test "x$ac_cv_func_strlcat" = xyes; then :
    $as_echo "#define HAVE_STRLCAT 1" >>confdefs.h
--- 15602,15607 ----
diff --git a/configure.in b/configure.in
index 3ada48b..3a23913 100644
*** a/configure.in
--- b/configure.in
*************** else
*** 1660,1666 ****
    AC_CHECK_FUNCS([fpclass fp_class fp_class_d class], [break])
  fi

! AC_REPLACE_FUNCS([crypt dlopen fls getopt getrusage inet_aton mkdtemp random rint srandom strerror strlcat strlcpy
strnlen])

  case $host_os in

--- 1660,1666 ----
    AC_CHECK_FUNCS([fpclass fp_class fp_class_d class], [break])
  fi

! AC_REPLACE_FUNCS([crypt dlopen fls getopt getrusage inet_aton mkdtemp random rint srandom strlcat strlcpy strnlen])

  case $host_os in

diff --git a/src/backend/port/win32/socket.c b/src/backend/port/win32/socket.c
index f4356fe..af35cfb 100644
*** a/src/backend/port/win32/socket.c
--- b/src/backend/port/win32/socket.c
*************** pgwin32_select(int nfds, fd_set *readfds
*** 690,728 ****
          memcpy(writefds, &outwritefds, sizeof(fd_set));
      return nummatches;
  }
-
-
- /*
-  * Return win32 error string, since strerror can't
-  * handle winsock codes
-  */
- static char wserrbuf[256];
- const char *
- pgwin32_socket_strerror(int err)
- {
-     static HANDLE handleDLL = INVALID_HANDLE_VALUE;
-
-     if (handleDLL == INVALID_HANDLE_VALUE)
-     {
-         handleDLL = LoadLibraryEx("netmsg.dll", NULL, DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE);
-         if (handleDLL == NULL)
-             ereport(FATAL,
-                     (errmsg_internal("could not load netmsg.dll: error code %lu", GetLastError())));
-     }
-
-     ZeroMemory(&wserrbuf, sizeof(wserrbuf));
-     if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS |
-                       FORMAT_MESSAGE_FROM_SYSTEM |
-                       FORMAT_MESSAGE_FROM_HMODULE,
-                       handleDLL,
-                       err,
-                       MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
-                       wserrbuf,
-                       sizeof(wserrbuf) - 1,
-                       NULL) == 0)
-     {
-         /* Failed to get id */
-         sprintf(wserrbuf, "unrecognized winsock error %d", err);
-     }
-     return wserrbuf;
- }
--- 690,692 ----
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 16531f7..22e5d87 100644
*** a/src/backend/utils/error/elog.c
--- b/src/backend/utils/error/elog.c
*************** static void send_message_to_server_log(E
*** 178,185 ****
  static void write_pipe_chunks(char *data, int len, int dest);
  static void send_message_to_frontend(ErrorData *edata);
  static char *expand_fmt_string(const char *fmt, ErrorData *edata);
- static const char *useful_strerror(int errnum);
- static const char *get_errno_symbol(int errnum);
  static const char *error_severity(int elevel);
  static void append_with_tabs(StringInfo buf, const char *str);
  static bool is_log_level_output(int elevel, int log_min_level);
--- 178,183 ----
*************** expand_fmt_string(const char *fmt, Error
*** 3360,3366 ****
                   */
                  const char *cp2;

!                 cp2 = useful_strerror(edata->saved_errno);
                  for (; *cp2; cp2++)
                  {
                      if (*cp2 == '%')
--- 3358,3364 ----
                   */
                  const char *cp2;

!                 cp2 = strerror(edata->saved_errno);
                  for (; *cp2; cp2++)
                  {
                      if (*cp2 == '%')
*************** expand_fmt_string(const char *fmt, Error
*** 3384,3602 ****


  /*
-  * A slightly cleaned-up version of strerror()
-  */
- static const char *
- useful_strerror(int errnum)
- {
-     /* this buffer is only used if strerror() and get_errno_symbol() fail */
-     static char errorstr_buf[48];
-     const char *str;
-
- #ifdef WIN32
-     /* Winsock error code range, per WinError.h */
-     if (errnum >= 10000 && errnum <= 11999)
-         return pgwin32_socket_strerror(errnum);
- #endif
-     str = strerror(errnum);
-
-     /*
-      * Some strerror()s return an empty string for out-of-range errno.  This
-      * is ANSI C spec compliant, but not exactly useful.  Also, we may get
-      * back strings of question marks if libc cannot transcode the message to
-      * the codeset specified by LC_CTYPE.  If we get nothing useful, first try
-      * get_errno_symbol(), and if that fails, print the numeric errno.
-      */
-     if (str == NULL || *str == '\0' || *str == '?')
-         str = get_errno_symbol(errnum);
-
-     if (str == NULL)
-     {
-         snprintf(errorstr_buf, sizeof(errorstr_buf),
-         /*------
-           translator: This string will be truncated at 47
-           characters expanded. */
-                  _("operating system error %d"), errnum);
-         str = errorstr_buf;
-     }
-
-     return str;
- }
-
- /*
-  * Returns a symbol (e.g. "ENOENT") for an errno code.
-  * Returns NULL if the code is unrecognized.
-  */
- static const char *
- get_errno_symbol(int errnum)
- {
-     switch (errnum)
-     {
-         case E2BIG:
-             return "E2BIG";
-         case EACCES:
-             return "EACCES";
- #ifdef EADDRINUSE
-         case EADDRINUSE:
-             return "EADDRINUSE";
- #endif
- #ifdef EADDRNOTAVAIL
-         case EADDRNOTAVAIL:
-             return "EADDRNOTAVAIL";
- #endif
-         case EAFNOSUPPORT:
-             return "EAFNOSUPPORT";
- #ifdef EAGAIN
-         case EAGAIN:
-             return "EAGAIN";
- #endif
- #ifdef EALREADY
-         case EALREADY:
-             return "EALREADY";
- #endif
-         case EBADF:
-             return "EBADF";
- #ifdef EBADMSG
-         case EBADMSG:
-             return "EBADMSG";
- #endif
-         case EBUSY:
-             return "EBUSY";
-         case ECHILD:
-             return "ECHILD";
- #ifdef ECONNABORTED
-         case ECONNABORTED:
-             return "ECONNABORTED";
- #endif
-         case ECONNREFUSED:
-             return "ECONNREFUSED";
- #ifdef ECONNRESET
-         case ECONNRESET:
-             return "ECONNRESET";
- #endif
-         case EDEADLK:
-             return "EDEADLK";
-         case EDOM:
-             return "EDOM";
-         case EEXIST:
-             return "EEXIST";
-         case EFAULT:
-             return "EFAULT";
-         case EFBIG:
-             return "EFBIG";
- #ifdef EHOSTUNREACH
-         case EHOSTUNREACH:
-             return "EHOSTUNREACH";
- #endif
-         case EIDRM:
-             return "EIDRM";
-         case EINPROGRESS:
-             return "EINPROGRESS";
-         case EINTR:
-             return "EINTR";
-         case EINVAL:
-             return "EINVAL";
-         case EIO:
-             return "EIO";
- #ifdef EISCONN
-         case EISCONN:
-             return "EISCONN";
- #endif
-         case EISDIR:
-             return "EISDIR";
- #ifdef ELOOP
-         case ELOOP:
-             return "ELOOP";
- #endif
-         case EMFILE:
-             return "EMFILE";
-         case EMLINK:
-             return "EMLINK";
-         case EMSGSIZE:
-             return "EMSGSIZE";
-         case ENAMETOOLONG:
-             return "ENAMETOOLONG";
-         case ENFILE:
-             return "ENFILE";
-         case ENOBUFS:
-             return "ENOBUFS";
-         case ENODEV:
-             return "ENODEV";
-         case ENOENT:
-             return "ENOENT";
-         case ENOEXEC:
-             return "ENOEXEC";
-         case ENOMEM:
-             return "ENOMEM";
-         case ENOSPC:
-             return "ENOSPC";
-         case ENOSYS:
-             return "ENOSYS";
- #ifdef ENOTCONN
-         case ENOTCONN:
-             return "ENOTCONN";
- #endif
-         case ENOTDIR:
-             return "ENOTDIR";
- #if defined(ENOTEMPTY) && (ENOTEMPTY != EEXIST) /* same code on AIX */
-         case ENOTEMPTY:
-             return "ENOTEMPTY";
- #endif
- #ifdef ENOTSOCK
-         case ENOTSOCK:
-             return "ENOTSOCK";
- #endif
- #ifdef ENOTSUP
-         case ENOTSUP:
-             return "ENOTSUP";
- #endif
-         case ENOTTY:
-             return "ENOTTY";
-         case ENXIO:
-             return "ENXIO";
- #if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || (EOPNOTSUPP != ENOTSUP))
-         case EOPNOTSUPP:
-             return "EOPNOTSUPP";
- #endif
- #ifdef EOVERFLOW
-         case EOVERFLOW:
-             return "EOVERFLOW";
- #endif
-         case EPERM:
-             return "EPERM";
-         case EPIPE:
-             return "EPIPE";
-         case EPROTONOSUPPORT:
-             return "EPROTONOSUPPORT";
-         case ERANGE:
-             return "ERANGE";
- #ifdef EROFS
-         case EROFS:
-             return "EROFS";
- #endif
-         case ESRCH:
-             return "ESRCH";
- #ifdef ETIMEDOUT
-         case ETIMEDOUT:
-             return "ETIMEDOUT";
- #endif
- #ifdef ETXTBSY
-         case ETXTBSY:
-             return "ETXTBSY";
- #endif
- #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
-         case EWOULDBLOCK:
-             return "EWOULDBLOCK";
- #endif
-         case EXDEV:
-             return "EXDEV";
-     }
-
-     return NULL;
- }
-
-
- /*
   * error_severity --- get string representing elevel
   *
   * The string is not localized here, but we mark the strings for translation
--- 3382,3387 ----
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 4094e22..705c52b 100644
*** a/src/include/pg_config.h.in
--- b/src/include/pg_config.h.in
***************
*** 531,539 ****
  /* Define to 1 if you have the <stdlib.h> header file. */
  #undef HAVE_STDLIB_H

- /* Define to 1 if you have the `strerror' function. */
- #undef HAVE_STRERROR
-
  /* Define to 1 if you have the `strerror_r' function. */
  #undef HAVE_STRERROR_R

--- 531,536 ----
diff --git a/src/include/pg_config.h.win32 b/src/include/pg_config.h.win32
index 6618b43..eafe377 100644
*** a/src/include/pg_config.h.win32
--- b/src/include/pg_config.h.win32
***************
*** 402,412 ****
  /* Define to 1 if you have the <stdlib.h> header file. */
  #define HAVE_STDLIB_H 1

- /* Define to 1 if you have the `strerror' function. */
- #ifndef HAVE_STRERROR
- #define HAVE_STRERROR 1
- #endif
-
  /* Define to 1 if you have the `strerror_r' function. */
  /* #undef HAVE_STRERROR_R */

--- 402,407 ----
diff --git a/src/include/port.h b/src/include/port.h
index d927561..bffc773 100644
*** a/src/include/port.h
--- b/src/include/port.h
*************** extern int    pg_printf(const char *fmt,...
*** 189,194 ****
--- 189,198 ----
  #endif
  #endif                            /* USE_REPL_SNPRINTF */

+ /* Replace strerror() with our own, somewhat more robust wrapper */
+ extern char *pg_strerror(int errnum);
+ #define strerror pg_strerror
+
  /* Portable prompt handling */
  extern void simple_prompt(const char *prompt, char *destination, size_t destlen,
                bool echo);
diff --git a/src/include/port/win32_port.h b/src/include/port/win32_port.h
index b398cd3..360dbdf 100644
*** a/src/include/port/win32_port.h
--- b/src/include/port/win32_port.h
*************** extern int    pgwin32_safestat(const char *
*** 322,329 ****
   * Supplement to <errno.h>.
   *
   * We redefine network-related Berkeley error symbols as the corresponding WSA
!  * constants.  This allows elog.c to recognize them as being in the Winsock
!  * error code range and pass them off to pgwin32_socket_strerror(), since
   * Windows' version of plain strerror() won't cope.  Note that this will break
   * if these names are used for anything else besides Windows Sockets errors.
   * See TranslateSocketError() when changing this list.
--- 322,329 ----
   * Supplement to <errno.h>.
   *
   * We redefine network-related Berkeley error symbols as the corresponding WSA
!  * constants. This allows strerror.c to recognize them as being in the Winsock
!  * error code range and pass them off to win32_socket_strerror(), since
   * Windows' version of plain strerror() won't cope.  Note that this will break
   * if these names are used for anything else besides Windows Sockets errors.
   * See TranslateSocketError() when changing this list.
*************** int            pgwin32_connect(SOCKET s, const st
*** 456,463 ****
  int            pgwin32_select(int nfds, fd_set *readfs, fd_set *writefds, fd_set *exceptfds, const struct timeval
*timeout);
  int            pgwin32_recv(SOCKET s, char *buf, int len, int flags);
  int            pgwin32_send(SOCKET s, const void *buf, int len, int flags);
-
- const char *pgwin32_socket_strerror(int err);
  int            pgwin32_waitforsinglesocket(SOCKET s, int what, int timeout);

  extern int    pgwin32_noblock;
--- 456,461 ----
diff --git a/src/interfaces/ecpg/compatlib/.gitignore b/src/interfaces/ecpg/compatlib/.gitignore
index ad5ba13..8b9aa95 100644
*** a/src/interfaces/ecpg/compatlib/.gitignore
--- b/src/interfaces/ecpg/compatlib/.gitignore
***************
*** 2,5 ****
--- 2,6 ----
  /blibecpg_compatdll.def
  /exports.list
  /snprintf.c
+ /strerror.c
  /strnlen.c
diff --git a/src/interfaces/ecpg/compatlib/Makefile b/src/interfaces/ecpg/compatlib/Makefile
index ebfd895..b7bd162 100644
*** a/src/interfaces/ecpg/compatlib/Makefile
--- b/src/interfaces/ecpg/compatlib/Makefile
*************** SHLIB_EXPORTS = exports.txt
*** 31,37 ****
  # Need to recompile any libpgport object files
  LIBS := $(filter-out -lpgport, $(LIBS))

! OBJS= informix.o $(filter snprintf.o strnlen.o, $(LIBOBJS)) $(WIN32RES)

  PKG_CONFIG_REQUIRES_PRIVATE = libecpg libpgtypes

--- 31,37 ----
  # Need to recompile any libpgport object files
  LIBS := $(filter-out -lpgport, $(LIBS))

! OBJS= informix.o strerror.o $(filter snprintf.o strnlen.o, $(LIBOBJS)) $(WIN32RES)

  PKG_CONFIG_REQUIRES_PRIVATE = libecpg libpgtypes

*************** submake-pgtypeslib:
*** 48,54 ****
  # Shared library stuff
  include $(top_srcdir)/src/Makefile.shlib

! snprintf.c strnlen.c: % : $(top_srcdir)/src/port/%
      rm -f $@ && $(LN_S) $< .

  install: all installdirs install-lib
--- 48,54 ----
  # Shared library stuff
  include $(top_srcdir)/src/Makefile.shlib

! snprintf.c strerror.c strnlen.c: % : $(top_srcdir)/src/port/%
      rm -f $@ && $(LN_S) $< .

  install: all installdirs install-lib
*************** installdirs: installdirs-lib
*** 58,63 ****
  uninstall: uninstall-lib

  clean distclean: clean-lib
!     rm -f $(OBJS) snprintf.c strnlen.c

  maintainer-clean: distclean maintainer-clean-lib
--- 58,63 ----
  uninstall: uninstall-lib

  clean distclean: clean-lib
!     rm -f $(OBJS) snprintf.c strerror.c strnlen.c

  maintainer-clean: distclean maintainer-clean-lib
diff --git a/src/interfaces/ecpg/ecpglib/.gitignore b/src/interfaces/ecpg/ecpglib/.gitignore
index 1619e97..545c106 100644
*** a/src/interfaces/ecpg/ecpglib/.gitignore
--- b/src/interfaces/ecpg/ecpglib/.gitignore
***************
*** 4,9 ****
--- 4,10 ----
  /path.c
  /pgstrcasecmp.c
  /snprintf.c
+ /strerror.c
  /strlcpy.c
  /strnlen.c
  /thread.c
diff --git a/src/interfaces/ecpg/ecpglib/Makefile b/src/interfaces/ecpg/ecpglib/Makefile
index d25d248..005d25a 100644
*** a/src/interfaces/ecpg/ecpglib/Makefile
--- b/src/interfaces/ecpg/ecpglib/Makefile
*************** override CFLAGS += $(PTHREAD_CFLAGS)
*** 26,32 ****
  LIBS := $(filter-out -lpgport, $(LIBS))

  OBJS= execute.o typename.o descriptor.o sqlda.o data.o error.o prepare.o memory.o \
!     connect.o misc.o path.o pgstrcasecmp.o \
      $(filter snprintf.o strlcpy.o strnlen.o win32setlocale.o isinf.o, $(LIBOBJS)) \
      $(WIN32RES)

--- 26,32 ----
  LIBS := $(filter-out -lpgport, $(LIBS))

  OBJS= execute.o typename.o descriptor.o sqlda.o data.o error.o prepare.o memory.o \
!     connect.o misc.o path.o pgstrcasecmp.o strerror.o \
      $(filter snprintf.o strlcpy.o strnlen.o win32setlocale.o isinf.o, $(LIBOBJS)) \
      $(WIN32RES)

*************** include $(top_srcdir)/src/Makefile.shlib
*** 57,63 ****
  # necessarily use the same object files as the backend uses. Instead,
  # symlink the source files in here and build our own object file.

! path.c pgstrcasecmp.c snprintf.c strlcpy.c strnlen.c thread.c win32setlocale.c isinf.c: % : $(top_srcdir)/src/port/%
      rm -f $@ && $(LN_S) $< .

  misc.o: misc.c $(top_builddir)/src/port/pg_config_paths.h
--- 57,63 ----
  # necessarily use the same object files as the backend uses. Instead,
  # symlink the source files in here and build our own object file.

! path.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c strnlen.c thread.c win32setlocale.c isinf.c: % :
$(top_srcdir)/src/port/%
      rm -f $@ && $(LN_S) $< .

  misc.o: misc.c $(top_builddir)/src/port/pg_config_paths.h
*************** uninstall: uninstall-lib
*** 74,79 ****

  clean distclean: clean-lib
      rm -f $(OBJS)
!     rm -f path.c pgstrcasecmp.c snprintf.c strlcpy.c strnlen.c thread.c win32setlocale.c isinf.c

  maintainer-clean: distclean maintainer-clean-lib
--- 74,79 ----

  clean distclean: clean-lib
      rm -f $(OBJS)
!     rm -f path.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c strnlen.c thread.c win32setlocale.c isinf.c

  maintainer-clean: distclean maintainer-clean-lib
diff --git a/src/interfaces/ecpg/pgtypeslib/.gitignore b/src/interfaces/ecpg/pgtypeslib/.gitignore
index d5f0fae..b3fae08 100644
*** a/src/interfaces/ecpg/pgtypeslib/.gitignore
--- b/src/interfaces/ecpg/pgtypeslib/.gitignore
***************
*** 4,8 ****
--- 4,9 ----
  /pgstrcasecmp.c
  /rint.c
  /snprintf.c
+ /strerror.c
  /string.c
  /strnlen.c
diff --git a/src/interfaces/ecpg/pgtypeslib/Makefile b/src/interfaces/ecpg/pgtypeslib/Makefile
index 29264ce..18b2402 100644
*** a/src/interfaces/ecpg/pgtypeslib/Makefile
--- b/src/interfaces/ecpg/pgtypeslib/Makefile
*************** SHLIB_LINK += $(filter -lm, $(LIBS))
*** 30,36 ****
  SHLIB_EXPORTS = exports.txt

  OBJS= numeric.o datetime.o common.o dt_common.o timestamp.o interval.o \
!     pgstrcasecmp.o \
      $(filter rint.o snprintf.o strnlen.o, $(LIBOBJS)) \
      string.o \
      $(WIN32RES)
--- 30,36 ----
  SHLIB_EXPORTS = exports.txt

  OBJS= numeric.o datetime.o common.o dt_common.o timestamp.o interval.o \
!     pgstrcasecmp.o strerror.o \
      $(filter rint.o snprintf.o strnlen.o, $(LIBOBJS)) \
      string.o \
      $(WIN32RES)
*************** include $(top_srcdir)/src/Makefile.shlib
*** 45,51 ****
  # necessarily use the same object files as the backend uses. Instead,
  # symlink the source files in here and build our own object file.

! pgstrcasecmp.c rint.c snprintf.c strnlen.c: % : $(top_srcdir)/src/port/%
      rm -f $@ && $(LN_S) $< .

  string.c: % : $(top_srcdir)/src/common/%
--- 45,51 ----
  # necessarily use the same object files as the backend uses. Instead,
  # symlink the source files in here and build our own object file.

! pgstrcasecmp.c rint.c snprintf.c strerror.c strnlen.c: % : $(top_srcdir)/src/port/%
      rm -f $@ && $(LN_S) $< .

  string.c: % : $(top_srcdir)/src/common/%
*************** installdirs: installdirs-lib
*** 58,63 ****
  uninstall: uninstall-lib

  clean distclean: clean-lib
!     rm -f $(OBJS) pgstrcasecmp.c rint.c snprintf.c strnlen.c string.c

  maintainer-clean: distclean maintainer-clean-lib
--- 58,63 ----
  uninstall: uninstall-lib

  clean distclean: clean-lib
!     rm -f $(OBJS) pgstrcasecmp.c rint.c snprintf.c strerror.c strnlen.c string.c

  maintainer-clean: distclean maintainer-clean-lib
diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile
index ec0122a..8324f4f 100644
*** a/src/interfaces/libpq/Makefile
--- b/src/interfaces/libpq/Makefile
*************** OBJS=    fe-auth.o fe-auth-scram.o fe-conne
*** 36,44 ****
      libpq-events.o
  # libpgport C files we always use
  OBJS += chklocale.o inet_net_ntop.o noblock.o pgstrcasecmp.o pqsignal.o \
!     thread.o
  # libpgport C files that are needed if identified by configure
! OBJS += $(filter crypt.o getaddrinfo.o getpeereid.o inet_aton.o open.o system.o snprintf.o strerror.o strlcpy.o
strnlen.owin32error.o win32setlocale.o, $(LIBOBJS)) 

  ifeq ($(enable_strong_random), yes)
  OBJS += pg_strong_random.o
--- 36,44 ----
      libpq-events.o
  # libpgport C files we always use
  OBJS += chklocale.o inet_net_ntop.o noblock.o pgstrcasecmp.o pqsignal.o \
!     strerror.o thread.o
  # libpgport C files that are needed if identified by configure
! OBJS += $(filter crypt.o getaddrinfo.o getpeereid.o inet_aton.o open.o system.o snprintf.o strlcpy.o strnlen.o
win32error.owin32setlocale.o, $(LIBOBJS)) 

  ifeq ($(enable_strong_random), yes)
  OBJS += pg_strong_random.o
diff --git a/src/pl/plpython/plpython.h b/src/pl/plpython/plpython.h
index 5c2e6a8..6cc323a 100644
*** a/src/pl/plpython/plpython.h
--- b/src/pl/plpython/plpython.h
***************
*** 27,33 ****
   */
  #undef _POSIX_C_SOURCE
  #undef _XOPEN_SOURCE
- #undef HAVE_STRERROR
  #undef HAVE_TZNAME

  /*
--- 27,32 ----
diff --git a/src/port/Makefile b/src/port/Makefile
index d7467fb..b3a10ba 100644
*** a/src/port/Makefile
--- b/src/port/Makefile
*************** LIBS += $(PTHREAD_LIBS)
*** 33,39 ****
  OBJS = $(LIBOBJS) $(PG_CRC32C_OBJS) chklocale.o erand48.o inet_net_ntop.o \
      noblock.o path.o pgcheckdir.o pgmkdirp.o pgsleep.o \
      pgstrcasecmp.o pqsignal.o \
!     qsort.o qsort_arg.o quotes.o sprompt.o tar.o thread.o

  ifeq ($(enable_strong_random), yes)
  OBJS += pg_strong_random.o
--- 33,39 ----
  OBJS = $(LIBOBJS) $(PG_CRC32C_OBJS) chklocale.o erand48.o inet_net_ntop.o \
      noblock.o path.o pgcheckdir.o pgmkdirp.o pgsleep.o \
      pgstrcasecmp.o pqsignal.o \
!     qsort.o qsort_arg.o quotes.o sprompt.o strerror.o tar.o thread.o

  ifeq ($(enable_strong_random), yes)
  OBJS += pg_strong_random.o
diff --git a/src/port/strerror.c b/src/port/strerror.c
index e92ebc9..e3393eb 100644
*** a/src/port/strerror.c
--- b/src/port/strerror.c
***************
*** 1,30 ****
! /* src/port/strerror.c */
!
! /*
!  * strerror - map error number to descriptive string
   *
!  * This version is obviously somewhat Unix-specific.
   *
!  * based on code by Henry Spencer
!  * modified for ANSI by D'Arcy J.M. Cain
   */
-
  #include "c.h"


! extern const char *const sys_errlist[];
! extern int    sys_nerr;

! const char *
! strerror(int errnum)
  {
!     static char buf[24];

!     if (errnum < 0 || errnum > sys_nerr)
      {
!         sprintf(buf, _("unrecognized error %d"), errnum);
!         return buf;
      }

!     return sys_errlist[errnum];
  }
--- 1,285 ----
! /*-------------------------------------------------------------------------
   *
!  * strerror.c
!  *      Replacement for standard strerror() function
   *
!  * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
!  * Portions Copyright (c) 1994, Regents of the University of California
!  *
!  *
!  * IDENTIFICATION
!  *      src/port/strerror.c
!  *
!  *-------------------------------------------------------------------------
   */
  #include "c.h"

+ /*
+  * Within this file, "strerror" means the platform's function not pg_strerror
+  */
+ #undef strerror

! static char *get_errno_symbol(int errnum);
! #ifdef WIN32
! static char *win32_socket_strerror(int errnum);
! #endif

!
! /*
!  * A slightly cleaned-up version of strerror()
!  */
! char *
! pg_strerror(int errnum)
  {
!     /* this buffer is only used if strerror() and get_errno_symbol() fail */
!     static char errorstr_buf[48];
!     char       *str;

!     /* If it's a Windows Winsock error, that needs special handling */
! #ifdef WIN32
!     /* Winsock error code range, per WinError.h */
!     if (errnum >= 10000 && errnum <= 11999)
!         return win32_socket_strerror(errnum);
! #endif
!
!     /* Try the platform's strerror() */
!     str = strerror(errnum);
!
!     /*
!      * Some strerror()s return an empty string for out-of-range errno.  This
!      * is ANSI C spec compliant, but not exactly useful.  Also, we may get
!      * back strings of question marks if libc cannot transcode the message to
!      * the codeset specified by LC_CTYPE.  If we get nothing useful, first try
!      * get_errno_symbol(), and if that fails, print the numeric errno.
!      */
!     if (str == NULL || *str == '\0' || *str == '?')
!         str = get_errno_symbol(errnum);
!
!     if (str == NULL)
      {
!         snprintf(errorstr_buf, sizeof(errorstr_buf),
!         /*------
!           translator: This string will be truncated at 47
!           characters expanded. */
!                  _("operating system error %d"), errnum);
!         str = errorstr_buf;
      }

!     return str;
  }
+
+ /*
+  * Returns a symbol (e.g. "ENOENT") for an errno code.
+  * Returns NULL if the code is unrecognized.
+  */
+ static char *
+ get_errno_symbol(int errnum)
+ {
+     switch (errnum)
+     {
+         case E2BIG:
+             return "E2BIG";
+         case EACCES:
+             return "EACCES";
+ #ifdef EADDRINUSE
+         case EADDRINUSE:
+             return "EADDRINUSE";
+ #endif
+ #ifdef EADDRNOTAVAIL
+         case EADDRNOTAVAIL:
+             return "EADDRNOTAVAIL";
+ #endif
+         case EAFNOSUPPORT:
+             return "EAFNOSUPPORT";
+ #ifdef EAGAIN
+         case EAGAIN:
+             return "EAGAIN";
+ #endif
+ #ifdef EALREADY
+         case EALREADY:
+             return "EALREADY";
+ #endif
+         case EBADF:
+             return "EBADF";
+ #ifdef EBADMSG
+         case EBADMSG:
+             return "EBADMSG";
+ #endif
+         case EBUSY:
+             return "EBUSY";
+         case ECHILD:
+             return "ECHILD";
+ #ifdef ECONNABORTED
+         case ECONNABORTED:
+             return "ECONNABORTED";
+ #endif
+         case ECONNREFUSED:
+             return "ECONNREFUSED";
+ #ifdef ECONNRESET
+         case ECONNRESET:
+             return "ECONNRESET";
+ #endif
+         case EDEADLK:
+             return "EDEADLK";
+         case EDOM:
+             return "EDOM";
+         case EEXIST:
+             return "EEXIST";
+         case EFAULT:
+             return "EFAULT";
+         case EFBIG:
+             return "EFBIG";
+ #ifdef EHOSTUNREACH
+         case EHOSTUNREACH:
+             return "EHOSTUNREACH";
+ #endif
+         case EIDRM:
+             return "EIDRM";
+         case EINPROGRESS:
+             return "EINPROGRESS";
+         case EINTR:
+             return "EINTR";
+         case EINVAL:
+             return "EINVAL";
+         case EIO:
+             return "EIO";
+ #ifdef EISCONN
+         case EISCONN:
+             return "EISCONN";
+ #endif
+         case EISDIR:
+             return "EISDIR";
+ #ifdef ELOOP
+         case ELOOP:
+             return "ELOOP";
+ #endif
+         case EMFILE:
+             return "EMFILE";
+         case EMLINK:
+             return "EMLINK";
+         case EMSGSIZE:
+             return "EMSGSIZE";
+         case ENAMETOOLONG:
+             return "ENAMETOOLONG";
+         case ENFILE:
+             return "ENFILE";
+         case ENOBUFS:
+             return "ENOBUFS";
+         case ENODEV:
+             return "ENODEV";
+         case ENOENT:
+             return "ENOENT";
+         case ENOEXEC:
+             return "ENOEXEC";
+         case ENOMEM:
+             return "ENOMEM";
+         case ENOSPC:
+             return "ENOSPC";
+         case ENOSYS:
+             return "ENOSYS";
+ #ifdef ENOTCONN
+         case ENOTCONN:
+             return "ENOTCONN";
+ #endif
+         case ENOTDIR:
+             return "ENOTDIR";
+ #if defined(ENOTEMPTY) && (ENOTEMPTY != EEXIST) /* same code on AIX */
+         case ENOTEMPTY:
+             return "ENOTEMPTY";
+ #endif
+ #ifdef ENOTSOCK
+         case ENOTSOCK:
+             return "ENOTSOCK";
+ #endif
+ #ifdef ENOTSUP
+         case ENOTSUP:
+             return "ENOTSUP";
+ #endif
+         case ENOTTY:
+             return "ENOTTY";
+         case ENXIO:
+             return "ENXIO";
+ #if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || (EOPNOTSUPP != ENOTSUP))
+         case EOPNOTSUPP:
+             return "EOPNOTSUPP";
+ #endif
+ #ifdef EOVERFLOW
+         case EOVERFLOW:
+             return "EOVERFLOW";
+ #endif
+         case EPERM:
+             return "EPERM";
+         case EPIPE:
+             return "EPIPE";
+         case EPROTONOSUPPORT:
+             return "EPROTONOSUPPORT";
+         case ERANGE:
+             return "ERANGE";
+ #ifdef EROFS
+         case EROFS:
+             return "EROFS";
+ #endif
+         case ESRCH:
+             return "ESRCH";
+ #ifdef ETIMEDOUT
+         case ETIMEDOUT:
+             return "ETIMEDOUT";
+ #endif
+ #ifdef ETXTBSY
+         case ETXTBSY:
+             return "ETXTBSY";
+ #endif
+ #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
+         case EWOULDBLOCK:
+             return "EWOULDBLOCK";
+ #endif
+         case EXDEV:
+             return "EXDEV";
+     }
+
+     return NULL;
+ }
+
+
+ #ifdef WIN32
+
+ /*
+  * Windows' strerror() doesn't know the Winsock codes, so handle them this way
+  */
+ static char *
+ win32_socket_strerror(int errnum)
+ {
+     static char wserrbuf[256];
+     static HANDLE handleDLL = INVALID_HANDLE_VALUE;
+
+     if (handleDLL == INVALID_HANDLE_VALUE)
+     {
+         handleDLL = LoadLibraryEx("netmsg.dll", NULL,
+                                   DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE);
+         if (handleDLL == NULL)
+         {
+             /* just treat this as an unrecognized error ... */
+             sprintf(wserrbuf, "unrecognized winsock error %d", errnum);
+             return wserrbuf;
+         }
+     }
+
+     ZeroMemory(&wserrbuf, sizeof(wserrbuf));
+     if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS |
+                       FORMAT_MESSAGE_FROM_SYSTEM |
+                       FORMAT_MESSAGE_FROM_HMODULE,
+                       handleDLL,
+                       errnum,
+                       MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
+                       wserrbuf,
+                       sizeof(wserrbuf) - 1,
+                       NULL) == 0)
+     {
+         /* Failed to get id */
+         sprintf(wserrbuf, "unrecognized winsock error %d", errnum);
+     }
+
+     return wserrbuf;
+ }
+
+ #endif                            /* WIN32 */
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index 9ce03ce..2be72f8 100644
*** a/src/tools/msvc/Mkvcbuild.pm
--- b/src/tools/msvc/Mkvcbuild.pm
*************** sub mkvcbuild
*** 96,104 ****
        chklocale.c crypt.c fls.c fseeko.c getrusage.c inet_aton.c random.c
        srandom.c getaddrinfo.c gettimeofday.c inet_net_ntop.c kill.c open.c
        erand48.c snprintf.c strlcat.c strlcpy.c dirmod.c noblock.c path.c
        pg_strong_random.c pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c
        pqsignal.c mkdtemp.c qsort.c qsort_arg.c quotes.c system.c
!       sprompt.c tar.c thread.c getopt.c getopt_long.c dirent.c dlopen.c
        win32env.c win32error.c win32security.c win32setlocale.c);

      push(@pgportfiles, 'rint.c') if ($vsVersion < '12.00');
--- 96,105 ----
        chklocale.c crypt.c fls.c fseeko.c getrusage.c inet_aton.c random.c
        srandom.c getaddrinfo.c gettimeofday.c inet_net_ntop.c kill.c open.c
        erand48.c snprintf.c strlcat.c strlcpy.c dirmod.c noblock.c path.c
+       dirent.c dlopen.c getopt.c getopt_long.c
        pg_strong_random.c pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c
        pqsignal.c mkdtemp.c qsort.c qsort_arg.c quotes.c system.c
!       sprompt.c strerror.c tar.c thread.c
        win32env.c win32error.c win32security.c win32setlocale.c);

      push(@pgportfiles, 'rint.c') if ($vsVersion < '12.00');
diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index eedaf12..fb58c94 100644
*** a/config/c-compiler.m4
--- b/config/c-compiler.m4
*************** fi])# PGAC_C_SIGNED
*** 20,34 ****
  # PGAC_C_PRINTF_ARCHETYPE
  # -----------------------
  # Select the format archetype to be used by gcc to check printf-type functions.
! # We prefer "gnu_printf", which matches the features glibc supports, notably
! # %m, 'z' and 'll' width modifiers ('ll' only matters if int64 requires it),
! # and argument order control if we're doing --enable-nls.  On platforms where
! # the native printf doesn't have 'z'/'ll' or arg control, we replace it with
! # src/port/snprintf.c which does, so that the only potential mismatch here is
! # whether or not %m is supported.  We need that for elog/ereport, so we live
! # with the fact that erroneous use of %m in plain printf calls won't be
! # detected.  (It appears that many versions of gcc/clang wouldn't report it
! # even if told to check according to plain printf archetype, anyway.)
  AC_DEFUN([PGAC_PRINTF_ARCHETYPE],
  [AC_CACHE_CHECK([for printf format archetype], pgac_cv_printf_archetype,
  [ac_save_c_werror_flag=$ac_c_werror_flag
--- 20,27 ----
  # PGAC_C_PRINTF_ARCHETYPE
  # -----------------------
  # Select the format archetype to be used by gcc to check printf-type functions.
! # We prefer "gnu_printf", as that most closely matches the features supported
! # by src/port/snprintf.c (particularly the %m conversion spec).
  AC_DEFUN([PGAC_PRINTF_ARCHETYPE],
  [AC_CACHE_CHECK([for printf format archetype], pgac_cv_printf_archetype,
  [ac_save_c_werror_flag=$ac_c_werror_flag
diff --git a/config/c-library.m4 b/config/c-library.m4
index da7fa77..d371f1b 100644
*** a/config/c-library.m4
--- b/config/c-library.m4
*************** AC_DEFUN([PGAC_STRUCT_ADDRINFO],
*** 171,276 ****
  ])])# PGAC_STRUCT_ADDRINFO


- # PGAC_FUNC_SNPRINTF_ARG_CONTROL
- # ---------------------------------------
- # Determine if snprintf supports %1$ argument selection, e.g. %5$ selects
- # the fifth argument after the printf format string.
- # This is not in the C99 standard, but in the Single Unix Specification (SUS).
- # It is used in our language translation strings.
- #
- AC_DEFUN([PGAC_FUNC_SNPRINTF_ARG_CONTROL],
- [AC_MSG_CHECKING([whether snprintf supports argument control])
- AC_CACHE_VAL(pgac_cv_snprintf_arg_control,
- [AC_RUN_IFELSE([AC_LANG_SOURCE([[#include <stdio.h>
- #include <string.h>
-
- int main()
- {
-   char buf[100];
-
-   /* can it swap arguments? */
-   snprintf(buf, 100, "%2\$d %1\$d", 3, 4);
-   if (strcmp(buf, "4 3") != 0)
-     return 1;
-   return 0;
- }]])],
- [pgac_cv_snprintf_arg_control=yes],
- [pgac_cv_snprintf_arg_control=no],
- [pgac_cv_snprintf_arg_control=cross])
- ])dnl AC_CACHE_VAL
- AC_MSG_RESULT([$pgac_cv_snprintf_arg_control])
- ])# PGAC_FUNC_SNPRINTF_ARG_CONTROL
-
- # PGAC_FUNC_SNPRINTF_SIZE_T_SUPPORT
- # ---------------------------------
- # Determine if snprintf supports the z length modifier for printing
- # size_t-sized variables. That's supported by C99 and POSIX but not
- # all platforms play ball, so we must test whether it's working.
- #
- AC_DEFUN([PGAC_FUNC_SNPRINTF_SIZE_T_SUPPORT],
- [AC_MSG_CHECKING([whether snprintf supports the %z modifier])
- AC_CACHE_VAL(pgac_cv_snprintf_size_t_support,
- [AC_RUN_IFELSE([AC_LANG_SOURCE([[#include <stdio.h>
- #include <string.h>
-
- int main()
- {
-   char bufz[100];
-   char buf64[100];
-
-   /*
-    * Print the largest unsigned number fitting in a size_t using both %zu
-    * and the previously-determined format for 64-bit integers.  Note that
-    * we don't run this code unless we know snprintf handles 64-bit ints.
-    */
-   bufz[0] = '\0';  /* in case snprintf fails to emit anything */
-   snprintf(bufz, sizeof(bufz), "%zu", ~((size_t) 0));
-   snprintf(buf64, sizeof(buf64), "%" INT64_MODIFIER "u",
-     (unsigned PG_INT64_TYPE) ~((size_t) 0));
-   if (strcmp(bufz, buf64) != 0)
-     return 1;
-   return 0;
- }]])],
- [pgac_cv_snprintf_size_t_support=yes],
- [pgac_cv_snprintf_size_t_support=no],
- [pgac_cv_snprintf_size_t_support=cross])
- ])dnl AC_CACHE_VAL
- AC_MSG_RESULT([$pgac_cv_snprintf_size_t_support])
- ])# PGAC_FUNC_SNPRINTF_SIZE_T_SUPPORT
-
- # PGAC_FUNC_SNPRINTF_C99_RESULT
- # -----------------------------
- # Determine whether snprintf returns the desired buffer length when
- # it overruns the actual buffer length.  That's required by C99 and POSIX
- # but ancient platforms don't behave that way, so we must test.
- # While we're at it, let's just verify that it doesn't physically overrun
- # the buffer.
- #
- AC_DEFUN([PGAC_FUNC_SNPRINTF_C99_RESULT],
- [AC_MSG_CHECKING([whether snprintf handles buffer overrun per C99])
- AC_CACHE_VAL(pgac_cv_snprintf_c99_result,
- [AC_RUN_IFELSE([AC_LANG_SOURCE([[#include <stdio.h>
- #include <string.h>
-
- int main()
- {
-   char buf[10];
-
-   strcpy(buf, "abcdefghi");
-   if (snprintf(buf, 4, "%d", 123456) != 6)
-     return 1;
-   if (strcmp(buf, "123") != 0 || buf[4] != 'e')
-     return 1;
-   return 0;
- }]])],
- [pgac_cv_snprintf_c99_result=yes],
- [pgac_cv_snprintf_c99_result=no],
- [pgac_cv_snprintf_c99_result=cross])
- ])dnl AC_CACHE_VAL
- AC_MSG_RESULT([$pgac_cv_snprintf_c99_result])
- ])# PGAC_FUNC_SNPRINTF_C99_RESULT
-
-
  # PGAC_TYPE_LOCALE_T
  # ------------------
  # Check for the locale_t type and find the right header file.  macOS
--- 171,176 ----
diff --git a/configure b/configure
index 1aefc57..4eed2f4 100755
*** a/configure
--- b/configure
*************** $as_echo "#define HAVE_PS_STRINGS 1" >>c
*** 15325,15421 ****
  fi


- # We use our snprintf.c emulation if either snprintf() or vsnprintf()
- # is missing.  Yes, there are machines that have only one.  We may
- # also decide to use snprintf.c if snprintf() is present but does not
- # have all the features we need --- see below.
-
- if test "$PORTNAME" = "win32"; then
-   # Win32 gets snprintf.c built unconditionally.
-   #
-   # To properly translate all NLS languages strings, we must support the
-   # *printf() %$ format, which allows *printf() arguments to be selected
-   # by position in the translated string.
-   #
-   # libintl versions < 0.13 use the native *printf() functions, and Win32
-   # *printf() doesn't understand %$, so we must use our /port versions,
-   # which do understand %$. libintl versions >= 0.13 include their own
-   # *printf versions on Win32.  The libintl 0.13 release note text is:
-   #
-   #   C format strings with positions, as they arise when a translator
-   #   needs to reorder a sentence, are now supported on all platforms.
-   #   On those few platforms (NetBSD and Woe32) for which the native
-   #   printf()/fprintf()/... functions don't support such format
-   #   strings, replacements are provided through <libintl.h>.
-   #
-   # We could use libintl >= 0.13's *printf() if we were sure that we had
-   # a libintl >= 0.13 at runtime, but seeing that there is no clean way
-   # to guarantee that, it is best to just use our own, so we are sure to
-   # get %$ support. In include/port.h we disable the *printf() macros
-   # that might have been defined by libintl.
-   #
-   # We do this unconditionally whether NLS is used or not so we are sure
-   # that all Win32 libraries and binaries behave the same.
-   pgac_need_repl_snprintf=yes
- else
-   pgac_need_repl_snprintf=no
-   for ac_func in snprintf
- do :
-   ac_fn_c_check_func "$LINENO" "snprintf" "ac_cv_func_snprintf"
- if test "x$ac_cv_func_snprintf" = xyes; then :
-   cat >>confdefs.h <<_ACEOF
- #define HAVE_SNPRINTF 1
- _ACEOF
-
- else
-   pgac_need_repl_snprintf=yes
- fi
- done
-
-   for ac_func in vsnprintf
- do :
-   ac_fn_c_check_func "$LINENO" "vsnprintf" "ac_cv_func_vsnprintf"
- if test "x$ac_cv_func_vsnprintf" = xyes; then :
-   cat >>confdefs.h <<_ACEOF
- #define HAVE_VSNPRINTF 1
- _ACEOF
-
- else
-   pgac_need_repl_snprintf=yes
- fi
- done
-
- fi
-
-
- # Check whether <stdio.h> declares snprintf() and vsnprintf(); if not,
- # include/c.h will provide declarations.  Note this is a separate test
- # from whether the functions exist in the C library --- there are
- # systems that have the functions but don't bother to declare them :-(
-
- ac_fn_c_check_decl "$LINENO" "snprintf" "ac_cv_have_decl_snprintf" "$ac_includes_default"
- if test "x$ac_cv_have_decl_snprintf" = xyes; then :
-   ac_have_decl=1
- else
-   ac_have_decl=0
- fi
-
- cat >>confdefs.h <<_ACEOF
- #define HAVE_DECL_SNPRINTF $ac_have_decl
- _ACEOF
- ac_fn_c_check_decl "$LINENO" "vsnprintf" "ac_cv_have_decl_vsnprintf" "$ac_includes_default"
- if test "x$ac_cv_have_decl_vsnprintf" = xyes; then :
-   ac_have_decl=1
- else
-   ac_have_decl=0
- fi
-
- cat >>confdefs.h <<_ACEOF
- #define HAVE_DECL_VSNPRINTF $ac_have_decl
- _ACEOF
-
-
-
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isinf" >&5
  $as_echo_n "checking for isinf... " >&6; }
  if ${ac_cv_func_isinf+:} false; then :
--- 15325,15330 ----
*************** fi
*** 16133,16185 ****
  # Run tests below here
  # --------------------

- # For NLS, force use of our snprintf if system's doesn't do arg control.
- # See comment above at snprintf test for details.
- if test "$enable_nls" = yes -a "$pgac_need_repl_snprintf" = no; then
-   { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether snprintf supports argument control" >&5
- $as_echo_n "checking whether snprintf supports argument control... " >&6; }
- if ${pgac_cv_snprintf_arg_control+:} false; then :
-   $as_echo_n "(cached) " >&6
- else
-   if test "$cross_compiling" = yes; then :
-   pgac_cv_snprintf_arg_control=cross
- else
-   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
- /* end confdefs.h.  */
- #include <stdio.h>
- #include <string.h>
-
- int main()
- {
-   char buf[100];
-
-   /* can it swap arguments? */
-   snprintf(buf, 100, "%2\$d %1\$d", 3, 4);
-   if (strcmp(buf, "4 3") != 0)
-     return 1;
-   return 0;
- }
- _ACEOF
- if ac_fn_c_try_run "$LINENO"; then :
-   pgac_cv_snprintf_arg_control=yes
- else
-   pgac_cv_snprintf_arg_control=no
- fi
- rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
-   conftest.$ac_objext conftest.beam conftest.$ac_ext
- fi
-
-
- fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_snprintf_arg_control" >&5
- $as_echo "$pgac_cv_snprintf_arg_control" >&6; }
-
-   if test $pgac_cv_snprintf_arg_control != yes ; then
-     pgac_need_repl_snprintf=yes
-   fi
- fi
-
-

  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether long int is 64 bits" >&5
  $as_echo_n "checking whether long int is 64 bits... " >&6; }
--- 16042,16047 ----
*************** _ACEOF
*** 16359,16366 ****


  # Select the printf length modifier that goes with that, too.
- # (This used to be bound up with replacement-snprintf selection, but now
- # we assume that the native *printf functions use standard length modifiers.)
  if test x"$pg_int64_type" = x"long long int" ; then
    INT64_MODIFIER='"ll"'
  else
--- 16221,16226 ----
*************** cat >>confdefs.h <<_ACEOF
*** 16373,16492 ****
  _ACEOF


- # Force use of our snprintf if the system's doesn't support the %z flag.
- # (Note this test uses PG_INT64_TYPE and INT64_MODIFIER.)
- if test "$pgac_need_repl_snprintf" = no; then
-   { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether snprintf supports the %z modifier" >&5
- $as_echo_n "checking whether snprintf supports the %z modifier... " >&6; }
- if ${pgac_cv_snprintf_size_t_support+:} false; then :
-   $as_echo_n "(cached) " >&6
- else
-   if test "$cross_compiling" = yes; then :
-   pgac_cv_snprintf_size_t_support=cross
- else
-   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
- /* end confdefs.h.  */
- #include <stdio.h>
- #include <string.h>
-
- int main()
- {
-   char bufz[100];
-   char buf64[100];
-
-   /*
-    * Print the largest unsigned number fitting in a size_t using both %zu
-    * and the previously-determined format for 64-bit integers.  Note that
-    * we don't run this code unless we know snprintf handles 64-bit ints.
-    */
-   bufz[0] = '\0';  /* in case snprintf fails to emit anything */
-   snprintf(bufz, sizeof(bufz), "%zu", ~((size_t) 0));
-   snprintf(buf64, sizeof(buf64), "%" INT64_MODIFIER "u",
-     (unsigned PG_INT64_TYPE) ~((size_t) 0));
-   if (strcmp(bufz, buf64) != 0)
-     return 1;
-   return 0;
- }
- _ACEOF
- if ac_fn_c_try_run "$LINENO"; then :
-   pgac_cv_snprintf_size_t_support=yes
- else
-   pgac_cv_snprintf_size_t_support=no
- fi
- rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
-   conftest.$ac_objext conftest.beam conftest.$ac_ext
- fi
-
-
- fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_snprintf_size_t_support" >&5
- $as_echo "$pgac_cv_snprintf_size_t_support" >&6; }
-
-   if test "$pgac_cv_snprintf_size_t_support" != yes; then
-     pgac_need_repl_snprintf=yes
-   fi
- fi
-
- # Force use of our snprintf if the system's doesn't handle buffer overrun
- # as specified by C99.
- if test "$pgac_need_repl_snprintf" = no; then
-   { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether snprintf handles buffer overrun per C99" >&5
- $as_echo_n "checking whether snprintf handles buffer overrun per C99... " >&6; }
- if ${pgac_cv_snprintf_c99_result+:} false; then :
-   $as_echo_n "(cached) " >&6
- else
-   if test "$cross_compiling" = yes; then :
-   pgac_cv_snprintf_c99_result=cross
- else
-   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
- /* end confdefs.h.  */
- #include <stdio.h>
- #include <string.h>
-
- int main()
- {
-   char buf[10];
-
-   strcpy(buf, "abcdefghi");
-   if (snprintf(buf, 4, "%d", 123456) != 6)
-     return 1;
-   if (strcmp(buf, "123") != 0 || buf[4] != 'e')
-     return 1;
-   return 0;
- }
- _ACEOF
- if ac_fn_c_try_run "$LINENO"; then :
-   pgac_cv_snprintf_c99_result=yes
- else
-   pgac_cv_snprintf_c99_result=no
- fi
- rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
-   conftest.$ac_objext conftest.beam conftest.$ac_ext
- fi
-
-
- fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_snprintf_c99_result" >&5
- $as_echo "$pgac_cv_snprintf_c99_result" >&6; }
-
-   if test "$pgac_cv_snprintf_c99_result" != yes; then
-     pgac_need_repl_snprintf=yes
-   fi
- fi
-
- # Now we have checked all the reasons to replace snprintf
- if test $pgac_need_repl_snprintf = yes; then
-
- $as_echo "#define USE_REPL_SNPRINTF 1" >>confdefs.h
-
-   case " $LIBOBJS " in
-   *" snprintf.$ac_objext "* ) ;;
-   *) LIBOBJS="$LIBOBJS snprintf.$ac_objext"
-  ;;
- esac
-
- fi
-
  # has to be down here, rather than with the other builtins, because
  # the test uses PG_INT64_TYPE.
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __builtin_mul_overflow" >&5
--- 16233,16238 ----
diff --git a/configure.in b/configure.in
index 3a23913..f4e0b07 100644
*** a/configure.in
--- b/configure.in
*************** if test "$pgac_cv_var_PS_STRINGS" = yes
*** 1595,1647 ****
  fi


- # We use our snprintf.c emulation if either snprintf() or vsnprintf()
- # is missing.  Yes, there are machines that have only one.  We may
- # also decide to use snprintf.c if snprintf() is present but does not
- # have all the features we need --- see below.
-
- if test "$PORTNAME" = "win32"; then
-   # Win32 gets snprintf.c built unconditionally.
-   #
-   # To properly translate all NLS languages strings, we must support the
-   # *printf() %$ format, which allows *printf() arguments to be selected
-   # by position in the translated string.
-   #
-   # libintl versions < 0.13 use the native *printf() functions, and Win32
-   # *printf() doesn't understand %$, so we must use our /port versions,
-   # which do understand %$. libintl versions >= 0.13 include their own
-   # *printf versions on Win32.  The libintl 0.13 release note text is:
-   #
-   #   C format strings with positions, as they arise when a translator
-   #   needs to reorder a sentence, are now supported on all platforms.
-   #   On those few platforms (NetBSD and Woe32) for which the native
-   #   printf()/fprintf()/... functions don't support such format
-   #   strings, replacements are provided through <libintl.h>.
-   #
-   # We could use libintl >= 0.13's *printf() if we were sure that we had
-   # a libintl >= 0.13 at runtime, but seeing that there is no clean way
-   # to guarantee that, it is best to just use our own, so we are sure to
-   # get %$ support. In include/port.h we disable the *printf() macros
-   # that might have been defined by libintl.
-   #
-   # We do this unconditionally whether NLS is used or not so we are sure
-   # that all Win32 libraries and binaries behave the same.
-   pgac_need_repl_snprintf=yes
- else
-   pgac_need_repl_snprintf=no
-   AC_CHECK_FUNCS(snprintf, [], pgac_need_repl_snprintf=yes)
-   AC_CHECK_FUNCS(vsnprintf, [], pgac_need_repl_snprintf=yes)
- fi
-
-
- # Check whether <stdio.h> declares snprintf() and vsnprintf(); if not,
- # include/c.h will provide declarations.  Note this is a separate test
- # from whether the functions exist in the C library --- there are
- # systems that have the functions but don't bother to declare them :-(
-
- AC_CHECK_DECLS([snprintf, vsnprintf])
-
-
  dnl Cannot use AC_CHECK_FUNC because isinf may be a macro
  AC_CACHE_CHECK([for isinf], ac_cv_func_isinf,
  [AC_LINK_IFELSE([AC_LANG_PROGRAM([
--- 1595,1600 ----
*************** for the exact reason.]])],
*** 1811,1826 ****
  # Run tests below here
  # --------------------

- # For NLS, force use of our snprintf if system's doesn't do arg control.
- # See comment above at snprintf test for details.
- if test "$enable_nls" = yes -a "$pgac_need_repl_snprintf" = no; then
-   PGAC_FUNC_SNPRINTF_ARG_CONTROL
-   if test $pgac_cv_snprintf_arg_control != yes ; then
-     pgac_need_repl_snprintf=yes
-   fi
- fi
-
-
  dnl Check to see if we have a working 64-bit integer type.
  dnl Since Postgres 8.4, we no longer support compilers without a working
  dnl 64-bit type; but we have to determine whether that type is called
--- 1764,1769 ----
*************** AC_DEFINE_UNQUOTED(PG_INT64_TYPE, $pg_in
*** 1843,1850 ****
    [Define to the name of a signed 64-bit integer type.])

  # Select the printf length modifier that goes with that, too.
- # (This used to be bound up with replacement-snprintf selection, but now
- # we assume that the native *printf functions use standard length modifiers.)
  if test x"$pg_int64_type" = x"long long int" ; then
    INT64_MODIFIER='"ll"'
  else
--- 1786,1791 ----
*************** fi
*** 1854,1883 ****
  AC_DEFINE_UNQUOTED(INT64_MODIFIER, $INT64_MODIFIER,
                     [Define to the appropriate printf length modifier for 64-bit ints.])

- # Force use of our snprintf if the system's doesn't support the %z flag.
- # (Note this test uses PG_INT64_TYPE and INT64_MODIFIER.)
- if test "$pgac_need_repl_snprintf" = no; then
-   PGAC_FUNC_SNPRINTF_SIZE_T_SUPPORT
-   if test "$pgac_cv_snprintf_size_t_support" != yes; then
-     pgac_need_repl_snprintf=yes
-   fi
- fi
-
- # Force use of our snprintf if the system's doesn't handle buffer overrun
- # as specified by C99.
- if test "$pgac_need_repl_snprintf" = no; then
-   PGAC_FUNC_SNPRINTF_C99_RESULT
-   if test "$pgac_cv_snprintf_c99_result" != yes; then
-     pgac_need_repl_snprintf=yes
-   fi
- fi
-
- # Now we have checked all the reasons to replace snprintf
- if test $pgac_need_repl_snprintf = yes; then
-   AC_DEFINE(USE_REPL_SNPRINTF, 1, [Use replacement snprintf() functions.])
-   AC_LIBOBJ(snprintf)
- fi
-
  # has to be down here, rather than with the other builtins, because
  # the test uses PG_INT64_TYPE.
  PGAC_C_BUILTIN_OP_OVERFLOW
--- 1795,1800 ----
diff --git a/src/backend/lib/stringinfo.c b/src/backend/lib/stringinfo.c
index 798a823..df7e01f 100644
*** a/src/backend/lib/stringinfo.c
--- b/src/backend/lib/stringinfo.c
*************** resetStringInfo(StringInfo str)
*** 77,88 ****
--- 77,91 ----
  void
  appendStringInfo(StringInfo str, const char *fmt,...)
  {
+     int            save_errno = errno;
+
      for (;;)
      {
          va_list        args;
          int            needed;

          /* Try to format the data. */
+         errno = save_errno;
          va_start(args, fmt);
          needed = appendStringInfoVA(str, fmt, args);
          va_end(args);
*************** appendStringInfo(StringInfo str, const c
*** 105,110 ****
--- 108,116 ----
   * pass the return value to enlargeStringInfo() before trying again; see
   * appendStringInfo for standard usage pattern.
   *
+  * Caution: callers must be sure to preserve their entry-time errno
+  * when looping, in case the fmt contains "%m".
+  *
   * XXX This API is ugly, but there seems no alternative given the C spec's
   * restrictions on what can portably be done with va_list arguments: you have
   * to redo va_start before you can rescan the argument list, and we can't do
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 22e5d87..b9c1130 100644
*** a/src/backend/utils/error/elog.c
--- b/src/backend/utils/error/elog.c
*************** static void write_csvlog(ErrorData *edat
*** 177,183 ****
  static void send_message_to_server_log(ErrorData *edata);
  static void write_pipe_chunks(char *data, int len, int dest);
  static void send_message_to_frontend(ErrorData *edata);
- static char *expand_fmt_string(const char *fmt, ErrorData *edata);
  static const char *error_severity(int elevel);
  static void append_with_tabs(StringInfo buf, const char *str);
  static bool is_log_level_output(int elevel, int log_min_level);
--- 177,182 ----
*************** errcode_for_socket_access(void)
*** 705,717 ****
   */
  #define EVALUATE_MESSAGE(domain, targetfield, appendval, translateit)    \
      { \
-         char           *fmtbuf; \
          StringInfoData    buf; \
          /* Internationalize the error format string */ \
          if ((translateit) && !in_error_recursion_trouble()) \
              fmt = dgettext((domain), fmt);                  \
-         /* Expand %m in format string */ \
-         fmtbuf = expand_fmt_string(fmt, edata); \
          initStringInfo(&buf); \
          if ((appendval) && edata->targetfield) { \
              appendStringInfoString(&buf, edata->targetfield); \
--- 704,713 ----
*************** errcode_for_socket_access(void)
*** 722,736 ****
          { \
              va_list        args; \
              int            needed; \
              va_start(args, fmt); \
!             needed = appendStringInfoVA(&buf, fmtbuf, args); \
              va_end(args); \
              if (needed == 0) \
                  break; \
              enlargeStringInfo(&buf, needed); \
          } \
-         /* Done with expanded fmt */ \
-         pfree(fmtbuf); \
          /* Save the completed message into the stack item */ \
          if (edata->targetfield) \
              pfree(edata->targetfield); \
--- 718,731 ----
          { \
              va_list        args; \
              int            needed; \
+             errno = edata->saved_errno; \
              va_start(args, fmt); \
!             needed = appendStringInfoVA(&buf, fmt, args); \
              va_end(args); \
              if (needed == 0) \
                  break; \
              enlargeStringInfo(&buf, needed); \
          } \
          /* Save the completed message into the stack item */ \
          if (edata->targetfield) \
              pfree(edata->targetfield); \
*************** errcode_for_socket_access(void)
*** 746,760 ****
  #define EVALUATE_MESSAGE_PLURAL(domain, targetfield, appendval)  \
      { \
          const char       *fmt; \
-         char           *fmtbuf; \
          StringInfoData    buf; \
          /* Internationalize the error format string */ \
          if (!in_error_recursion_trouble()) \
              fmt = dngettext((domain), fmt_singular, fmt_plural, n); \
          else \
              fmt = (n == 1 ? fmt_singular : fmt_plural); \
-         /* Expand %m in format string */ \
-         fmtbuf = expand_fmt_string(fmt, edata); \
          initStringInfo(&buf); \
          if ((appendval) && edata->targetfield) { \
              appendStringInfoString(&buf, edata->targetfield); \
--- 741,752 ----
*************** errcode_for_socket_access(void)
*** 765,779 ****
          { \
              va_list        args; \
              int            needed; \
              va_start(args, n); \
!             needed = appendStringInfoVA(&buf, fmtbuf, args); \
              va_end(args); \
              if (needed == 0) \
                  break; \
              enlargeStringInfo(&buf, needed); \
          } \
-         /* Done with expanded fmt */ \
-         pfree(fmtbuf); \
          /* Save the completed message into the stack item */ \
          if (edata->targetfield) \
              pfree(edata->targetfield); \
--- 757,770 ----
          { \
              va_list        args; \
              int            needed; \
+             errno = edata->saved_errno; \
              va_start(args, n); \
!             needed = appendStringInfoVA(&buf, fmt, args); \
              va_end(args); \
              if (needed == 0) \
                  break; \
              enlargeStringInfo(&buf, needed); \
          } \
          /* Save the completed message into the stack item */ \
          if (edata->targetfield) \
              pfree(edata->targetfield); \
*************** send_message_to_frontend(ErrorData *edat
*** 3329,3387 ****


  /*
-  * expand_fmt_string --- process special format codes in a format string
-  *
-  * We must replace %m with the appropriate strerror string, since vsnprintf
-  * won't know what to do with it.
-  *
-  * The result is a palloc'd string.
-  */
- static char *
- expand_fmt_string(const char *fmt, ErrorData *edata)
- {
-     StringInfoData buf;
-     const char *cp;
-
-     initStringInfo(&buf);
-
-     for (cp = fmt; *cp; cp++)
-     {
-         if (cp[0] == '%' && cp[1] != '\0')
-         {
-             cp++;
-             if (*cp == 'm')
-             {
-                 /*
-                  * Replace %m by system error string.  If there are any %'s in
-                  * the string, we'd better double them so that vsnprintf won't
-                  * misinterpret.
-                  */
-                 const char *cp2;
-
-                 cp2 = strerror(edata->saved_errno);
-                 for (; *cp2; cp2++)
-                 {
-                     if (*cp2 == '%')
-                         appendStringInfoCharMacro(&buf, '%');
-                     appendStringInfoCharMacro(&buf, *cp2);
-                 }
-             }
-             else
-             {
-                 /* copy % and next char --- this avoids trouble with %%m */
-                 appendStringInfoCharMacro(&buf, '%');
-                 appendStringInfoCharMacro(&buf, *cp);
-             }
-         }
-         else
-             appendStringInfoCharMacro(&buf, *cp);
-     }
-
-     return buf.data;
- }
-
-
- /*
   * error_severity --- get string representing elevel
   *
   * The string is not localized here, but we mark the strings for translation
--- 3320,3325 ----
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
index 36e3383..267d86a 100644
*** a/src/bin/pg_dump/pg_backup_archiver.c
--- b/src/bin/pg_dump/pg_backup_archiver.c
*************** archputs(const char *s, Archive *AH)
*** 1471,1476 ****
--- 1471,1477 ----
  int
  archprintf(Archive *AH, const char *fmt,...)
  {
+     int            save_errno = errno;
      char       *p;
      size_t        len = 128;        /* initial assumption about buffer size */
      size_t        cnt;
*************** archprintf(Archive *AH, const char *fmt,
*** 1483,1488 ****
--- 1484,1490 ----
          p = (char *) pg_malloc(len);

          /* Try to format the data. */
+         errno = save_errno;
          va_start(args, fmt);
          cnt = pvsnprintf(p, len, fmt, args);
          va_end(args);
*************** RestoreOutput(ArchiveHandle *AH, OutputC
*** 1604,1609 ****
--- 1606,1612 ----
  int
  ahprintf(ArchiveHandle *AH, const char *fmt,...)
  {
+     int            save_errno = errno;
      char       *p;
      size_t        len = 128;        /* initial assumption about buffer size */
      size_t        cnt;
*************** ahprintf(ArchiveHandle *AH, const char *
*** 1616,1621 ****
--- 1619,1625 ----
          p = (char *) pg_malloc(len);

          /* Try to format the data. */
+         errno = save_errno;
          va_start(args, fmt);
          cnt = pvsnprintf(p, len, fmt, args);
          va_end(args);
diff --git a/src/bin/pg_dump/pg_backup_tar.c b/src/bin/pg_dump/pg_backup_tar.c
index 007be12..407a56d 100644
*** a/src/bin/pg_dump/pg_backup_tar.c
--- b/src/bin/pg_dump/pg_backup_tar.c
*************** _EndBlobs(ArchiveHandle *AH, TocEntry *t
*** 1026,1031 ****
--- 1026,1032 ----
  static int
  tarPrintf(ArchiveHandle *AH, TAR_MEMBER *th, const char *fmt,...)
  {
+     int            save_errno = errno;
      char       *p;
      size_t        len = 128;        /* initial assumption about buffer size */
      size_t        cnt;
*************** tarPrintf(ArchiveHandle *AH, TAR_MEMBER
*** 1038,1043 ****
--- 1039,1045 ----
          p = (char *) pg_malloc(len);

          /* Try to format the data. */
+         errno = save_errno;
          va_start(args, fmt);
          cnt = pvsnprintf(p, len, fmt, args);
          va_end(args);
diff --git a/src/common/psprintf.c b/src/common/psprintf.c
index 04465a1..2cf100f 100644
*** a/src/common/psprintf.c
--- b/src/common/psprintf.c
***************
*** 45,50 ****
--- 45,51 ----
  char *
  psprintf(const char *fmt,...)
  {
+     int            save_errno = errno;
      size_t        len = 128;        /* initial assumption about buffer size */

      for (;;)
*************** psprintf(const char *fmt,...)
*** 60,65 ****
--- 61,67 ----
          result = (char *) palloc(len);

          /* Try to format the data. */
+         errno = save_errno;
          va_start(args, fmt);
          newlen = pvsnprintf(result, len, fmt, args);
          va_end(args);
*************** psprintf(const char *fmt,...)
*** 89,94 ****
--- 91,99 ----
   * Other error cases do not return, but exit via elog(ERROR) or exit().
   * Hence, this shouldn't be used inside libpq.
   *
+  * Caution: callers must be sure to preserve their entry-time errno
+  * when looping, in case the fmt contains "%m".
+  *
   * Note that the semantics of the return value are not exactly C99's.
   * First, we don't promise that the estimated buffer size is exactly right;
   * callers must be prepared to loop multiple times to get the right size.
diff --git a/src/include/c.h b/src/include/c.h
index 901d791..b255da6 100644
*** a/src/include/c.h
--- b/src/include/c.h
*************** typedef union PGAlignedXLogBlock
*** 1114,1127 ****
   * standard C library.
   */

- #if !HAVE_DECL_SNPRINTF
- extern int    snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3, 4);
- #endif
-
- #if !HAVE_DECL_VSNPRINTF
- extern int    vsnprintf(char *str, size_t count, const char *fmt, va_list args);
- #endif
-
  #if defined(HAVE_FDATASYNC) && !HAVE_DECL_FDATASYNC
  extern int    fdatasync(int fildes);
  #endif
--- 1114,1119 ----
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 705c52b..254fa80 100644
*** a/src/include/pg_config.h.in
--- b/src/include/pg_config.h.in
***************
*** 166,175 ****
     don't. */
  #undef HAVE_DECL_RTLD_NOW

- /* Define to 1 if you have the declaration of `snprintf', and to 0 if you
-    don't. */
- #undef HAVE_DECL_SNPRINTF
-
  /* Define to 1 if you have the declaration of `strlcat', and to 0 if you
     don't. */
  #undef HAVE_DECL_STRLCAT
--- 166,171 ----
***************
*** 194,203 ****
     don't. */
  #undef HAVE_DECL_SYS_SIGLIST

- /* Define to 1 if you have the declaration of `vsnprintf', and to 0 if you
-    don't. */
- #undef HAVE_DECL_VSNPRINTF
-
  /* Define to 1 if you have the `dlopen' function. */
  #undef HAVE_DLOPEN

--- 190,195 ----
***************
*** 507,515 ****
  /* Define to 1 if you have the `shm_open' function. */
  #undef HAVE_SHM_OPEN

- /* Define to 1 if you have the `snprintf' function. */
- #undef HAVE_SNPRINTF
-
  /* Define to 1 if you have spinlocks. */
  #undef HAVE_SPINLOCKS

--- 499,504 ----
***************
*** 712,720 ****
  /* Define to 1 if you have the <uuid/uuid.h> header file. */
  #undef HAVE_UUID_UUID_H

- /* Define to 1 if you have the `vsnprintf' function. */
- #undef HAVE_VSNPRINTF
-
  /* Define to 1 if you have the <wchar.h> header file. */
  #undef HAVE_WCHAR_H

--- 701,706 ----
***************
*** 923,931 ****
  /* Define to 1 to build with PAM support. (--with-pam) */
  #undef USE_PAM

- /* Use replacement snprintf() functions. */
- #undef USE_REPL_SNPRINTF
-
  /* Define to 1 to use software CRC-32C implementation (slicing-by-8). */
  #undef USE_SLICING_BY_8_CRC32C

--- 909,914 ----
diff --git a/src/include/pg_config.h.win32 b/src/include/pg_config.h.win32
index eafe377..92d648e 100644
*** a/src/include/pg_config.h.win32
--- b/src/include/pg_config.h.win32
***************
*** 135,144 ****
     don't. */
  #define HAVE_DECL_RTLD_NOW 0

- /* Define to 1 if you have the declaration of `snprintf', and to 0 if you
-    don't. */
- #define HAVE_DECL_SNPRINTF 1
-
  /* Define to 1 if you have the declaration of `strnlen', and to 0 if you
     don't. */
  #define HAVE_DECL_STRNLEN 1
--- 135,140 ----
***************
*** 151,160 ****
     don't. */
  #define HAVE_DECL_STRTOULL 1

- /* Define to 1 if you have the declaration of `vsnprintf', and to 0 if you
-    don't. */
- #define HAVE_DECL_VSNPRINTF 1
-
  /* Define to 1 if you have the `dlopen' function. */
  /* #undef HAVE_DLOPEN */

--- 147,152 ----
***************
*** 373,381 ****
  /* Define to 1 if you have the `setsid' function. */
  /* #undef HAVE_SETSID */

- /* Define to 1 if you have the `snprintf' function. */
- /* #undef HAVE_SNPRINTF */
-
  /* Define to 1 if you have spinlocks. */
  #define HAVE_SPINLOCKS 1

--- 365,370 ----
***************
*** 553,561 ****
  /* Define to 1 if you have the <utime.h> header file. */
  #define HAVE_UTIME_H 1

- /* Define to 1 if you have the `vsnprintf' function. */
- #define HAVE_VSNPRINTF 1
-
  /* Define to 1 if you have the <wchar.h> header file. */
  #define HAVE_WCHAR_H 1

--- 542,547 ----
***************
*** 712,720 ****
  /* Define to 1 to build with PAM support. (--with-pam) */
  /* #undef USE_PAM */

- /* Use replacement snprintf() functions. */
- #define USE_REPL_SNPRINTF 1
-
  /* Define to 1 to use software CRC-32C implementation (slicing-by-8). */
  #if (_MSC_VER < 1500)
  #define USE_SLICING_BY_8_CRC32C 1
--- 698,703 ----
diff --git a/src/include/port.h b/src/include/port.h
index bffc773..0f0cd28 100644
*** a/src/include/port.h
--- b/src/include/port.h
*************** extern unsigned char pg_tolower(unsigned
*** 134,140 ****
  extern unsigned char pg_ascii_toupper(unsigned char ch);
  extern unsigned char pg_ascii_tolower(unsigned char ch);

! #ifdef USE_REPL_SNPRINTF

  /*
   * Versions of libintl >= 0.13 try to replace printf() and friends with
--- 134,145 ----
  extern unsigned char pg_ascii_toupper(unsigned char ch);
  extern unsigned char pg_ascii_tolower(unsigned char ch);

! /*
!  * Beginning in v12, we always replace snprintf() and friends with our own
!  * implementation.  This symbol is no longer consulted by the core code,
!  * but keep it defined anyway in case any extensions are looking at it.
!  */
! #define USE_REPL_SNPRINTF 1

  /*
   * Versions of libintl >= 0.13 try to replace printf() and friends with
*************** extern int    pg_printf(const char *fmt,...
*** 187,193 ****
  #define fprintf            pg_fprintf
  #define printf            pg_printf
  #endif
- #endif                            /* USE_REPL_SNPRINTF */

  /* Replace strerror() with our own, somewhat more robust wrapper */
  extern char *pg_strerror(int errnum);
--- 192,197 ----
diff --git a/src/interfaces/ecpg/compatlib/Makefile b/src/interfaces/ecpg/compatlib/Makefile
index b7bd162..e07a7fa 100644
*** a/src/interfaces/ecpg/compatlib/Makefile
--- b/src/interfaces/ecpg/compatlib/Makefile
*************** SHLIB_EXPORTS = exports.txt
*** 31,37 ****
  # Need to recompile any libpgport object files
  LIBS := $(filter-out -lpgport, $(LIBS))

! OBJS= informix.o strerror.o $(filter snprintf.o strnlen.o, $(LIBOBJS)) $(WIN32RES)

  PKG_CONFIG_REQUIRES_PRIVATE = libecpg libpgtypes

--- 31,38 ----
  # Need to recompile any libpgport object files
  LIBS := $(filter-out -lpgport, $(LIBS))

! OBJS= informix.o snprintf.o strerror.o \
!     $(filter strnlen.o, $(LIBOBJS)) $(WIN32RES)

  PKG_CONFIG_REQUIRES_PRIVATE = libecpg libpgtypes

diff --git a/src/interfaces/ecpg/ecpglib/Makefile b/src/interfaces/ecpg/ecpglib/Makefile
index 005d25a..b381623 100644
*** a/src/interfaces/ecpg/ecpglib/Makefile
--- b/src/interfaces/ecpg/ecpglib/Makefile
*************** override CFLAGS += $(PTHREAD_CFLAGS)
*** 26,33 ****
  LIBS := $(filter-out -lpgport, $(LIBS))

  OBJS= execute.o typename.o descriptor.o sqlda.o data.o error.o prepare.o memory.o \
!     connect.o misc.o path.o pgstrcasecmp.o strerror.o \
!     $(filter snprintf.o strlcpy.o strnlen.o win32setlocale.o isinf.o, $(LIBOBJS)) \
      $(WIN32RES)

  # thread.c is needed only for non-WIN32 implementation of path.c
--- 26,33 ----
  LIBS := $(filter-out -lpgport, $(LIBS))

  OBJS= execute.o typename.o descriptor.o sqlda.o data.o error.o prepare.o memory.o \
!     connect.o misc.o path.o pgstrcasecmp.o snprintf.o strerror.o \
!     $(filter strlcpy.o strnlen.o win32setlocale.o isinf.o, $(LIBOBJS)) \
      $(WIN32RES)

  # thread.c is needed only for non-WIN32 implementation of path.c
diff --git a/src/interfaces/ecpg/pgtypeslib/Makefile b/src/interfaces/ecpg/pgtypeslib/Makefile
index 18b2402..15d7f33 100644
*** a/src/interfaces/ecpg/pgtypeslib/Makefile
--- b/src/interfaces/ecpg/pgtypeslib/Makefile
*************** SHLIB_LINK += $(filter -lm, $(LIBS))
*** 30,37 ****
  SHLIB_EXPORTS = exports.txt

  OBJS= numeric.o datetime.o common.o dt_common.o timestamp.o interval.o \
!     pgstrcasecmp.o strerror.o \
!     $(filter rint.o snprintf.o strnlen.o, $(LIBOBJS)) \
      string.o \
      $(WIN32RES)

--- 30,37 ----
  SHLIB_EXPORTS = exports.txt

  OBJS= numeric.o datetime.o common.o dt_common.o timestamp.o interval.o \
!     pgstrcasecmp.o snprintf.o strerror.o \
!     $(filter rint.o strnlen.o, $(LIBOBJS)) \
      string.o \
      $(WIN32RES)

diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile
index 8324f4f..a106088 100644
*** a/src/interfaces/libpq/Makefile
--- b/src/interfaces/libpq/Makefile
*************** OBJS=    fe-auth.o fe-auth-scram.o fe-conne
*** 36,44 ****
      libpq-events.o
  # libpgport C files we always use
  OBJS += chklocale.o inet_net_ntop.o noblock.o pgstrcasecmp.o pqsignal.o \
!     strerror.o thread.o
  # libpgport C files that are needed if identified by configure
! OBJS += $(filter crypt.o getaddrinfo.o getpeereid.o inet_aton.o open.o system.o snprintf.o strlcpy.o strnlen.o
win32error.owin32setlocale.o, $(LIBOBJS)) 

  ifeq ($(enable_strong_random), yes)
  OBJS += pg_strong_random.o
--- 36,44 ----
      libpq-events.o
  # libpgport C files we always use
  OBJS += chklocale.o inet_net_ntop.o noblock.o pgstrcasecmp.o pqsignal.o \
!     snprintf.o strerror.o thread.o
  # libpgport C files that are needed if identified by configure
! OBJS += $(filter crypt.o getaddrinfo.o getpeereid.o inet_aton.o open.o system.o strlcpy.o strnlen.o win32error.o
win32setlocale.o,$(LIBOBJS)) 

  ifeq ($(enable_strong_random), yes)
  OBJS += pg_strong_random.o
diff --git a/src/interfaces/libpq/pqexpbuffer.c b/src/interfaces/libpq/pqexpbuffer.c
index 0814ec6..43c36c3 100644
*** a/src/interfaces/libpq/pqexpbuffer.c
--- b/src/interfaces/libpq/pqexpbuffer.c
*************** enlargePQExpBuffer(PQExpBuffer str, size
*** 233,238 ****
--- 233,239 ----
  void
  printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
  {
+     int            save_errno = errno;
      va_list        args;
      bool        done;

*************** printfPQExpBuffer(PQExpBuffer str, const
*** 244,249 ****
--- 245,251 ----
      /* Loop in case we have to retry after enlarging the buffer. */
      do
      {
+         errno = save_errno;
          va_start(args, fmt);
          done = appendPQExpBufferVA(str, fmt, args);
          va_end(args);
*************** printfPQExpBuffer(PQExpBuffer str, const
*** 261,266 ****
--- 263,269 ----
  void
  appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
  {
+     int            save_errno = errno;
      va_list        args;
      bool        done;

*************** appendPQExpBuffer(PQExpBuffer str, const
*** 270,275 ****
--- 273,279 ----
      /* Loop in case we have to retry after enlarging the buffer. */
      do
      {
+         errno = save_errno;
          va_start(args, fmt);
          done = appendPQExpBufferVA(str, fmt, args);
          va_end(args);
*************** appendPQExpBuffer(PQExpBuffer str, const
*** 281,286 ****
--- 285,293 ----
   * Shared guts of printfPQExpBuffer/appendPQExpBuffer.
   * Attempt to format data and append it to str.  Returns true if done
   * (either successful or hard failure), false if need to retry.
+  *
+  * Caution: callers must be sure to preserve their entry-time errno
+  * when looping, in case the fmt contains "%m".
   */
  static bool
  appendPQExpBufferVA(PQExpBuffer str, const char *fmt, va_list args)
diff --git a/src/pl/plperl/plperl.h b/src/pl/plperl/plperl.h
index e6241f0..f8888a4 100644
*** a/src/pl/plperl/plperl.h
--- b/src/pl/plperl/plperl.h
***************
*** 29,39 ****
   * Sometimes perl carefully scribbles on our *printf macros.
   * So we undefine them here and redefine them after it's done its dirty deed.
   */
-
- #ifdef USE_REPL_SNPRINTF
  #undef snprintf
  #undef vsnprintf
- #endif

  /*
   * ActivePerl 5.18 and later are MinGW-built, and their headers use GCC's
--- 29,36 ----
***************
*** 99,105 ****
  #endif

  /* put back our snprintf and vsnprintf */
- #ifdef USE_REPL_SNPRINTF
  #ifdef snprintf
  #undef snprintf
  #endif
--- 96,101 ----
***************
*** 113,119 ****
  #define vsnprintf        pg_vsnprintf
  #define snprintf        pg_snprintf
  #endif                            /* __GNUC__ */
- #endif                            /* USE_REPL_SNPRINTF */

  /* perl version and platform portability */
  #define NEED_eval_pv
--- 109,114 ----
diff --git a/src/pl/plpython/plpy_elog.c b/src/pl/plpython/plpy_elog.c
index e244104..3814a6c 100644
*** a/src/pl/plpython/plpy_elog.c
--- b/src/pl/plpython/plpy_elog.c
*************** static bool set_string_attr(PyObject *ob
*** 46,51 ****
--- 46,52 ----
  void
  PLy_elog_impl(int elevel, const char *fmt,...)
  {
+     int            save_errno = errno;
      char       *xmsg;
      char       *tbmsg;
      int            tb_depth;
*************** PLy_elog_impl(int elevel, const char *fm
*** 96,101 ****
--- 97,103 ----
              va_list        ap;
              int            needed;

+             errno = save_errno;
              va_start(ap, fmt);
              needed = appendStringInfoVA(&emsg, dgettext(TEXTDOMAIN, fmt), ap);
              va_end(ap);
diff --git a/src/pl/plpython/plpython.h b/src/pl/plpython/plpython.h
index 6cc323a..aefbfc2 100644
*** a/src/pl/plpython/plpython.h
--- b/src/pl/plpython/plpython.h
***************
*** 33,43 ****
   * Sometimes python carefully scribbles on our *printf macros.
   * So we undefine them here and redefine them after it's done its dirty deed.
   */
-
- #ifdef USE_REPL_SNPRINTF
  #undef snprintf
  #undef vsnprintf
- #endif

  #if defined(_MSC_VER) && defined(_DEBUG)
  /* Python uses #pragma to bring in a non-default libpython on VC++ if
--- 33,40 ----
*************** typedef int Py_ssize_t;
*** 124,130 ****
  #include <eval.h>

  /* put back our snprintf and vsnprintf */
- #ifdef USE_REPL_SNPRINTF
  #ifdef snprintf
  #undef snprintf
  #endif
--- 121,126 ----
*************** typedef int Py_ssize_t;
*** 138,144 ****
  #define vsnprintf                pg_vsnprintf
  #define snprintf                pg_snprintf
  #endif                            /* __GNUC__ */
- #endif                            /* USE_REPL_SNPRINTF */

  /*
   * Used throughout, and also by the Python 2/3 porting layer, so it's easier to
--- 134,139 ----
diff --git a/src/port/Makefile b/src/port/Makefile
index b3a10ba..a2ee8e2 100644
*** a/src/port/Makefile
--- b/src/port/Makefile
*************** LIBS += $(PTHREAD_LIBS)
*** 33,39 ****
  OBJS = $(LIBOBJS) $(PG_CRC32C_OBJS) chklocale.o erand48.o inet_net_ntop.o \
      noblock.o path.o pgcheckdir.o pgmkdirp.o pgsleep.o \
      pgstrcasecmp.o pqsignal.o \
!     qsort.o qsort_arg.o quotes.o sprompt.o strerror.o tar.o thread.o

  ifeq ($(enable_strong_random), yes)
  OBJS += pg_strong_random.o
--- 33,40 ----
  OBJS = $(LIBOBJS) $(PG_CRC32C_OBJS) chklocale.o erand48.o inet_net_ntop.o \
      noblock.o path.o pgcheckdir.o pgmkdirp.o pgsleep.o \
      pgstrcasecmp.o pqsignal.o \
!     qsort.o qsort_arg.o quotes.o snprintf.o sprompt.o strerror.o \
!     tar.o thread.o

  ifeq ($(enable_strong_random), yes)
  OBJS += pg_strong_random.o
diff --git a/src/port/README b/src/port/README
index 4ae96da..c446b46 100644
*** a/src/port/README
--- b/src/port/README
*************** and adding infrastructure to recompile t
*** 18,24 ****

          OBJS= execute.o typename.o descriptor.o data.o error.o prepare.o memory.o \
                  connect.o misc.o path.o exec.o \
!                 $(filter snprintf.o, $(LIBOBJS))

  The problem is that there is no testing of which object files need to be
  added, but missing functions usually show up when linking user
--- 18,24 ----

          OBJS= execute.o typename.o descriptor.o data.o error.o prepare.o memory.o \
                  connect.o misc.o path.o exec.o \
!                 $(filter strlcat.o, $(LIBOBJS))

  The problem is that there is no testing of which object files need to be
  added, but missing functions usually show up when linking user
diff --git a/src/port/snprintf.c b/src/port/snprintf.c
index 851e2ae..63cec5d 100644
*** a/src/port/snprintf.c
--- b/src/port/snprintf.c
***************
*** 64,69 ****
--- 64,77 ----
   *
   * 5. Space and '#' flags are not implemented.
   *
+  * In addition, we support some extensions over C99:
+  *
+  * 1. Argument order control through "%n$" and "*n$", as required by POSIX.
+  *
+  * 2. "%m" expands to the value of strerror(errno), where errno is the
+  * value that variable had at the start of the call.  This is a glibc
+  * extension, but a very useful one.
+  *
   *
   * Historically the result values of sprintf/snprintf varied across platforms.
   * This implementation now follows the C99 standard:
*************** static void flushbuffer(PrintfTarget *ta
*** 155,160 ****
--- 163,175 ----
  static void dopr(PrintfTarget *target, const char *format, va_list args);


+ /*
+  * Externally visible entry points.
+  *
+  * All of these are just wrappers around dopr().  Note it's essential that
+  * they not change the value of "errno" before reaching dopr().
+  */
+
  int
  pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args)
  {
*************** static void trailing_pad(int *padlen, Pr
*** 315,325 ****


  /*
!  * dopr(): poor man's version of doprintf
   */
  static void
  dopr(PrintfTarget *target, const char *format, va_list args)
  {
      const char *format_start = format;
      int            ch;
      bool        have_dollar;
--- 330,341 ----


  /*
!  * dopr(): the guts of *printf for all cases.
   */
  static void
  dopr(PrintfTarget *target, const char *format, va_list args)
  {
+     int            save_errno = errno;
      const char *format_start = format;
      int            ch;
      bool        have_dollar;
*************** nextch1:
*** 497,502 ****
--- 513,519 ----
                  else
                      have_non_dollar = true;
                  break;
+             case 'm':
              case '%':
                  break;
          }
*************** nextch2:
*** 802,807 ****
--- 819,831 ----
                           precision, pointflag,
                           target);
                  break;
+             case 'm':
+                 {
+                     const char *errm = strerror(save_errno);
+
+                     dostr(errm, strlen(errm), target);
+                 }
+                 break;
              case '%':
                  dopr_outch('%', target);
                  break;

pgsql-hackers by date:

Previous
From: Michael Banck
Date:
Subject: Re: Postgres 11 release notes
Next
From: Peter Geoghegan
Date:
Subject: Re: Making all nbtree entries unique by having heap TIDs participatein comparisons