Header And Logo

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

sprompt.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * sprompt.c
00004  *    simple_prompt() routine
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/port/sprompt.c
00012  *
00013  *-------------------------------------------------------------------------
00014  */
00015 
00016 
00017 /*
00018  * simple_prompt
00019  *
00020  * Generalized function especially intended for reading in usernames and
00021  * password interactively. Reads from /dev/tty or stdin/stderr.
00022  *
00023  * prompt:      The prompt to print
00024  * maxlen:      How many characters to accept
00025  * echo:        Set to false if you want to hide what is entered (for passwords)
00026  *
00027  * Returns a malloc()'ed string with the input (w/o trailing newline).
00028  */
00029 #include "c.h"
00030 
00031 #ifdef HAVE_TERMIOS_H
00032 #include <termios.h>
00033 #endif
00034 
00035 extern char *simple_prompt(const char *prompt, int maxlen, bool echo);
00036 
00037 char *
00038 simple_prompt(const char *prompt, int maxlen, bool echo)
00039 {
00040     int         length;
00041     char       *destination;
00042     FILE       *termin,
00043                *termout;
00044 
00045 #ifdef HAVE_TERMIOS_H
00046     struct termios t_orig,
00047                 t;
00048 #else
00049 #ifdef WIN32
00050     HANDLE      t = NULL;
00051     LPDWORD     t_orig = NULL;
00052 #endif
00053 #endif
00054 
00055     destination = (char *) malloc(maxlen + 1);
00056     if (!destination)
00057         return NULL;
00058 
00059 #ifdef WIN32
00060 
00061     /*
00062      * A Windows console has an "input code page" and an "output code page";
00063      * these usually match each other, but they rarely match the "Windows ANSI
00064      * code page" defined at system boot and expected of "char *" arguments to
00065      * Windows API functions.  The Microsoft CRT write() implementation
00066      * automatically converts text between these code pages when writing to a
00067      * console.  To identify such file descriptors, it calls GetConsoleMode()
00068      * on the underlying HANDLE, which in turn requires GENERIC_READ access on
00069      * the HANDLE.  Opening termout in mode "w+" allows that detection to
00070      * succeed.  Otherwise, write() would not recognize the descriptor as a
00071      * console, and non-ASCII characters would display incorrectly.
00072      *
00073      * XXX fgets() still receives text in the console's input code page.  This
00074      * makes non-ASCII credentials unportable.
00075      */
00076     termin = fopen("CONIN$", "r");
00077     termout = fopen("CONOUT$", "w+");
00078 #else
00079 
00080     /*
00081      * Do not try to collapse these into one "w+" mode file. Doesn't work on
00082      * some platforms (eg, HPUX 10.20).
00083      */
00084     termin = fopen("/dev/tty", "r");
00085     termout = fopen("/dev/tty", "w");
00086 #endif
00087     if (!termin || !termout
00088 #ifdef WIN32
00089     /*
00090      * Direct console I/O does not work from the MSYS 1.0.10 console.  Writes
00091      * reach nowhere user-visible; reads block indefinitely.  XXX This affects
00092      * most Windows terminal environments, including rxvt, mintty, Cygwin
00093      * xterm, Cygwin sshd, and PowerShell ISE.  Switch to a more-generic test.
00094      */
00095         || (getenv("OSTYPE") && strcmp(getenv("OSTYPE"), "msys") == 0)
00096 #endif
00097         )
00098     {
00099         if (termin)
00100             fclose(termin);
00101         if (termout)
00102             fclose(termout);
00103         termin = stdin;
00104         termout = stderr;
00105     }
00106 
00107 #ifdef HAVE_TERMIOS_H
00108     if (!echo)
00109     {
00110         tcgetattr(fileno(termin), &t);
00111         t_orig = t;
00112         t.c_lflag &= ~ECHO;
00113         tcsetattr(fileno(termin), TCSAFLUSH, &t);
00114     }
00115 #else
00116 #ifdef WIN32
00117     if (!echo)
00118     {
00119         /* get a new handle to turn echo off */
00120         t_orig = (LPDWORD) malloc(sizeof(DWORD));
00121         t = GetStdHandle(STD_INPUT_HANDLE);
00122 
00123         /* save the old configuration first */
00124         GetConsoleMode(t, t_orig);
00125 
00126         /* set to the new mode */
00127         SetConsoleMode(t, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
00128     }
00129 #endif
00130 #endif
00131 
00132     if (prompt)
00133     {
00134         fputs(_(prompt), termout);
00135         fflush(termout);
00136     }
00137 
00138     if (fgets(destination, maxlen + 1, termin) == NULL)
00139         destination[0] = '\0';
00140 
00141     length = strlen(destination);
00142     if (length > 0 && destination[length - 1] != '\n')
00143     {
00144         /* eat rest of the line */
00145         char        buf[128];
00146         int         buflen;
00147 
00148         do
00149         {
00150             if (fgets(buf, sizeof(buf), termin) == NULL)
00151                 break;
00152             buflen = strlen(buf);
00153         } while (buflen > 0 && buf[buflen - 1] != '\n');
00154     }
00155 
00156     if (length > 0 && destination[length - 1] == '\n')
00157         /* remove trailing newline */
00158         destination[length - 1] = '\0';
00159 
00160 #ifdef HAVE_TERMIOS_H
00161     if (!echo)
00162     {
00163         tcsetattr(fileno(termin), TCSAFLUSH, &t_orig);
00164         fputs("\n", termout);
00165         fflush(termout);
00166     }
00167 #else
00168 #ifdef WIN32
00169     if (!echo)
00170     {
00171         /* reset to the original console mode */
00172         SetConsoleMode(t, *t_orig);
00173         fputs("\n", termout);
00174         fflush(termout);
00175         free(t_orig);
00176     }
00177 #endif
00178 #endif
00179 
00180     if (termin != stdin)
00181     {
00182         fclose(termin);
00183         fclose(termout);
00184     }
00185 
00186     return destination;
00187 }