2 * psql - the PostgreSQL interactive terminal
4 * Copyright (c) 2000-2006, PostgreSQL Global Development Group
6 * $PostgreSQL: pgsql/src/bin/psql/prompt.c,v 1.48 2006/08/29 15:19:51 tgl Exp $
8 #include "postgres_fe.h"
15 #ifdef HAVE_UNIX_SOCKETS
26 /*--------------------------
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)
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 * %> - database server port number
38 * %n - database user name
39 * %/ - current database
40 * %~ - like %/ but "~" when database name equals user name
41 * %# - "#" if superuser, ">" otherwise
42 * %R - in prompt1 normally =, or ^ if single line mode,
43 * or a ! if session is not connected to a database;
44 * in prompt2 -, *, ', or ";
46 * %x - transaction status: empty, *, !, ? (unknown or no connection)
47 * %? - the error code of the last query (not yet implemented)
50 * %[0-9] - the character with the given decimal code
51 * %0[0-7] - the character with the given octal code
52 * %0x[0-9A-Fa-f] - the character with the given hexadecimal code
54 * %`command` - The result of executing command in /bin/sh with trailing
56 * %:name: - The value of the psql variable 'name'
57 * (those will not be rescanned for more escape sequences!)
59 * %[ ... %] - tell readline that the contained text is invisible
61 * If the application-wide prompts become NULL somehow, the returned string
62 * will be empty (not NULL!).
63 *--------------------------
67 get_prompt(promptStatus_t status)
69 #define MAX_PROMPT_SIZE 256
70 static char destination[MAX_PROMPT_SIZE + 1];
71 char buf[MAX_PROMPT_SIZE + 1];
74 const char *prompt_string = "? ";
79 prompt_string = pset.prompt1;
83 case PROMPT_SINGLEQUOTE:
84 case PROMPT_DOUBLEQUOTE:
85 case PROMPT_DOLLARQUOTE:
88 prompt_string = pset.prompt2;
92 prompt_string = pset.prompt3;
96 destination[0] = '\0';
98 for (p = prompt_string;
99 *p && strlen(destination) < MAX_PROMPT_SIZE;
102 memset(buf, 0, MAX_PROMPT_SIZE + 1);
107 /* Current database */
110 strncpy(buf, PQdb(pset.db), MAX_PROMPT_SIZE);
117 if (strcmp(PQdb(pset.db), PQuser(pset.db)) == 0 ||
118 ((var = getenv("PGDATABASE")) && strcmp(var, PQdb(pset.db)) == 0))
121 strncpy(buf, PQdb(pset.db), MAX_PROMPT_SIZE);
125 /* DB server hostname (long/short) */
130 const char *host = PQhost(pset.db);
133 if (host && host[0] && !is_absolute_path(host))
135 strncpy(buf, host, MAX_PROMPT_SIZE);
137 buf[strcspn(buf, ".")] = '\0';
139 #ifdef HAVE_UNIX_SOCKETS
144 || strcmp(host, DEFAULT_PGSOCKET_DIR) == 0
146 strncpy(buf, "[local]", MAX_PROMPT_SIZE);
148 snprintf(buf, MAX_PROMPT_SIZE, "[local:%s]", host);
153 /* DB server port number */
155 if (pset.db && PQport(pset.db))
156 strncpy(buf, PQport(pset.db), MAX_PROMPT_SIZE);
158 /* DB server user name */
161 strncpy(buf, session_username(), MAX_PROMPT_SIZE);
172 *buf = (char) strtol(p, (char **) &p, 8);
181 else if (!pset.singleline)
186 case PROMPT_CONTINUE:
189 case PROMPT_SINGLEQUOTE:
192 case PROMPT_DOUBLEQUOTE:
195 case PROMPT_DOLLARQUOTE:
214 switch (PQtransactionStatus(pset.db))
220 case PQTRANS_INTRANS:
223 case PQTRANS_INERROR:
243 /* execute command */
247 char *file = pg_strdup(p + 1);
250 cmdend = strcspn(file, "`");
252 fd = popen(file, "r");
255 fgets(buf, MAX_PROMPT_SIZE - 1, fd);
258 if (strlen(buf) > 0 && buf[strlen(buf) - 1] == '\n')
259 buf[strlen(buf) - 1] = '\0';
265 /* interpolate variable */
272 name = pg_strdup(p + 1);
273 nameend = strcspn(name, ":");
274 name[nameend] = '\0';
275 val = GetVariable(pset.vars, name);
277 strncpy(buf, val, MAX_PROMPT_SIZE);
285 #if defined(USE_READLINE) && defined(RL_PROMPT_START_IGNORE)
288 * readline >=4.0 undocumented feature: non-printing
289 * characters in prompt strings must be marked as such, in
290 * order to properly display the line during editing.
292 buf[0] = (*p == '[') ? RL_PROMPT_START_IGNORE : RL_PROMPT_END_IGNORE;
294 #endif /* USE_READLINE */
315 strncat(destination, buf, MAX_PROMPT_SIZE - strlen(destination));
318 destination[MAX_PROMPT_SIZE] = '\0';