]> granicus.if.org Git - postgresql/blob - src/port/sprompt.c
Fix the fastpath rule for jsonb_concat with an empty operand.
[postgresql] / src / port / sprompt.c
1 /*-------------------------------------------------------------------------
2  *
3  * sprompt.c
4  *        simple_prompt() routine
5  *
6  * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        src/port/sprompt.c
12  *
13  *-------------------------------------------------------------------------
14  */
15
16
17 /*
18  * simple_prompt
19  *
20  * Generalized function especially intended for reading in usernames and
21  * password interactively. Reads from /dev/tty or stdin/stderr.
22  *
23  * prompt:              The prompt to print
24  * maxlen:              How many characters to accept
25  * echo:                Set to false if you want to hide what is entered (for passwords)
26  *
27  * Returns a malloc()'ed string with the input (w/o trailing newline).
28  */
29 #include "c.h"
30
31 #ifdef HAVE_TERMIOS_H
32 #include <termios.h>
33 #endif
34
35 extern char *simple_prompt(const char *prompt, int maxlen, bool echo);
36
37 char *
38 simple_prompt(const char *prompt, int maxlen, bool echo)
39 {
40         int                     length;
41         char       *destination;
42         FILE       *termin,
43                            *termout;
44
45 #ifdef HAVE_TERMIOS_H
46         struct termios t_orig,
47                                 t;
48 #else
49 #ifdef WIN32
50         HANDLE          t = NULL;
51         LPDWORD         t_orig = NULL;
52 #endif
53 #endif
54
55         destination = (char *) malloc(maxlen + 1);
56         if (!destination)
57                 return NULL;
58
59 #ifdef WIN32
60
61         /*
62          * A Windows console has an "input code page" and an "output code page";
63          * these usually match each other, but they rarely match the "Windows ANSI
64          * code page" defined at system boot and expected of "char *" arguments to
65          * Windows API functions.  The Microsoft CRT write() implementation
66          * automatically converts text between these code pages when writing to a
67          * console.  To identify such file descriptors, it calls GetConsoleMode()
68          * on the underlying HANDLE, which in turn requires GENERIC_READ access on
69          * the HANDLE.  Opening termout in mode "w+" allows that detection to
70          * succeed.  Otherwise, write() would not recognize the descriptor as a
71          * console, and non-ASCII characters would display incorrectly.
72          *
73          * XXX fgets() still receives text in the console's input code page.  This
74          * makes non-ASCII credentials unportable.
75          */
76         termin = fopen("CONIN$", "r");
77         termout = fopen("CONOUT$", "w+");
78 #else
79
80         /*
81          * Do not try to collapse these into one "w+" mode file. Doesn't work on
82          * some platforms (eg, HPUX 10.20).
83          */
84         termin = fopen("/dev/tty", "r");
85         termout = fopen("/dev/tty", "w");
86 #endif
87         if (!termin || !termout
88 #ifdef WIN32
89
90         /*
91          * Direct console I/O does not work from the MSYS 1.0.10 console.  Writes
92          * reach nowhere user-visible; reads block indefinitely.  XXX This affects
93          * most Windows terminal environments, including rxvt, mintty, Cygwin
94          * xterm, Cygwin sshd, and PowerShell ISE.  Switch to a more-generic test.
95          */
96                 || (getenv("OSTYPE") && strcmp(getenv("OSTYPE"), "msys") == 0)
97 #endif
98                 )
99         {
100                 if (termin)
101                         fclose(termin);
102                 if (termout)
103                         fclose(termout);
104                 termin = stdin;
105                 termout = stderr;
106         }
107
108 #ifdef HAVE_TERMIOS_H
109         if (!echo)
110         {
111                 tcgetattr(fileno(termin), &t);
112                 t_orig = t;
113                 t.c_lflag &= ~ECHO;
114                 tcsetattr(fileno(termin), TCSAFLUSH, &t);
115         }
116 #else
117 #ifdef WIN32
118         if (!echo)
119         {
120                 /* get a new handle to turn echo off */
121                 t_orig = (LPDWORD) malloc(sizeof(DWORD));
122                 t = GetStdHandle(STD_INPUT_HANDLE);
123
124                 /* save the old configuration first */
125                 GetConsoleMode(t, t_orig);
126
127                 /* set to the new mode */
128                 SetConsoleMode(t, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
129         }
130 #endif
131 #endif
132
133         if (prompt)
134         {
135                 fputs(_(prompt), termout);
136                 fflush(termout);
137         }
138
139         if (fgets(destination, maxlen + 1, termin) == NULL)
140                 destination[0] = '\0';
141
142         length = strlen(destination);
143         if (length > 0 && destination[length - 1] != '\n')
144         {
145                 /* eat rest of the line */
146                 char            buf[128];
147                 int                     buflen;
148
149                 do
150                 {
151                         if (fgets(buf, sizeof(buf), termin) == NULL)
152                                 break;
153                         buflen = strlen(buf);
154                 } while (buflen > 0 && buf[buflen - 1] != '\n');
155         }
156
157         if (length > 0 && destination[length - 1] == '\n')
158                 /* remove trailing newline */
159                 destination[length - 1] = '\0';
160
161 #ifdef HAVE_TERMIOS_H
162         if (!echo)
163         {
164                 tcsetattr(fileno(termin), TCSAFLUSH, &t_orig);
165                 fputs("\n", termout);
166                 fflush(termout);
167         }
168 #else
169 #ifdef WIN32
170         if (!echo)
171         {
172                 /* reset to the original console mode */
173                 SetConsoleMode(t, *t_orig);
174                 fputs("\n", termout);
175                 fflush(termout);
176                 free(t_orig);
177         }
178 #endif
179 #endif
180
181         if (termin != stdin)
182         {
183                 fclose(termin);
184                 fclose(termout);
185         }
186
187         return destination;
188 }