PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
psprintf.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * psprintf.c
4 * sprintf into an allocated-on-demand buffer
5 *
6 *
7 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
9 *
10 *
11 * IDENTIFICATION
12 * src/common/psprintf.c
13 *
14 *-------------------------------------------------------------------------
15 */
16
17#ifndef FRONTEND
18
19#include "postgres.h"
20
21#include "utils/memutils.h"
22
23#else
24
25#include "postgres_fe.h"
26
27#endif
28
29
30/*
31 * psprintf
32 *
33 * Format text data under the control of fmt (an sprintf-style format string)
34 * and return it in an allocated-on-demand buffer. The buffer is allocated
35 * with palloc in the backend, or malloc in frontend builds. Caller is
36 * responsible to free the buffer when no longer needed, if appropriate.
37 *
38 * Errors are not returned to the caller, but are reported via elog(ERROR)
39 * in the backend, or printf-to-stderr-and-exit() in frontend builds.
40 * One should therefore think twice about using this in libpq.
41 */
42char *
43psprintf(const char *fmt,...)
44{
45 int save_errno = errno;
46 size_t len = 128; /* initial assumption about buffer size */
47
48 for (;;)
49 {
50 char *result;
51 va_list args;
52 size_t newlen;
53
54 /*
55 * Allocate result buffer. Note that in frontend this maps to malloc
56 * with exit-on-error.
57 */
58 result = (char *) palloc(len);
59
60 /* Try to format the data. */
61 errno = save_errno;
63 newlen = pvsnprintf(result, len, fmt, args);
64 va_end(args);
65
66 if (newlen < len)
67 return result; /* success */
68
69 /* Release buffer and loop around to try again with larger len. */
70 pfree(result);
71 len = newlen;
72 }
73}
74
75/*
76 * pvsnprintf
77 *
78 * Attempt to format text data under the control of fmt (an sprintf-style
79 * format string) and insert it into buf (which has length len).
80 *
81 * If successful, return the number of bytes emitted, not counting the
82 * trailing zero byte. This will always be strictly less than len.
83 *
84 * If there's not enough space in buf, return an estimate of the buffer size
85 * needed to succeed (this *must* be more than the given len, else callers
86 * might loop infinitely).
87 *
88 * Other error cases do not return, but exit via elog(ERROR) or exit().
89 * Hence, this shouldn't be used inside libpq.
90 *
91 * Caution: callers must be sure to preserve their entry-time errno
92 * when looping, in case the fmt contains "%m".
93 *
94 * Note that the semantics of the return value are not exactly C99's.
95 * First, we don't promise that the estimated buffer size is exactly right;
96 * callers must be prepared to loop multiple times to get the right size.
97 * (Given a C99-compliant vsnprintf, that won't happen, but it is rumored
98 * that some implementations don't always return the same value ...)
99 * Second, we return the recommended buffer size, not one less than that;
100 * this lets overflow concerns be handled here rather than in the callers.
101 */
102size_t
103pvsnprintf(char *buf, size_t len, const char *fmt, va_list args)
104{
105 int nprinted;
106
107 nprinted = vsnprintf(buf, len, fmt, args);
108
109 /* We assume failure means the fmt is bogus, hence hard failure is OK */
110 if (unlikely(nprinted < 0))
111 {
112#ifndef FRONTEND
113 elog(ERROR, "vsnprintf failed: %m with format string \"%s\"", fmt);
114#else
115 fprintf(stderr, "vsnprintf failed: %m with format string \"%s\"\n",
116 fmt);
118#endif
119 }
120
121 if ((size_t) nprinted < len)
122 {
123 /* Success. Note nprinted does not include trailing null. */
124 return (size_t) nprinted;
125 }
126
127 /*
128 * We assume a C99-compliant vsnprintf, so believe its estimate of the
129 * required space, and add one for the trailing null. (If it's wrong, the
130 * logic will still work, but we may loop multiple times.)
131 *
132 * Choke if the required space would exceed MaxAllocSize. Note we use
133 * this palloc-oriented overflow limit even when in frontend.
134 */
135 if (unlikely((size_t) nprinted > MaxAllocSize - 1))
136 {
137#ifndef FRONTEND
139 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
140 errmsg("out of memory")));
141#else
142 fprintf(stderr, _("out of memory\n"));
144#endif
145 }
146
147 return nprinted + 1;
148}
#define unlikely(x)
Definition: c.h:330
#define fprintf(file, fmt, msg)
Definition: cubescan.l:21
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define _(x)
Definition: elog.c:90
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
#define MaxAllocSize
Definition: fe_memutils.h:22
static void const char * fmt
va_end(args)
exit(1)
va_start(args, fmt)
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc(Size size)
Definition: mcxt.c:1317
const void size_t len
static char * buf
Definition: pg_test_fsync.c:72
#define vsnprintf
Definition: port.h:237
size_t pvsnprintf(char *buf, size_t len, const char *fmt, va_list args)
Definition: psprintf.c:103
char * psprintf(const char *fmt,...)
Definition: psprintf.c:43
#define EXIT_FAILURE
Definition: settings.h:178