PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
prompt.c File Reference
#include "postgres_fe.h"
#include "common.h"
#include "common/string.h"
#include "input.h"
#include "libpq/pqcomm.h"
#include "prompt.h"
#include "settings.h"
Include dependency graph for prompt.c:

Go to the source code of this file.

Macros

#define MAX_PROMPT_SIZE   256
 

Functions

char * get_prompt (promptStatus_t status, ConditionalStack cstack)
 

Macro Definition Documentation

◆ MAX_PROMPT_SIZE

#define MAX_PROMPT_SIZE   256

Function Documentation

◆ get_prompt()

char * get_prompt ( promptStatus_t  status,
ConditionalStack  cstack 
)

Definition at line 68 of file prompt.c.

69{
70#define MAX_PROMPT_SIZE 256
71 static char destination[MAX_PROMPT_SIZE + 1];
72 char buf[MAX_PROMPT_SIZE + 1];
73 bool esc = false;
74 const char *p;
75 const char *prompt_string = "? ";
76 static size_t last_prompt1_width = 0;
77
78 switch (status)
79 {
80 case PROMPT_READY:
81 prompt_string = pset.prompt1;
82 break;
83
84 case PROMPT_CONTINUE:
88 case PROMPT_COMMENT:
89 case PROMPT_PAREN:
90 prompt_string = pset.prompt2;
91 break;
92
93 case PROMPT_COPY:
94 prompt_string = pset.prompt3;
95 break;
96 }
97
98 destination[0] = '\0';
99
100 for (p = prompt_string;
101 *p && strlen(destination) < sizeof(destination) - 1;
102 p++)
103 {
104 memset(buf, 0, sizeof(buf));
105 if (esc)
106 {
107 switch (*p)
108 {
109 /* Current database */
110 case '/':
111 if (pset.db)
112 strlcpy(buf, PQdb(pset.db), sizeof(buf));
113 break;
114 case '~':
115 if (pset.db)
116 {
117 const char *var;
118
119 if (strcmp(PQdb(pset.db), PQuser(pset.db)) == 0 ||
120 ((var = getenv("PGDATABASE")) && strcmp(var, PQdb(pset.db)) == 0))
121 strlcpy(buf, "~", sizeof(buf));
122 else
123 strlcpy(buf, PQdb(pset.db), sizeof(buf));
124 }
125 break;
126
127 /* Whitespace of the same width as the last PROMPT1 */
128 case 'w':
129 if (pset.db)
130 memset(buf, ' ',
131 Min(last_prompt1_width, sizeof(buf) - 1));
132 break;
133
134 /* DB server hostname (long/short) */
135 case 'M':
136 case 'm':
137 if (pset.db)
138 {
139 const char *host = PQhost(pset.db);
140
141 /* INET socket */
142 if (host && host[0] && !is_unixsock_path(host))
143 {
144 strlcpy(buf, host, sizeof(buf));
145 if (*p == 'm')
146 buf[strcspn(buf, ".")] = '\0';
147 }
148 /* UNIX socket */
149 else
150 {
151 if (!host
152 || strcmp(host, DEFAULT_PGSOCKET_DIR) == 0
153 || *p == 'm')
154 strlcpy(buf, "[local]", sizeof(buf));
155 else
156 snprintf(buf, sizeof(buf), "[local:%s]", host);
157 }
158 }
159 break;
160 /* DB server port number */
161 case '>':
162 if (pset.db && PQport(pset.db))
163 strlcpy(buf, PQport(pset.db), sizeof(buf));
164 break;
165 /* DB server user name */
166 case 'n':
167 if (pset.db)
168 strlcpy(buf, session_username(), sizeof(buf));
169 break;
170 /* service name */
171 case 's':
172 if (pset.db && PQservice(pset.db))
173 strlcpy(buf, PQservice(pset.db), sizeof(buf));
174 break;
175 /* backend pid */
176 case 'p':
177 if (pset.db)
178 {
179 int pid = PQbackendPID(pset.db);
180
181 if (pid)
182 snprintf(buf, sizeof(buf), "%d", pid);
183 }
184 break;
185 /* pipeline status */
186 case 'P':
187 {
189
190 if (status == PQ_PIPELINE_ON)
191 strlcpy(buf, "on", sizeof(buf));
192 else if (status == PQ_PIPELINE_ABORTED)
193 strlcpy(buf, "abort", sizeof(buf));
194 else
195 strlcpy(buf, "off", sizeof(buf));
196 break;
197 }
198
199 case '0':
200 case '1':
201 case '2':
202 case '3':
203 case '4':
204 case '5':
205 case '6':
206 case '7':
207 *buf = (char) strtol(p, unconstify(char **, &p), 8);
208 --p;
209 break;
210 case 'R':
211 switch (status)
212 {
213 case PROMPT_READY:
214 if (cstack != NULL && !conditional_active(cstack))
215 buf[0] = '@';
216 else if (!pset.db)
217 buf[0] = '!';
218 else if (!pset.singleline)
219 buf[0] = '=';
220 else
221 buf[0] = '^';
222 break;
223 case PROMPT_CONTINUE:
224 buf[0] = '-';
225 break;
227 buf[0] = '\'';
228 break;
230 buf[0] = '"';
231 break;
233 buf[0] = '$';
234 break;
235 case PROMPT_COMMENT:
236 buf[0] = '*';
237 break;
238 case PROMPT_PAREN:
239 buf[0] = '(';
240 break;
241 default:
242 buf[0] = '\0';
243 break;
244 }
245 break;
246
247 case 'x':
248 if (!pset.db)
249 buf[0] = '?';
250 else
251 switch (PQtransactionStatus(pset.db))
252 {
253 case PQTRANS_IDLE:
254 buf[0] = '\0';
255 break;
256 case PQTRANS_ACTIVE:
257 case PQTRANS_INTRANS:
258 buf[0] = '*';
259 break;
260 case PQTRANS_INERROR:
261 buf[0] = '!';
262 break;
263 default:
264 buf[0] = '?';
265 break;
266 }
267 break;
268
269 case 'l':
271 break;
272
273 case '?':
274 /* not here yet */
275 break;
276
277 case '#':
278 if (is_superuser())
279 buf[0] = '#';
280 else
281 buf[0] = '>';
282 break;
283
284 /* execute command */
285 case '`':
286 {
287 int cmdend = strcspn(p + 1, "`");
288 char *file = pnstrdup(p + 1, cmdend);
289 FILE *fd;
290
291 fflush(NULL);
292 fd = popen(file, "r");
293 if (fd)
294 {
295 if (fgets(buf, sizeof(buf), fd) == NULL)
296 buf[0] = '\0';
297 pclose(fd);
298 }
299
300 /* strip trailing newline and carriage return */
301 (void) pg_strip_crlf(buf);
302
303 free(file);
304 p += cmdend + 1;
305 break;
306 }
307
308 /* interpolate variable */
309 case ':':
310 {
311 int nameend = strcspn(p + 1, ":");
312 char *name = pnstrdup(p + 1, nameend);
313 const char *val;
314
316 if (val)
317 strlcpy(buf, val, sizeof(buf));
318 free(name);
319 p += nameend + 1;
320 break;
321 }
322
323 case '[':
324 case ']':
325#if defined(USE_READLINE) && defined(RL_PROMPT_START_IGNORE)
326
327 /*
328 * readline >=4.0 undocumented feature: non-printing
329 * characters in prompt strings must be marked as such, in
330 * order to properly display the line during editing.
331 */
332 buf[0] = (*p == '[') ? RL_PROMPT_START_IGNORE : RL_PROMPT_END_IGNORE;
333 buf[1] = '\0';
334#endif /* USE_READLINE */
335 break;
336
337 default:
338 buf[0] = *p;
339 buf[1] = '\0';
340 break;
341 }
342 esc = false;
343 }
344 else if (*p == '%')
345 esc = true;
346 else
347 {
348 buf[0] = *p;
349 buf[1] = '\0';
350 esc = false;
351 }
352
353 if (!esc)
354 strlcat(destination, buf, sizeof(destination));
355 }
356
357 /* Compute the visible width of PROMPT1, for PROMPT2's %w */
358 if (prompt_string == pset.prompt1)
359 {
360 char *p = destination;
361 char *end = p + strlen(p);
362 bool visible = true;
363
364 last_prompt1_width = 0;
365 while (*p)
366 {
367#if defined(USE_READLINE) && defined(RL_PROMPT_START_IGNORE)
368 if (*p == RL_PROMPT_START_IGNORE)
369 {
370 visible = false;
371 ++p;
372 }
373 else if (*p == RL_PROMPT_END_IGNORE)
374 {
375 visible = true;
376 ++p;
377 }
378 else
379#endif
380 {
381 int chlen,
382 chwidth;
383
384 chlen = PQmblen(p, pset.encoding);
385 if (p + chlen > end)
386 break; /* Invalid string */
387
388 if (visible)
389 {
390 chwidth = PQdsplen(p, pset.encoding);
391
392 if (*p == '\n')
393 last_prompt1_width = 0;
394 else if (chwidth > 0)
395 last_prompt1_width += chwidth;
396 }
397
398 p += chlen;
399 }
400 }
401 }
402
403 return destination;
404}
const char * session_username(void)
Definition: common.c:2468
#define unconstify(underlying_type, expr)
Definition: c.h:1216
#define Min(x, y)
Definition: c.h:975
#define UINT64_FORMAT
Definition: c.h:521
bool conditional_active(ConditionalStack cstack)
Definition: conditional.c:140
char * PQdb(const PGconn *conn)
Definition: fe-connect.c:7381
char * PQport(const PGconn *conn)
Definition: fe-connect.c:7458
PGTransactionStatusType PQtransactionStatus(const PGconn *conn)
Definition: fe-connect.c:7498
char * PQhost(const PGconn *conn)
Definition: fe-connect.c:7422
char * PQservice(const PGconn *conn)
Definition: fe-connect.c:7389
int PQbackendPID(const PGconn *conn)
Definition: fe-connect.c:7589
char * PQuser(const PGconn *conn)
Definition: fe-connect.c:7397
PGpipelineStatus PQpipelineStatus(const PGconn *conn)
Definition: fe-connect.c:7597
int PQmblen(const char *s, int encoding)
Definition: fe-misc.c:1233
int PQdsplen(const char *s, int encoding)
Definition: fe-misc.c:1253
#define free(a)
Definition: header.h:65
long val
Definition: informix.c:689
@ PQTRANS_INTRANS
Definition: libpq-fe.h:148
@ PQTRANS_IDLE
Definition: libpq-fe.h:146
@ PQTRANS_ACTIVE
Definition: libpq-fe.h:147
@ PQTRANS_INERROR
Definition: libpq-fe.h:149
PGpipelineStatus
Definition: libpq-fe.h:185
@ PQ_PIPELINE_ABORTED
Definition: libpq-fe.h:188
@ PQ_PIPELINE_ON
Definition: libpq-fe.h:187
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:1710
#define DEFAULT_PGSOCKET_DIR
static bool is_superuser(Archive *fout)
Definition: pg_dump.c:4838
static char * buf
Definition: pg_test_fsync.c:72
#define snprintf
Definition: port.h:239
size_t strlcat(char *dst, const char *src, size_t siz)
Definition: strlcat.c:33
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
static bool is_unixsock_path(const char *path)
Definition: pqcomm.h:67
static int fd(const char *x, int i)
Definition: preproc-init.c:105
#define MAX_PROMPT_SIZE
@ PROMPT_READY
Definition: psqlscan.h:41
@ PROMPT_COPY
Definition: psqlscan.h:48
@ PROMPT_PAREN
Definition: psqlscan.h:47
@ PROMPT_COMMENT
Definition: psqlscan.h:43
@ PROMPT_CONTINUE
Definition: psqlscan.h:42
@ PROMPT_SINGLEQUOTE
Definition: psqlscan.h:44
@ PROMPT_DOLLARQUOTE
Definition: psqlscan.h:46
@ PROMPT_DOUBLEQUOTE
Definition: psqlscan.h:45
PsqlSettings pset
Definition: startup.c:32
int pg_strip_crlf(char *str)
Definition: string.c:154
VariableSpace vars
Definition: settings.h:145
int encoding
Definition: settings.h:98
const char * prompt2
Definition: settings.h:175
const char * prompt3
Definition: settings.h:176
PGconn * db
Definition: settings.h:97
uint64 stmt_lineno
Definition: settings.h:139
bool singleline
Definition: settings.h:162
const char * prompt1
Definition: settings.h:174
const char * GetVariable(VariableSpace space, const char *name)
Definition: variables.c:71
const char * name

References buf, conditional_active(), _psqlSettings::db, DEFAULT_PGSOCKET_DIR, _psqlSettings::encoding, fd(), free, GetVariable(), is_superuser(), is_unixsock_path(), MAX_PROMPT_SIZE, Min, name, pg_strip_crlf(), pnstrdup(), PQ_PIPELINE_ABORTED, PQ_PIPELINE_ON, PQbackendPID(), PQdb(), PQdsplen(), PQhost(), PQmblen(), PQpipelineStatus(), PQport(), PQservice(), PQTRANS_ACTIVE, PQTRANS_IDLE, PQTRANS_INERROR, PQTRANS_INTRANS, PQtransactionStatus(), PQuser(), _psqlSettings::prompt1, _psqlSettings::prompt2, _psqlSettings::prompt3, PROMPT_COMMENT, PROMPT_CONTINUE, PROMPT_COPY, PROMPT_DOLLARQUOTE, PROMPT_DOUBLEQUOTE, PROMPT_PAREN, PROMPT_READY, PROMPT_SINGLEQUOTE, pset, session_username(), _psqlSettings::singleline, snprintf, _psqlSettings::stmt_lineno, strlcat(), strlcpy(), UINT64_FORMAT, unconstify, val, and _psqlSettings::vars.

Referenced by handleCopyIn(), and MainLoop().