diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2018-09-26 13:31:56 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2018-09-26 13:31:56 -0400 |
commit | d6c55de1f99a9028540516316b95321a7b12a540 (patch) | |
tree | 7c95ff050f56bcf20648e3d7a8a7fbb2ddbc7293 /src/port/snprintf.c | |
parent | 96bf88d52711ad3a0a4cc2d1d9cb0e2acab85e63 (diff) | |
download | postgresql-d6c55de1f99a9028540516316b95321a7b12a540.tar.gz postgresql-d6c55de1f99a9028540516316b95321a7b12a540.zip |
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
Diffstat (limited to 'src/port/snprintf.c')
-rw-r--r-- | src/port/snprintf.c | 28 |
1 files changed, 27 insertions, 1 deletions
diff --git a/src/port/snprintf.c b/src/port/snprintf.c index 851e2ae330a..2c77eec1c6b 100644 --- a/src/port/snprintf.c +++ b/src/port/snprintf.c @@ -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; |