aboutsummaryrefslogtreecommitdiff
path: root/src/port/snprintf.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2018-09-26 13:31:56 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2018-09-26 13:31:56 -0400
commitd6c55de1f99a9028540516316b95321a7b12a540 (patch)
tree7c95ff050f56bcf20648e3d7a8a7fbb2ddbc7293 /src/port/snprintf.c
parent96bf88d52711ad3a0a4cc2d1d9cb0e2acab85e63 (diff)
downloadpostgresql-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.c28
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;