complete: zsh: use zsh completion for the main cmd
[git/debian.git] / compat / terminal.c
blob9b5e3d1bb8fe0adafb78721c09caff5b165dbf40
1 #include "git-compat-util.h"
2 #include "compat/terminal.h"
3 #include "sigchain.h"
4 #include "strbuf.h"
6 #if defined(HAVE_DEV_TTY) || defined(WIN32)
8 static void restore_term(void);
10 static void restore_term_on_signal(int sig)
12 restore_term();
13 sigchain_pop(sig);
14 raise(sig);
17 #ifdef HAVE_DEV_TTY
19 #define INPUT_PATH "/dev/tty"
20 #define OUTPUT_PATH "/dev/tty"
22 static int term_fd = -1;
23 static struct termios old_term;
25 static void restore_term(void)
27 if (term_fd < 0)
28 return;
30 tcsetattr(term_fd, TCSAFLUSH, &old_term);
31 close(term_fd);
32 term_fd = -1;
35 static int disable_echo(void)
37 struct termios t;
39 term_fd = open("/dev/tty", O_RDWR);
40 if (tcgetattr(term_fd, &t) < 0)
41 goto error;
43 old_term = t;
44 sigchain_push_common(restore_term_on_signal);
46 t.c_lflag &= ~ECHO;
47 if (!tcsetattr(term_fd, TCSAFLUSH, &t))
48 return 0;
50 error:
51 close(term_fd);
52 term_fd = -1;
53 return -1;
56 #elif defined(WIN32)
58 #define INPUT_PATH "CONIN$"
59 #define OUTPUT_PATH "CONOUT$"
60 #define FORCE_TEXT "t"
62 static HANDLE hconin = INVALID_HANDLE_VALUE;
63 static DWORD cmode;
65 static void restore_term(void)
67 if (hconin == INVALID_HANDLE_VALUE)
68 return;
70 SetConsoleMode(hconin, cmode);
71 CloseHandle(hconin);
72 hconin = INVALID_HANDLE_VALUE;
75 static int disable_echo(void)
77 hconin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
78 FILE_SHARE_READ, NULL, OPEN_EXISTING,
79 FILE_ATTRIBUTE_NORMAL, NULL);
80 if (hconin == INVALID_HANDLE_VALUE)
81 return -1;
83 GetConsoleMode(hconin, &cmode);
84 sigchain_push_common(restore_term_on_signal);
85 if (!SetConsoleMode(hconin, cmode & (~ENABLE_ECHO_INPUT))) {
86 CloseHandle(hconin);
87 hconin = INVALID_HANDLE_VALUE;
88 return -1;
91 return 0;
94 #endif
96 #ifndef FORCE_TEXT
97 #define FORCE_TEXT
98 #endif
100 char *git_terminal_prompt(const char *prompt, int echo)
102 static struct strbuf buf = STRBUF_INIT;
103 int r;
104 FILE *input_fh, *output_fh;
106 input_fh = fopen(INPUT_PATH, "r" FORCE_TEXT);
107 if (!input_fh)
108 return NULL;
110 output_fh = fopen(OUTPUT_PATH, "w" FORCE_TEXT);
111 if (!output_fh) {
112 fclose(input_fh);
113 return NULL;
116 if (!echo && disable_echo()) {
117 fclose(input_fh);
118 fclose(output_fh);
119 return NULL;
122 fputs(prompt, output_fh);
123 fflush(output_fh);
125 r = strbuf_getline(&buf, input_fh, '\n');
126 if (!echo) {
127 putc('\n', output_fh);
128 fflush(output_fh);
131 restore_term();
132 fclose(input_fh);
133 fclose(output_fh);
135 if (r == EOF)
136 return NULL;
137 return buf.buf;
140 #else
142 char *git_terminal_prompt(const char *prompt, int echo)
144 return getpass(prompt);
147 #endif