1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-11 10:01:57 +03:00

Implement %m in src/port/snprintf.c, and teach elog.c to rely on that.

I started out with the idea that we needed to detect use of %m format specs
in contexts other than elog/ereport calls, because we couldn't rely on that
working in *printf calls.  But a better answer is to fix things so that it
does work.  Now that we're using snprintf.c all the time, we can implement
%m in that and we've fixed the problem.

This requires also adjusting our various printf-wrapping functions so that
they ensure "errno" is preserved when they call snprintf.c.

Remove elog.c's handmade implementation of %m, and let it rely on
snprintf to support the feature.  That should provide some performance
gain, though I've not attempted to measure it.

There are a lot of places where we could now simplify 'printf("%s",
strerror(errno))' into 'printf("%m")', but I'm not in any big hurry
to make that happen.

Patch by me, reviewed by Michael Paquier

Discussion: https://postgr.es/m/2975.1526862605@sss.pgh.pa.us
This commit is contained in:
Tom Lane
2018-09-26 13:31:56 -04:00
parent 96bf88d527
commit d6c55de1f9
8 changed files with 57 additions and 67 deletions

View File

@ -64,6 +64,14 @@
*
* 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:
@ -155,6 +163,13 @@ static void flushbuffer(PrintfTarget *target);
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)
{
@ -315,11 +330,12 @@ static void trailing_pad(int *padlen, PrintfTarget *target);
/*
* dopr(): poor man's version of doprintf
* 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;
@ -497,6 +513,7 @@ nextch1:
else
have_non_dollar = true;
break;
case 'm':
case '%':
break;
}
@ -802,6 +819,15 @@ nextch2:
precision, pointflag,
target);
break;
case 'm':
{
char errbuf[PG_STRERROR_R_BUFLEN];
const char *errm = strerror_r(save_errno,
errbuf, sizeof(errbuf));
dostr(errm, strlen(errm), target);
}
break;
case '%':
dopr_outch('%', target);
break;