Merge branch 'jc/diff-stat-scaler'
[git] / compat / terminal.c
1 #include "git-compat-util.h"
2 #include "compat/terminal.h"
3 #include "sigchain.h"
4 #include "strbuf.h"
5
6 #ifdef HAVE_DEV_TTY
7
8 static int term_fd = -1;
9 static struct termios old_term;
10
11 static void restore_term(void)
12 {
13         if (term_fd < 0)
14                 return;
15
16         tcsetattr(term_fd, TCSAFLUSH, &old_term);
17         term_fd = -1;
18 }
19
20 static void restore_term_on_signal(int sig)
21 {
22         restore_term();
23         sigchain_pop(sig);
24         raise(sig);
25 }
26
27 char *git_terminal_prompt(const char *prompt, int echo)
28 {
29         static struct strbuf buf = STRBUF_INIT;
30         int r;
31         FILE *fh;
32
33         fh = fopen("/dev/tty", "w+");
34         if (!fh)
35                 return NULL;
36
37         if (!echo) {
38                 struct termios t;
39
40                 if (tcgetattr(fileno(fh), &t) < 0) {
41                         fclose(fh);
42                         return NULL;
43                 }
44
45                 old_term = t;
46                 term_fd = fileno(fh);
47                 sigchain_push_common(restore_term_on_signal);
48
49                 t.c_lflag &= ~ECHO;
50                 if (tcsetattr(fileno(fh), TCSAFLUSH, &t) < 0) {
51                         term_fd = -1;
52                         fclose(fh);
53                         return NULL;
54                 }
55         }
56
57         fputs(prompt, fh);
58         fflush(fh);
59
60         r = strbuf_getline(&buf, fh, '\n');
61         if (!echo) {
62                 putc('\n', fh);
63                 fflush(fh);
64         }
65
66         restore_term();
67         fclose(fh);
68
69         if (r == EOF)
70                 return NULL;
71         return buf.buf;
72 }
73
74 #else
75
76 char *git_terminal_prompt(const char *prompt, int echo)
77 {
78         return getpass(prompt);
79 }
80
81 #endif