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