mirror of
https://github.com/git/git.git
synced 2026-02-17 21:28:11 +00:00
Without /dev/tty support, git_terminal_prompt simply ignores the 'echo'-parameter. On Windows we can do better by clevering up our getpass-implementation a bit so it can conditionally echo. While we're at it, plug a small memory-leak by returning a pointer to a static strbuf instead of detaching it. This is the same thing the /dev/tty-version of git_terminal_prompt does, and the callee doesn't expect to have to free it's memory. Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com>
103 lines
1.5 KiB
C
103 lines
1.5 KiB
C
#include "git-compat-util.h"
|
|
#include "compat/terminal.h"
|
|
#include "sigchain.h"
|
|
#include "strbuf.h"
|
|
|
|
#ifdef HAVE_DEV_TTY
|
|
|
|
static int term_fd = -1;
|
|
static struct termios old_term;
|
|
|
|
static void restore_term(void)
|
|
{
|
|
if (term_fd < 0)
|
|
return;
|
|
|
|
tcsetattr(term_fd, TCSAFLUSH, &old_term);
|
|
term_fd = -1;
|
|
}
|
|
|
|
static void restore_term_on_signal(int sig)
|
|
{
|
|
restore_term();
|
|
sigchain_pop(sig);
|
|
raise(sig);
|
|
}
|
|
|
|
char *git_terminal_prompt(const char *prompt, int echo)
|
|
{
|
|
static struct strbuf buf = STRBUF_INIT;
|
|
int r;
|
|
FILE *fh;
|
|
|
|
fh = fopen("/dev/tty", "w+");
|
|
if (!fh)
|
|
return NULL;
|
|
|
|
if (!echo) {
|
|
struct termios t;
|
|
|
|
if (tcgetattr(fileno(fh), &t) < 0) {
|
|
fclose(fh);
|
|
return NULL;
|
|
}
|
|
|
|
old_term = t;
|
|
term_fd = fileno(fh);
|
|
sigchain_push_common(restore_term_on_signal);
|
|
|
|
t.c_lflag &= ~ECHO;
|
|
if (tcsetattr(fileno(fh), TCSAFLUSH, &t) < 0) {
|
|
term_fd = -1;
|
|
fclose(fh);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
fputs(prompt, fh);
|
|
fflush(fh);
|
|
|
|
r = strbuf_getline(&buf, fh, '\n');
|
|
if (!echo) {
|
|
fseek(fh, SEEK_CUR, 0);
|
|
putc('\n', fh);
|
|
fflush(fh);
|
|
}
|
|
|
|
restore_term();
|
|
fclose(fh);
|
|
|
|
if (r == EOF)
|
|
return NULL;
|
|
return buf.buf;
|
|
}
|
|
|
|
#elif defined(WIN32)
|
|
|
|
char *git_terminal_prompt(const char *prompt, int echo)
|
|
{
|
|
static struct strbuf buf = STRBUF_INIT;
|
|
|
|
fputs(prompt, stderr);
|
|
strbuf_reset(&buf);
|
|
for (;;) {
|
|
int c = _getch();
|
|
if (c == '\n' || c == '\r')
|
|
break;
|
|
if (echo)
|
|
putc(c, stderr);
|
|
strbuf_addch(&buf, c);
|
|
}
|
|
putc('\n', stderr);
|
|
return buf.buf;
|
|
}
|
|
|
|
#else
|
|
|
|
char *git_terminal_prompt(const char *prompt, int echo)
|
|
{
|
|
return getpass(prompt);
|
|
}
|
|
|
|
#endif
|