PostgreSQL Source Code git master
prompt.h File Reference
Include dependency graph for prompt.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

char * get_prompt (promptStatus_t status, ConditionalStack cstack)
 

Function Documentation

◆ get_prompt()

char * get_prompt ( promptStatus_t  status,
ConditionalStack  cstack 
)

Definition at line 67 of file prompt.c.

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