]> git.ipfire.org Git - thirdparty/bird.git/blob - client/birdc.c
Restructures birdc and birdcl to merge duplicated code.
[thirdparty/bird.git] / client / birdc.c
1 /*
2 * BIRD Client - Readline variant I/O
3 *
4 * (c) 1999--2004 Martin Mares <mj@ucw.cz>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <termios.h>
13
14 #include <readline/readline.h>
15 #include <readline/history.h>
16 #include <curses.h>
17
18 #include "nest/bird.h"
19 #include "lib/resource.h"
20 #include "lib/string.h"
21 #include "client/client.h"
22 #include "sysdep/unix/unix.h"
23
24 static int input_hidden_end;
25 static int prompt_active;
26
27 /*** Input ***/
28
29 /* HACK: libreadline internals we need to access */
30 extern int _rl_vis_botlin;
31 extern void _rl_move_vert(int);
32 extern Function *rl_last_func;
33
34 static void
35 add_history_dedup(char *cmd)
36 {
37 /* Add history line if it differs from the last one */
38 HIST_ENTRY *he = history_get(history_length);
39 if (!he || strcmp(he->line, cmd))
40 add_history(cmd);
41 }
42
43 static void
44 input_got_line(char *cmd_buffer)
45 {
46 if (!cmd_buffer)
47 {
48 cleanup();
49 exit(0);
50 }
51
52 if (cmd_buffer[0])
53 {
54 add_history_dedup(cmd_buffer);
55 submit_command(cmd_buffer);
56 }
57
58 free(cmd_buffer);
59 }
60
61 void
62 input_start_list(void)
63 {
64 /* Leave the currently edited line and make space for listing */
65 _rl_move_vert(_rl_vis_botlin);
66 #ifdef HAVE_RL_CRLF
67 rl_crlf();
68 #endif
69 }
70
71 void
72 input_stop_list(void)
73 {
74 /* Reprint the currently edited line after listing */
75 rl_on_new_line();
76 rl_redisplay();
77 }
78
79 static int
80 input_complete(int arg UNUSED, int key UNUSED)
81 {
82 static int complete_flag;
83 char buf[256];
84
85 if (rl_last_func != input_complete)
86 complete_flag = 0;
87 switch (cmd_complete(rl_line_buffer, rl_point, buf, complete_flag))
88 {
89 case 0:
90 complete_flag = 1;
91 break;
92 case 1:
93 rl_insert_text(buf);
94 break;
95 default:
96 complete_flag = 1;
97 #ifdef HAVE_RL_DING
98 rl_ding();
99 #endif
100 }
101 return 0;
102 }
103
104 static int
105 input_help(int arg, int key UNUSED)
106 {
107 int i, in_string, in_bracket;
108
109 if (arg != 1)
110 return rl_insert(arg, '?');
111
112 in_string = in_bracket = 0;
113 for (i = 0; i < rl_point; i++)
114 {
115
116 if (rl_line_buffer[i] == '"')
117 in_string = ! in_string;
118 else if (! in_string)
119 {
120 if (rl_line_buffer[i] == '[')
121 in_bracket++;
122 else if (rl_line_buffer[i] == ']')
123 in_bracket--;
124 }
125 }
126
127 /* `?' inside string or path -> insert */
128 if (in_string || in_bracket)
129 return rl_insert(1, '?');
130
131 rl_begin_undo_group(); /* HACK: We want to display `?' at point position */
132 rl_insert_text("?");
133 rl_redisplay();
134 rl_end_undo_group();
135 input_start_list();
136 cmd_help(rl_line_buffer, rl_point);
137 rl_undo_command(1, 0);
138 input_stop_list();
139 return 0;
140 }
141
142 void
143 input_init(void)
144 {
145 rl_readline_name = "birdc";
146 rl_add_defun("bird-complete", input_complete, '\t');
147 rl_add_defun("bird-help", input_help, '?');
148 rl_callback_handler_install("bird> ", input_got_line);
149
150 // rl_get_screen_size();
151 term_lns = LINES ? LINES : 25;
152 term_cls = COLS ? COLS : 80;
153
154 prompt_active = 1;
155
156 // readline library does strange things when stdin is nonblocking.
157 // if (fcntl(0, F_SETFL, O_NONBLOCK) < 0)
158 // die("fcntl: %m");
159 }
160
161 static void
162 input_reveal(void)
163 {
164 /* need this, otherwise some lib seems to eat pending output when
165 the prompt is displayed */
166 fflush(stdout);
167 tcdrain(STDOUT_FILENO);
168
169 rl_end = input_hidden_end;
170 rl_expand_prompt("bird> ");
171 rl_forced_update_display();
172
173 prompt_active = 1;
174 }
175
176 static void
177 input_hide(void)
178 {
179 input_hidden_end = rl_end;
180 rl_end = 0;
181 rl_expand_prompt("");
182 rl_redisplay();
183
184 prompt_active = 0;
185 }
186
187 void
188 input_notify(int prompt)
189 {
190 if (prompt == prompt_active)
191 return;
192
193 if (prompt)
194 input_reveal();
195 else
196 input_hide();
197 }
198
199 void
200 input_read(void)
201 {
202 rl_callback_read_char();
203 }
204
205 void
206 more_begin(void)
207 {
208 }
209
210 void
211 more_end(void)
212 {
213 }
214
215 void
216 cleanup(void)
217 {
218 if (init)
219 return;
220
221 input_hide();
222 rl_callback_handler_remove();
223 }