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