1 /*-------------------------------------------------------------------------
4 * Common routines to replace percent placeholders in strings
6 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/common/percentrepl.c
13 *-------------------------------------------------------------------------
19 #include "postgres_fe.h"
20 #include "common/logging.h"
23 #include "common/percentrepl.h"
24 #include "lib/stringinfo.h"
27 * replace_percent_placeholders
29 * Replace percent-letter placeholders in input string with the supplied
30 * values. For example, to replace %f with foo and %b with bar, call
32 * replace_percent_placeholders(instr, "param_name", "bf", bar, foo);
34 * The return value is palloc'd.
36 * "%%" is replaced by a single "%".
38 * This throws an error for an unsupported placeholder or a "%" at the end of
41 * A value may be NULL. If the corresponding placeholder is found in the
42 * input string, it will be treated as if an unsupported placeholder was used.
43 * This allows callers to share a "letters" specification but vary the
44 * actually supported placeholders at run time.
46 * This functions is meant for cases where all the values are readily
47 * available or cheap to compute and most invocations will use most values
48 * (for example for archive_command). Also, it requires that all values are
49 * strings. It won't be a good match for things like log prefixes or prompts
50 * that use a mix of data types and any invocation will only use a few of the
53 * param_name is the name of the underlying GUC parameter, for error
54 * reporting. At the moment, this function is only used for GUC parameters.
55 * If other kinds of uses were added, the error reporting would need to be
59 replace_percent_placeholders(const char *instr
, const char *param_name
, const char *letters
,...)
61 StringInfoData result
;
63 initStringInfo(&result
);
65 for (const char *sp
= instr
; *sp
; sp
++)
71 /* Convert %% to a single % */
73 appendStringInfoChar(&result
, *sp
);
75 else if (sp
[1] == '\0')
77 /* Incomplete escape sequence, expected a character afterward */
79 pg_log_error("invalid value for parameter \"%s\": \"%s\"", param_name
, instr
);
80 pg_log_error_detail("String ends unexpectedly after escape character \"%%\".");
84 errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
85 errmsg("invalid value for parameter \"%s\": \"%s\"", param_name
, instr
),
86 errdetail("String ends unexpectedly after escape character \"%%\"."));
91 /* Look up placeholder character */
97 va_start(ap
, letters
);
98 for (const char *lp
= letters
; *lp
; lp
++)
100 char *val
= va_arg(ap
, char *);
106 appendStringInfoString(&result
, val
);
109 /* If val is NULL, we will report an error. */
116 /* Unknown placeholder */
118 pg_log_error("invalid value for parameter \"%s\": \"%s\"", param_name
, instr
);
119 pg_log_error_detail("String contains unexpected placeholder \"%%%c\".", *sp
);
123 errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
124 errmsg("invalid value for parameter \"%s\": \"%s\"", param_name
, instr
),
125 errdetail("String contains unexpected placeholder \"%%%c\".", *sp
));
132 appendStringInfoChar(&result
, *sp
);