OSDN Git Service

Standard pgindent run for 8.1.
[pg-rex/syncrep.git] / src / bin / psql / prompt.c
1 /*
2  * psql - the PostgreSQL interactive terminal
3  *
4  * Copyright (c) 2000-2005, PostgreSQL Global Development Group
5  *
6  * $PostgreSQL: pgsql/src/bin/psql/prompt.c,v 1.40 2005/10/15 02:49:40 momjian Exp $
7  */
8 #include "postgres_fe.h"
9 #include "prompt.h"
10
11 #include "libpq-fe.h"
12
13 #include "settings.h"
14 #include "common.h"
15 #include "input.h"
16 #include "variables.h"
17
18 #ifdef WIN32
19 #include <io.h>
20 #include <win32.h>
21 #endif
22
23 #ifdef HAVE_UNIX_SOCKETS
24 #include <unistd.h>
25 #include <netdb.h>
26 #endif
27
28 /*--------------------------
29  * get_prompt
30  *
31  * Returns a statically allocated prompt made by interpolating certain
32  * tcsh style escape sequences into pset.vars "PROMPT1|2|3".
33  * (might not be completely multibyte safe)
34  *
35  * Defined interpolations are:
36  * %M - database server "hostname.domainname", "[local]" for AF_UNIX
37  *              sockets, "[local:/dir/name]" if not default
38  * %m - like %M, but hostname only (before first dot), or always "[local]"
39  * %> - database server port number
40  * %n - database user name
41  * %/ - current database
42  * %~ - like %/ but "~" when database name equals user name
43  * %# - "#" if superuser, ">" otherwise
44  * %R - in prompt1 normally =, or ^ if single line mode,
45  *                      or a ! if session is not connected to a database;
46  *              in prompt2 -, *, ', or ";
47  *              in prompt3 nothing
48  * %x - transaction status: empty, *, !, ? (unknown or no connection)
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 *
69 get_prompt(promptStatus_t status)
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         const char *prompt_name = NULL;
78
79         switch (status)
80         {
81                 case PROMPT_READY:
82                         prompt_name = "PROMPT1";
83                         break;
84
85                 case PROMPT_CONTINUE:
86                 case PROMPT_SINGLEQUOTE:
87                 case PROMPT_DOUBLEQUOTE:
88                 case PROMPT_DOLLARQUOTE:
89                 case PROMPT_COMMENT:
90                 case PROMPT_PAREN:
91                         prompt_name = "PROMPT2";
92                         break;
93
94                 case PROMPT_COPY:
95                         prompt_name = "PROMPT3";
96                         break;
97         }
98
99         if (prompt_name)
100                 prompt_string = GetVariable(pset.vars, prompt_name);
101
102         destination[0] = '\0';
103
104         for (p = prompt_string;
105                  p && *p && strlen(destination) < MAX_PROMPT_SIZE;
106                  p++)
107         {
108                 memset(buf, 0, MAX_PROMPT_SIZE + 1);
109                 if (esc)
110                 {
111                         switch (*p)
112                         {
113                                         /* Current database */
114                                 case '/':
115                                         if (pset.db)
116                                                 strncpy(buf, PQdb(pset.db), MAX_PROMPT_SIZE);
117                                         break;
118                                 case '~':
119                                         if (pset.db)
120                                         {
121                                                 const char *var;
122
123                                                 if (strcmp(PQdb(pset.db), PQuser(pset.db)) == 0 ||
124                                                         ((var = getenv("PGDATABASE")) && strcmp(var, PQdb(pset.db)) == 0))
125                                                         strcpy(buf, "~");
126                                                 else
127                                                         strncpy(buf, PQdb(pset.db), MAX_PROMPT_SIZE);
128                                         }
129                                         break;
130
131                                         /* DB server hostname (long/short) */
132                                 case 'M':
133                                 case 'm':
134                                         if (pset.db)
135                                         {
136                                                 const char *host = PQhost(pset.db);
137
138                                                 /* INET socket */
139                                                 if (host && host[0] && !is_absolute_path(host))
140                                                 {
141                                                         strncpy(buf, host, MAX_PROMPT_SIZE);
142                                                         if (*p == 'm')
143                                                                 buf[strcspn(buf, ".")] = '\0';
144                                                 }
145 #ifdef HAVE_UNIX_SOCKETS
146                                                 /* UNIX socket */
147                                                 else
148                                                 {
149                                                         if (!host
150                                                                 || strcmp(host, DEFAULT_PGSOCKET_DIR) == 0
151                                                                 || *p == 'm')
152                                                                 strncpy(buf, "[local]", MAX_PROMPT_SIZE);
153                                                         else
154                                                                 snprintf(buf, MAX_PROMPT_SIZE, "[local:%s]", host);
155                                                 }
156 #endif
157                                         }
158                                         break;
159                                         /* DB server port number */
160                                 case '>':
161                                         if (pset.db && PQport(pset.db))
162                                                 strncpy(buf, PQport(pset.db), MAX_PROMPT_SIZE);
163                                         break;
164                                         /* DB server user name */
165                                 case 'n':
166                                         if (pset.db)
167                                                 strncpy(buf, session_username(), MAX_PROMPT_SIZE);
168                                         break;
169
170                                 case '0':
171                                 case '1':
172                                 case '2':
173                                 case '3':
174                                 case '4':
175                                 case '5':
176                                 case '6':
177                                 case '7':
178                                         *buf = (char) strtol(p, (char **) &p, 8);
179                                         --p;
180                                         break;
181                                 case 'R':
182                                         switch (status)
183                                         {
184                                                 case PROMPT_READY:
185                                                         if (!pset.db)
186                                                                 buf[0] = '!';
187                                                         else if (!GetVariableBool(pset.vars, "SINGLELINE"))
188                                                                 buf[0] = '=';
189                                                         else
190                                                                 buf[0] = '^';
191                                                         break;
192                                                 case PROMPT_CONTINUE:
193                                                         buf[0] = '-';
194                                                         break;
195                                                 case PROMPT_SINGLEQUOTE:
196                                                         buf[0] = '\'';
197                                                         break;
198                                                 case PROMPT_DOUBLEQUOTE:
199                                                         buf[0] = '"';
200                                                         break;
201                                                 case PROMPT_DOLLARQUOTE:
202                                                         buf[0] = '$';
203                                                         break;
204                                                 case PROMPT_COMMENT:
205                                                         buf[0] = '*';
206                                                         break;
207                                                 case PROMPT_PAREN:
208                                                         buf[0] = '(';
209                                                         break;
210                                                 default:
211                                                         buf[0] = '\0';
212                                                         break;
213                                         }
214                                         break;
215
216                                 case 'x':
217                                         if (!pset.db)
218                                                 buf[0] = '?';
219                                         else
220                                                 switch (PQtransactionStatus(pset.db))
221                                                 {
222                                                         case PQTRANS_IDLE:
223                                                                 buf[0] = '\0';
224                                                                 break;
225                                                         case PQTRANS_ACTIVE:
226                                                         case PQTRANS_INTRANS:
227                                                                 buf[0] = '*';
228                                                                 break;
229                                                         case PQTRANS_INERROR:
230                                                                 buf[0] = '!';
231                                                                 break;
232                                                         default:
233                                                                 buf[0] = '?';
234                                                                 break;
235                                                 }
236                                         break;
237
238                                 case '?':
239                                         /* not here yet */
240                                         break;
241
242                                 case '#':
243                                         if (is_superuser())
244                                                 buf[0] = '#';
245                                         else
246                                                 buf[0] = '>';
247                                         break;
248
249                                         /* execute command */
250                                 case '`':
251                                         {
252                                                 FILE       *fd = NULL;
253                                                 char       *file = pg_strdup(p + 1);
254                                                 int                     cmdend;
255
256                                                 cmdend = strcspn(file, "`");
257                                                 file[cmdend] = '\0';
258                                                 if (file)
259                                                         fd = popen(file, "r");
260                                                 if (fd)
261                                                 {
262                                                         fgets(buf, MAX_PROMPT_SIZE - 1, fd);
263                                                         pclose(fd);
264                                                 }
265                                                 if (strlen(buf) > 0 && buf[strlen(buf) - 1] == '\n')
266                                                         buf[strlen(buf) - 1] = '\0';
267                                                 free(file);
268                                                 p += cmdend + 1;
269                                                 break;
270                                         }
271
272                                         /* interpolate variable */
273                                 case ':':
274                                         {
275                                                 char       *name;
276                                                 const char *val;
277                                                 int                     nameend;
278
279                                                 name = pg_strdup(p + 1);
280                                                 nameend = strcspn(name, ":");
281                                                 name[nameend] = '\0';
282                                                 val = GetVariable(pset.vars, name);
283                                                 if (val)
284                                                         strncpy(buf, val, MAX_PROMPT_SIZE);
285                                                 free(name);
286                                                 p += nameend + 1;
287                                                 break;
288                                         }
289
290                                 case '[':
291                                 case ']':
292 #if defined(USE_READLINE) && defined(RL_PROMPT_START_IGNORE)
293
294                                         /*
295                                          * readline >=4.0 undocumented feature: non-printing
296                                          * characters in prompt strings must be marked as such, in
297                                          * order to properly display the line during editing.
298                                          */
299                                         buf[0] = '\001';
300                                         buf[1] = (*p == '[') ? RL_PROMPT_START_IGNORE : RL_PROMPT_END_IGNORE;
301 #endif   /* USE_READLINE */
302                                         break;
303
304                                 default:
305                                         buf[0] = *p;
306                                         buf[1] = '\0';
307                                         break;
308
309                         }
310                         esc = false;
311                 }
312                 else if (*p == '%')
313                         esc = true;
314                 else
315                 {
316                         buf[0] = *p;
317                         buf[1] = '\0';
318                         esc = false;
319                 }
320
321                 if (!esc)
322                         strncat(destination, buf, MAX_PROMPT_SIZE - strlen(destination));
323         }
324
325         destination[MAX_PROMPT_SIZE] = '\0';
326         return destination;
327 }