Header And Logo

PostgreSQL
| The world's most advanced open source database.

prompt.c

Go to the documentation of this file.
00001 /*
00002  * psql - the PostgreSQL interactive terminal
00003  *
00004  * Copyright (c) 2000-2013, PostgreSQL Global Development Group
00005  *
00006  * src/bin/psql/prompt.c
00007  */
00008 #include "postgres_fe.h"
00009 
00010 #ifdef WIN32
00011 #include <io.h>
00012 #include <win32.h>
00013 #endif
00014 
00015 #ifdef HAVE_UNIX_SOCKETS
00016 #include <unistd.h>
00017 #include <netdb.h>
00018 #endif
00019 
00020 #include "common.h"
00021 #include "input.h"
00022 #include "prompt.h"
00023 #include "settings.h"
00024 
00025 
00026 /*--------------------------
00027  * get_prompt
00028  *
00029  * Returns a statically allocated prompt made by interpolating certain
00030  * tcsh style escape sequences into pset.vars "PROMPT1|2|3".
00031  * (might not be completely multibyte safe)
00032  *
00033  * Defined interpolations are:
00034  * %M - database server "hostname.domainname", "[local]" for AF_UNIX
00035  *      sockets, "[local:/dir/name]" if not default
00036  * %m - like %M, but hostname only (before first dot), or always "[local]"
00037  * %> - database server port number
00038  * %n - database user name
00039  * %/ - current database
00040  * %~ - like %/ but "~" when database name equals user name
00041  * %# - "#" if superuser, ">" otherwise
00042  * %R - in prompt1 normally =, or ^ if single line mode,
00043  *          or a ! if session is not connected to a database;
00044  *      in prompt2 -, *, ', or ";
00045  *      in prompt3 nothing
00046  * %x - transaction status: empty, *, !, ? (unknown or no connection)
00047  * %? - the error code of the last query (not yet implemented)
00048  * %% - a percent sign
00049  *
00050  * %[0-9]          - the character with the given decimal code
00051  * %0[0-7]         - the character with the given octal code
00052  * %0x[0-9A-Fa-f]  - the character with the given hexadecimal code
00053  *
00054  * %`command`      - The result of executing command in /bin/sh with trailing
00055  *                   newline stripped.
00056  * %:name:         - The value of the psql variable 'name'
00057  * (those will not be rescanned for more escape sequences!)
00058  *
00059  * %[ ... %]       - tell readline that the contained text is invisible
00060  *
00061  * If the application-wide prompts become NULL somehow, the returned string
00062  * will be empty (not NULL!).
00063  *--------------------------
00064  */
00065 
00066 char *
00067 get_prompt(promptStatus_t status)
00068 {
00069 #define MAX_PROMPT_SIZE 256
00070     static char destination[MAX_PROMPT_SIZE + 1];
00071     char        buf[MAX_PROMPT_SIZE + 1];
00072     bool        esc = false;
00073     const char *p;
00074     const char *prompt_string = "? ";
00075 
00076     switch (status)
00077     {
00078         case PROMPT_READY:
00079             prompt_string = pset.prompt1;
00080             break;
00081 
00082         case PROMPT_CONTINUE:
00083         case PROMPT_SINGLEQUOTE:
00084         case PROMPT_DOUBLEQUOTE:
00085         case PROMPT_DOLLARQUOTE:
00086         case PROMPT_COMMENT:
00087         case PROMPT_PAREN:
00088             prompt_string = pset.prompt2;
00089             break;
00090 
00091         case PROMPT_COPY:
00092             prompt_string = pset.prompt3;
00093             break;
00094     }
00095 
00096     destination[0] = '\0';
00097 
00098     for (p = prompt_string;
00099          *p && strlen(destination) < sizeof(destination) - 1;
00100          p++)
00101     {
00102         memset(buf, 0, sizeof(buf));
00103         if (esc)
00104         {
00105             switch (*p)
00106             {
00107                     /* Current database */
00108                 case '/':
00109                     if (pset.db)
00110                         strlcpy(buf, PQdb(pset.db), sizeof(buf));
00111                     break;
00112                 case '~':
00113                     if (pset.db)
00114                     {
00115                         const char *var;
00116 
00117                         if (strcmp(PQdb(pset.db), PQuser(pset.db)) == 0 ||
00118                             ((var = getenv("PGDATABASE")) && strcmp(var, PQdb(pset.db)) == 0))
00119                             strlcpy(buf, "~", sizeof(buf));
00120                         else
00121                             strlcpy(buf, PQdb(pset.db), sizeof(buf));
00122                     }
00123                     break;
00124 
00125                     /* DB server hostname (long/short) */
00126                 case 'M':
00127                 case 'm':
00128                     if (pset.db)
00129                     {
00130                         const char *host = PQhost(pset.db);
00131 
00132                         /* INET socket */
00133                         if (host && host[0] && !is_absolute_path(host))
00134                         {
00135                             strlcpy(buf, host, sizeof(buf));
00136                             if (*p == 'm')
00137                                 buf[strcspn(buf, ".")] = '\0';
00138                         }
00139 #ifdef HAVE_UNIX_SOCKETS
00140                         /* UNIX socket */
00141                         else
00142                         {
00143                             if (!host
00144                                 || strcmp(host, DEFAULT_PGSOCKET_DIR) == 0
00145                                 || *p == 'm')
00146                                 strlcpy(buf, "[local]", sizeof(buf));
00147                             else
00148                                 snprintf(buf, sizeof(buf), "[local:%s]", host);
00149                         }
00150 #endif
00151                     }
00152                     break;
00153                     /* DB server port number */
00154                 case '>':
00155                     if (pset.db && PQport(pset.db))
00156                         strlcpy(buf, PQport(pset.db), sizeof(buf));
00157                     break;
00158                     /* DB server user name */
00159                 case 'n':
00160                     if (pset.db)
00161                         strlcpy(buf, session_username(), sizeof(buf));
00162                     break;
00163 
00164                 case '0':
00165                 case '1':
00166                 case '2':
00167                 case '3':
00168                 case '4':
00169                 case '5':
00170                 case '6':
00171                 case '7':
00172                     *buf = (char) strtol(p, (char **) &p, 8);
00173                     --p;
00174                     break;
00175                 case 'R':
00176                     switch (status)
00177                     {
00178                         case PROMPT_READY:
00179                             if (!pset.db)
00180                                 buf[0] = '!';
00181                             else if (!pset.singleline)
00182                                 buf[0] = '=';
00183                             else
00184                                 buf[0] = '^';
00185                             break;
00186                         case PROMPT_CONTINUE:
00187                             buf[0] = '-';
00188                             break;
00189                         case PROMPT_SINGLEQUOTE:
00190                             buf[0] = '\'';
00191                             break;
00192                         case PROMPT_DOUBLEQUOTE:
00193                             buf[0] = '"';
00194                             break;
00195                         case PROMPT_DOLLARQUOTE:
00196                             buf[0] = '$';
00197                             break;
00198                         case PROMPT_COMMENT:
00199                             buf[0] = '*';
00200                             break;
00201                         case PROMPT_PAREN:
00202                             buf[0] = '(';
00203                             break;
00204                         default:
00205                             buf[0] = '\0';
00206                             break;
00207                     }
00208                     break;
00209 
00210                 case 'x':
00211                     if (!pset.db)
00212                         buf[0] = '?';
00213                     else
00214                         switch (PQtransactionStatus(pset.db))
00215                         {
00216                             case PQTRANS_IDLE:
00217                                 buf[0] = '\0';
00218                                 break;
00219                             case PQTRANS_ACTIVE:
00220                             case PQTRANS_INTRANS:
00221                                 buf[0] = '*';
00222                                 break;
00223                             case PQTRANS_INERROR:
00224                                 buf[0] = '!';
00225                                 break;
00226                             default:
00227                                 buf[0] = '?';
00228                                 break;
00229                         }
00230                     break;
00231 
00232                 case '?':
00233                     /* not here yet */
00234                     break;
00235 
00236                 case '#':
00237                     if (is_superuser())
00238                         buf[0] = '#';
00239                     else
00240                         buf[0] = '>';
00241                     break;
00242 
00243                     /* execute command */
00244                 case '`':
00245                     {
00246                         FILE       *fd;
00247                         char       *file = pg_strdup(p + 1);
00248                         int         cmdend;
00249 
00250                         cmdend = strcspn(file, "`");
00251                         file[cmdend] = '\0';
00252                         fd = popen(file, "r");
00253                         if (fd)
00254                         {
00255                             if (fgets(buf, sizeof(buf), fd) == NULL)
00256                                 buf[0] = '\0';
00257                             pclose(fd);
00258                         }
00259                         if (strlen(buf) > 0 && buf[strlen(buf) - 1] == '\n')
00260                             buf[strlen(buf) - 1] = '\0';
00261                         free(file);
00262                         p += cmdend + 1;
00263                         break;
00264                     }
00265 
00266                     /* interpolate variable */
00267                 case ':':
00268                     {
00269                         char       *name;
00270                         const char *val;
00271                         int         nameend;
00272 
00273                         name = pg_strdup(p + 1);
00274                         nameend = strcspn(name, ":");
00275                         name[nameend] = '\0';
00276                         val = GetVariable(pset.vars, name);
00277                         if (val)
00278                             strlcpy(buf, val, sizeof(buf));
00279                         free(name);
00280                         p += nameend + 1;
00281                         break;
00282                     }
00283 
00284                 case '[':
00285                 case ']':
00286 #if defined(USE_READLINE) && defined(RL_PROMPT_START_IGNORE)
00287 
00288                     /*
00289                      * readline >=4.0 undocumented feature: non-printing
00290                      * characters in prompt strings must be marked as such, in
00291                      * order to properly display the line during editing.
00292                      */
00293                     buf[0] = (*p == '[') ? RL_PROMPT_START_IGNORE : RL_PROMPT_END_IGNORE;
00294                     buf[1] = '\0';
00295 #endif   /* USE_READLINE */
00296                     break;
00297 
00298                 default:
00299                     buf[0] = *p;
00300                     buf[1] = '\0';
00301                     break;
00302 
00303             }
00304             esc = false;
00305         }
00306         else if (*p == '%')
00307             esc = true;
00308         else
00309         {
00310             buf[0] = *p;
00311             buf[1] = '\0';
00312             esc = false;
00313         }
00314 
00315         if (!esc)
00316             strlcat(destination, buf, sizeof(destination));
00317     }
00318 
00319     return destination;
00320 }