compat/terminal: support echoing on windows
[git/dscho.git] / compat / terminal.c
blob8e91f330eb55ebfc65eeb18455a30fd1814ab808
1 #include "git-compat-util.h"
2 #include "compat/terminal.h"
3 #include "sigchain.h"
4 #include "strbuf.h"
6 #ifdef HAVE_DEV_TTY
8 static int term_fd = -1;
9 static struct termios old_term;
11 static void restore_term(void)
13 if (term_fd < 0)
14 return;
16 tcsetattr(term_fd, TCSAFLUSH, &old_term);
17 term_fd = -1;
20 static void restore_term_on_signal(int sig)
22 restore_term();
23 sigchain_pop(sig);
24 raise(sig);
27 char *git_terminal_prompt(const char *prompt, int echo)
29 static struct strbuf buf = STRBUF_INIT;
30 int r;
31 FILE *fh;
33 fh = fopen("/dev/tty", "w+");
34 if (!fh)
35 return NULL;
37 if (!echo) {
38 struct termios t;
40 if (tcgetattr(fileno(fh), &t) < 0) {
41 fclose(fh);
42 return NULL;
45 old_term = t;
46 term_fd = fileno(fh);
47 sigchain_push_common(restore_term_on_signal);
49 t.c_lflag &= ~ECHO;
50 if (tcsetattr(fileno(fh), TCSAFLUSH, &t) < 0) {
51 term_fd = -1;
52 fclose(fh);
53 return NULL;
57 fputs(prompt, fh);
58 fflush(fh);
60 r = strbuf_getline(&buf, fh, '\n');
61 if (!echo) {
62 fseek(fh, SEEK_CUR, 0);
63 putc('\n', fh);
64 fflush(fh);
67 restore_term();
68 fclose(fh);
70 if (r == EOF)
71 return NULL;
72 return buf.buf;
75 #elif defined(WIN32)
77 char *git_terminal_prompt(const char *prompt, int echo)
79 static struct strbuf buf = STRBUF_INIT;
81 fputs(prompt, stderr);
82 strbuf_reset(&buf);
83 for (;;) {
84 int c = _getch();
85 if (c == '\n' || c == '\r')
86 break;
87 if (echo)
88 putc(c, stderr);
89 strbuf_addch(&buf, c);
91 putc('\n', stderr);
92 return buf.buf;
95 #else
97 char *git_terminal_prompt(const char *prompt, int echo)
99 return getpass(prompt);
102 #endif