PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
prompt.c
Go to the documentation of this file.
1 /*
2  * psql - the PostgreSQL interactive terminal
3  *
4  * Copyright (c) 2000-2017, PostgreSQL Global Development Group
5  *
6  * src/bin/psql/prompt.c
7  */
8 #include "postgres_fe.h"
9 
10 #ifdef WIN32
11 #include <io.h>
12 #include <win32.h>
13 #endif
14 
15 #ifdef HAVE_UNIX_SOCKETS
16 #include <unistd.h>
17 #include <netdb.h>
18 #endif
19 
20 #include "common.h"
21 #include "input.h"
22 #include "prompt.h"
23 #include "settings.h"
24 
25 
26 /*--------------------------
27  * get_prompt
28  *
29  * Returns a statically allocated prompt made by interpolating certain
30  * tcsh style escape sequences into pset.vars "PROMPT1|2|3".
31  * (might not be completely multibyte safe)
32  *
33  * Defined interpolations are:
34  * %M - database server "hostname.domainname", "[local]" for AF_UNIX
35  * sockets, "[local:/dir/name]" if not default
36  * %m - like %M, but hostname only (before first dot), or always "[local]"
37  * %p - backend pid
38  * %> - database server port number
39  * %n - database user name
40  * %/ - current database
41  * %~ - like %/ but "~" when database name equals user name
42  * %# - "#" if superuser, ">" otherwise
43  * %R - in prompt1 normally =, or ^ if single line mode,
44  * or a ! if session is not connected to a database;
45  * in prompt2 -, *, ', or ";
46  * in prompt3 nothing
47  * %x - transaction status: empty, *, !, ? (unknown or no connection)
48  * %l - The line number inside the current statement, starting from 1.
49  * %? - the error code of the last query (not yet implemented)
50  * %% - a percent sign
51  *
52  * %[0-9] - the character with the given decimal code
53  * %0[0-7] - the character with the given octal code
54  * %0x[0-9A-Fa-f] - the character with the given hexadecimal code
55  *
56  * %`command` - The result of executing command in /bin/sh with trailing
57  * newline stripped.
58  * %:name: - The value of the psql variable 'name'
59  * (those will not be rescanned for more escape sequences!)
60  *
61  * %[ ... %] - tell readline that the contained text is invisible
62  *
63  * If the application-wide prompts become NULL somehow, the returned string
64  * will be empty (not NULL!).
65  *--------------------------
66  */
67 
68 char *
70 {
71 #define MAX_PROMPT_SIZE 256
72  static char destination[MAX_PROMPT_SIZE + 1];
73  char buf[MAX_PROMPT_SIZE + 1];
74  bool esc = false;
75  const char *p;
76  const char *prompt_string = "? ";
77 
78  switch (status)
79  {
80  case PROMPT_READY:
81  prompt_string = pset.prompt1;
82  break;
83 
84  case PROMPT_CONTINUE:
85  case PROMPT_SINGLEQUOTE:
86  case PROMPT_DOUBLEQUOTE:
87  case PROMPT_DOLLARQUOTE:
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  /* DB server hostname (long/short) */
128  case 'M':
129  case 'm':
130  if (pset.db)
131  {
132  const char *host = PQhost(pset.db);
133 
134  /* INET socket */
135  if (host && host[0] && !is_absolute_path(host))
136  {
137  strlcpy(buf, host, sizeof(buf));
138  if (*p == 'm')
139  buf[strcspn(buf, ".")] = '\0';
140  }
141 #ifdef HAVE_UNIX_SOCKETS
142  /* UNIX socket */
143  else
144  {
145  if (!host
146  || strcmp(host, DEFAULT_PGSOCKET_DIR) == 0
147  || *p == 'm')
148  strlcpy(buf, "[local]", sizeof(buf));
149  else
150  snprintf(buf, sizeof(buf), "[local:%s]", host);
151  }
152 #endif
153  }
154  break;
155  /* DB server port number */
156  case '>':
157  if (pset.db && PQport(pset.db))
158  strlcpy(buf, PQport(pset.db), sizeof(buf));
159  break;
160  /* DB server user name */
161  case 'n':
162  if (pset.db)
163  strlcpy(buf, session_username(), sizeof(buf));
164  break;
165  /* backend pid */
166  case 'p':
167  if (pset.db)
168  {
169  int pid = PQbackendPID(pset.db);
170 
171  if (pid)
172  snprintf(buf, sizeof(buf), "%d", pid);
173  }
174  break;
175 
176  case '0':
177  case '1':
178  case '2':
179  case '3':
180  case '4':
181  case '5':
182  case '6':
183  case '7':
184  *buf = (char) strtol(p, (char **) &p, 8);
185  --p;
186  break;
187  case 'R':
188  switch (status)
189  {
190  case PROMPT_READY:
191  if (cstack != NULL && !conditional_active(cstack))
192  buf[0] = '@';
193  else if (!pset.db)
194  buf[0] = '!';
195  else if (!pset.singleline)
196  buf[0] = '=';
197  else
198  buf[0] = '^';
199  break;
200  case PROMPT_CONTINUE:
201  buf[0] = '-';
202  break;
203  case PROMPT_SINGLEQUOTE:
204  buf[0] = '\'';
205  break;
206  case PROMPT_DOUBLEQUOTE:
207  buf[0] = '"';
208  break;
209  case PROMPT_DOLLARQUOTE:
210  buf[0] = '$';
211  break;
212  case PROMPT_COMMENT:
213  buf[0] = '*';
214  break;
215  case PROMPT_PAREN:
216  buf[0] = '(';
217  break;
218  default:
219  buf[0] = '\0';
220  break;
221  }
222  break;
223 
224  case 'x':
225  if (!pset.db)
226  buf[0] = '?';
227  else
228  switch (PQtransactionStatus(pset.db))
229  {
230  case PQTRANS_IDLE:
231  buf[0] = '\0';
232  break;
233  case PQTRANS_ACTIVE:
234  case PQTRANS_INTRANS:
235  buf[0] = '*';
236  break;
237  case PQTRANS_INERROR:
238  buf[0] = '!';
239  break;
240  default:
241  buf[0] = '?';
242  break;
243  }
244  break;
245 
246  case 'l':
247  snprintf(buf, sizeof(buf), UINT64_FORMAT, pset.stmt_lineno);
248  break;
249 
250  case '?':
251  /* not here yet */
252  break;
253 
254  case '#':
255  if (is_superuser())
256  buf[0] = '#';
257  else
258  buf[0] = '>';
259  break;
260 
261  /* execute command */
262  case '`':
263  {
264  FILE *fd;
265  char *file = pg_strdup(p + 1);
266  int cmdend;
267 
268  cmdend = strcspn(file, "`");
269  file[cmdend] = '\0';
270  fd = popen(file, "r");
271  if (fd)
272  {
273  if (fgets(buf, sizeof(buf), fd) == NULL)
274  buf[0] = '\0';
275  pclose(fd);
276  }
277  if (strlen(buf) > 0 && buf[strlen(buf) - 1] == '\n')
278  buf[strlen(buf) - 1] = '\0';
279  free(file);
280  p += cmdend + 1;
281  break;
282  }
283 
284  /* interpolate variable */
285  case ':':
286  {
287  char *name;
288  const char *val;
289  int nameend;
290 
291  name = pg_strdup(p + 1);
292  nameend = strcspn(name, ":");
293  name[nameend] = '\0';
294  val = GetVariable(pset.vars, name);
295  if (val)
296  strlcpy(buf, val, sizeof(buf));
297  free(name);
298  p += nameend + 1;
299  break;
300  }
301 
302  case '[':
303  case ']':
304 #if defined(USE_READLINE) && defined(RL_PROMPT_START_IGNORE)
305 
306  /*
307  * readline >=4.0 undocumented feature: non-printing
308  * characters in prompt strings must be marked as such, in
309  * order to properly display the line during editing.
310  */
311  buf[0] = (*p == '[') ? RL_PROMPT_START_IGNORE : RL_PROMPT_END_IGNORE;
312  buf[1] = '\0';
313 #endif /* USE_READLINE */
314  break;
315 
316  default:
317  buf[0] = *p;
318  buf[1] = '\0';
319  break;
320 
321  }
322  esc = false;
323  }
324  else if (*p == '%')
325  esc = true;
326  else
327  {
328  buf[0] = *p;
329  buf[1] = '\0';
330  esc = false;
331  }
332 
333  if (!esc)
334  strlcat(destination, buf, sizeof(destination));
335  }
336 
337  return destination;
338 }
PGconn * db
Definition: settings.h:82
bool conditional_active(ConditionalStack cstack)
Definition: conditional.c:104
PsqlSettings pset
Definition: startup.c:33
const char * prompt3
Definition: settings.h:139
char * get_prompt(promptStatus_t status, ConditionalStack cstack)
Definition: prompt.c:69
char * PQport(const PGconn *conn)
Definition: fe-connect.c:6018
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
static int fd(const char *x, int i)
Definition: preproc-init.c:105
char * PQuser(const PGconn *conn)
Definition: fe-connect.c:5973
static char * buf
Definition: pg_test_fsync.c:67
const char * session_username(void)
Definition: common.c:2282
#define is_absolute_path(filename)
Definition: port.h:77
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
bool singleline
Definition: settings.h:127
PGTransactionStatusType PQtransactionStatus(const PGconn *conn)
Definition: fe-connect.c:6052
const char * GetVariable(VariableSpace space, const char *name)
Definition: variables.c:71
int PQbackendPID(const PGconn *conn)
Definition: fe-connect.c:6123
char * PQhost(const PGconn *conn)
Definition: fe-connect.c:5998
#define free(a)
Definition: header.h:65
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
char * PQdb(const PGconn *conn)
Definition: fe-connect.c:5965
#define MAX_PROMPT_SIZE
const char * prompt2
Definition: settings.h:138
enum _promptStatus promptStatus_t
const char * prompt1
Definition: settings.h:137
static bool is_superuser(Archive *fout)
Definition: pg_dump.c:3748
const char * name
Definition: encode.c:521
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:225
#define UINT64_FORMAT
Definition: c.h:301
long val
Definition: informix.c:689
uint64 stmt_lineno
Definition: settings.h:111
size_t strlcat(char *dst, const char *src, size_t siz)
Definition: strlcat.c:33
#define DEFAULT_PGSOCKET_DIR
VariableSpace vars
Definition: settings.h:117