blob: 16ec70407ac94d1529a98b218f9b2b51ba32fdef [file] [log] [blame]
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001/*
2 * QEMU readline utility
3 *
4 * Copyright (c) 2003-2004 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070024#include "readline.h"
25#include "monitor.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080026
27#define IS_NORM 0
28#define IS_ESC 1
29#define IS_CSI 2
30
David 'Digit' Turner92518662010-05-10 23:26:01 -070031#undef printf
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080032#define printf do_not_use_printf
33
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070034void readline_show_prompt(ReadLineState *rs)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080035{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070036 monitor_printf(rs->mon, "%s", rs->prompt);
37 monitor_flush(rs->mon);
38 rs->last_cmd_buf_index = 0;
39 rs->last_cmd_buf_size = 0;
40 rs->esc_state = IS_NORM;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080041}
42
43/* update the displayed command line */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070044static void readline_update(ReadLineState *rs)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080045{
46 int i, delta, len;
47
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070048 if (rs->cmd_buf_size != rs->last_cmd_buf_size ||
49 memcmp(rs->cmd_buf, rs->last_cmd_buf, rs->cmd_buf_size) != 0) {
50 for(i = 0; i < rs->last_cmd_buf_index; i++) {
51 monitor_printf(rs->mon, "\033[D");
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080052 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070053 rs->cmd_buf[rs->cmd_buf_size] = '\0';
54 if (rs->read_password) {
55 len = strlen(rs->cmd_buf);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080056 for(i = 0; i < len; i++)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070057 monitor_printf(rs->mon, "*");
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080058 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070059 monitor_printf(rs->mon, "%s", rs->cmd_buf);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080060 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070061 monitor_printf(rs->mon, "\033[K");
62 memcpy(rs->last_cmd_buf, rs->cmd_buf, rs->cmd_buf_size);
63 rs->last_cmd_buf_size = rs->cmd_buf_size;
64 rs->last_cmd_buf_index = rs->cmd_buf_size;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080065 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070066 if (rs->cmd_buf_index != rs->last_cmd_buf_index) {
67 delta = rs->cmd_buf_index - rs->last_cmd_buf_index;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080068 if (delta > 0) {
69 for(i = 0;i < delta; i++) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070070 monitor_printf(rs->mon, "\033[C");
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080071 }
72 } else {
73 delta = -delta;
74 for(i = 0;i < delta; i++) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070075 monitor_printf(rs->mon, "\033[D");
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080076 }
77 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070078 rs->last_cmd_buf_index = rs->cmd_buf_index;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080079 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070080 monitor_flush(rs->mon);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080081}
82
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070083static void readline_insert_char(ReadLineState *rs, int ch)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080084{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070085 if (rs->cmd_buf_index < READLINE_CMD_BUF_SIZE) {
86 memmove(rs->cmd_buf + rs->cmd_buf_index + 1,
87 rs->cmd_buf + rs->cmd_buf_index,
88 rs->cmd_buf_size - rs->cmd_buf_index);
89 rs->cmd_buf[rs->cmd_buf_index] = ch;
90 rs->cmd_buf_size++;
91 rs->cmd_buf_index++;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080092 }
93}
94
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070095static void readline_backward_char(ReadLineState *rs)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080096{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070097 if (rs->cmd_buf_index > 0) {
98 rs->cmd_buf_index--;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080099 }
100}
101
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700102static void readline_forward_char(ReadLineState *rs)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800103{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700104 if (rs->cmd_buf_index < rs->cmd_buf_size) {
105 rs->cmd_buf_index++;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800106 }
107}
108
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700109static void readline_delete_char(ReadLineState *rs)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800110{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700111 if (rs->cmd_buf_index < rs->cmd_buf_size) {
112 memmove(rs->cmd_buf + rs->cmd_buf_index,
113 rs->cmd_buf + rs->cmd_buf_index + 1,
114 rs->cmd_buf_size - rs->cmd_buf_index - 1);
115 rs->cmd_buf_size--;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800116 }
117}
118
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700119static void readline_backspace(ReadLineState *rs)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800120{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700121 if (rs->cmd_buf_index > 0) {
122 readline_backward_char(rs);
123 readline_delete_char(rs);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800124 }
125}
126
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700127static void readline_backword(ReadLineState *rs)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800128{
129 int start;
130
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700131 if (rs->cmd_buf_index == 0 || rs->cmd_buf_index > rs->cmd_buf_size) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800132 return;
133 }
134
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700135 start = rs->cmd_buf_index - 1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800136
137 /* find first word (backwards) */
138 while (start > 0) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700139 if (!qemu_isspace(rs->cmd_buf[start])) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800140 break;
141 }
142
143 --start;
144 }
145
146 /* find first space (backwards) */
147 while (start > 0) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700148 if (qemu_isspace(rs->cmd_buf[start])) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800149 ++start;
150 break;
151 }
152
153 --start;
154 }
155
156 /* remove word */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700157 if (start < rs->cmd_buf_index) {
158 memmove(rs->cmd_buf + start,
159 rs->cmd_buf + rs->cmd_buf_index,
160 rs->cmd_buf_size - rs->cmd_buf_index);
161 rs->cmd_buf_size -= rs->cmd_buf_index - start;
162 rs->cmd_buf_index = start;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800163 }
164}
165
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700166static void readline_bol(ReadLineState *rs)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800167{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700168 rs->cmd_buf_index = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800169}
170
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700171static void readline_eol(ReadLineState *rs)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800172{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700173 rs->cmd_buf_index = rs->cmd_buf_size;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800174}
175
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700176static void readline_up_char(ReadLineState *rs)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800177{
178 int idx;
179
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700180 if (rs->hist_entry == 0)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800181 return;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700182 if (rs->hist_entry == -1) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800183 /* Find latest entry */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700184 for (idx = 0; idx < READLINE_MAX_CMDS; idx++) {
185 if (rs->history[idx] == NULL)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800186 break;
187 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700188 rs->hist_entry = idx;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800189 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700190 rs->hist_entry--;
191 if (rs->hist_entry >= 0) {
192 pstrcpy(rs->cmd_buf, sizeof(rs->cmd_buf),
193 rs->history[rs->hist_entry]);
194 rs->cmd_buf_index = rs->cmd_buf_size = strlen(rs->cmd_buf);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800195 }
196}
197
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700198static void readline_down_char(ReadLineState *rs)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800199{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700200 if (rs->hist_entry == -1)
201 return;
202 if (rs->hist_entry < READLINE_MAX_CMDS - 1 &&
203 rs->history[++rs->hist_entry] != NULL) {
204 pstrcpy(rs->cmd_buf, sizeof(rs->cmd_buf),
205 rs->history[rs->hist_entry]);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800206 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700207 rs->cmd_buf[0] = 0;
208 rs->hist_entry = -1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800209 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700210 rs->cmd_buf_index = rs->cmd_buf_size = strlen(rs->cmd_buf);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800211}
212
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700213static void readline_hist_add(ReadLineState *rs, const char *cmdline)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800214{
215 char *hist_entry, *new_entry;
216 int idx;
217
218 if (cmdline[0] == '\0')
219 return;
220 new_entry = NULL;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700221 if (rs->hist_entry != -1) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800222 /* We were editing an existing history entry: replace it */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700223 hist_entry = rs->history[rs->hist_entry];
224 idx = rs->hist_entry;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800225 if (strcmp(hist_entry, cmdline) == 0) {
226 goto same_entry;
227 }
228 }
229 /* Search cmdline in history buffers */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700230 for (idx = 0; idx < READLINE_MAX_CMDS; idx++) {
231 hist_entry = rs->history[idx];
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800232 if (hist_entry == NULL)
233 break;
234 if (strcmp(hist_entry, cmdline) == 0) {
235 same_entry:
236 new_entry = hist_entry;
237 /* Put this entry at the end of history */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700238 memmove(&rs->history[idx], &rs->history[idx + 1],
239 (READLINE_MAX_CMDS - idx + 1) * sizeof(char *));
240 rs->history[READLINE_MAX_CMDS - 1] = NULL;
241 for (; idx < READLINE_MAX_CMDS; idx++) {
242 if (rs->history[idx] == NULL)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800243 break;
244 }
245 break;
246 }
247 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700248 if (idx == READLINE_MAX_CMDS) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800249 /* Need to get one free slot */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700250 free(rs->history[0]);
251 memcpy(rs->history, &rs->history[1],
252 (READLINE_MAX_CMDS - 1) * sizeof(char *));
253 rs->history[READLINE_MAX_CMDS - 1] = NULL;
254 idx = READLINE_MAX_CMDS - 1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800255 }
256 if (new_entry == NULL)
257 new_entry = strdup(cmdline);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700258 rs->history[idx] = new_entry;
259 rs->hist_entry = -1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800260}
261
262/* completion support */
263
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700264void readline_add_completion(ReadLineState *rs, const char *str)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800265{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700266 if (rs->nb_completions < READLINE_MAX_COMPLETIONS) {
267 rs->completions[rs->nb_completions++] = qemu_strdup(str);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800268 }
269}
270
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700271void readline_set_completion_index(ReadLineState *rs, int index)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800272{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700273 rs->completion_index = index;
274}
275
276static void readline_completion(ReadLineState *rs)
277{
278 Monitor *mon = cur_mon;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800279 int len, i, j, max_width, nb_cols, max_prefix;
280 char *cmdline;
281
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700282 rs->nb_completions = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800283
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700284 cmdline = qemu_malloc(rs->cmd_buf_index + 1);
285 memcpy(cmdline, rs->cmd_buf, rs->cmd_buf_index);
286 cmdline[rs->cmd_buf_index] = '\0';
287 rs->completion_finder(cmdline);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800288 qemu_free(cmdline);
289
290 /* no completion found */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700291 if (rs->nb_completions <= 0)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800292 return;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700293 if (rs->nb_completions == 1) {
294 len = strlen(rs->completions[0]);
295 for(i = rs->completion_index; i < len; i++) {
296 readline_insert_char(rs, rs->completions[0][i]);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800297 }
298 /* extra space for next argument. XXX: make it more generic */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700299 if (len > 0 && rs->completions[0][len - 1] != '/')
300 readline_insert_char(rs, ' ');
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800301 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700302 monitor_printf(mon, "\n");
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800303 max_width = 0;
304 max_prefix = 0;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700305 for(i = 0; i < rs->nb_completions; i++) {
306 len = strlen(rs->completions[i]);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800307 if (i==0) {
308 max_prefix = len;
309 } else {
310 if (len < max_prefix)
311 max_prefix = len;
312 for(j=0; j<max_prefix; j++) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700313 if (rs->completions[i][j] != rs->completions[0][j])
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800314 max_prefix = j;
315 }
316 }
317 if (len > max_width)
318 max_width = len;
319 }
320 if (max_prefix > 0)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700321 for(i = rs->completion_index; i < max_prefix; i++) {
322 readline_insert_char(rs, rs->completions[0][i]);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800323 }
324 max_width += 2;
325 if (max_width < 10)
326 max_width = 10;
327 else if (max_width > 80)
328 max_width = 80;
329 nb_cols = 80 / max_width;
330 j = 0;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700331 for(i = 0; i < rs->nb_completions; i++) {
332 monitor_printf(rs->mon, "%-*s", max_width, rs->completions[i]);
333 if (++j == nb_cols || i == (rs->nb_completions - 1)) {
334 monitor_printf(rs->mon, "\n");
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800335 j = 0;
336 }
337 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700338 readline_show_prompt(rs);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800339 }
340}
341
342/* return true if command handled */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700343void readline_handle_byte(ReadLineState *rs, int ch)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800344{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700345 switch(rs->esc_state) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800346 case IS_NORM:
347 switch(ch) {
348 case 1:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700349 readline_bol(rs);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800350 break;
351 case 4:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700352 readline_delete_char(rs);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800353 break;
354 case 5:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700355 readline_eol(rs);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800356 break;
357 case 9:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700358 readline_completion(rs);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800359 break;
360 case 10:
361 case 13:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700362 rs->cmd_buf[rs->cmd_buf_size] = '\0';
363 if (!rs->read_password)
364 readline_hist_add(rs, rs->cmd_buf);
365 monitor_printf(rs->mon, "\n");
366 rs->cmd_buf_index = 0;
367 rs->cmd_buf_size = 0;
368 rs->last_cmd_buf_index = 0;
369 rs->last_cmd_buf_size = 0;
370 rs->readline_func(rs->mon, rs->cmd_buf, rs->readline_opaque);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800371 break;
372 case 23:
373 /* ^W */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700374 readline_backword(rs);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800375 break;
376 case 27:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700377 rs->esc_state = IS_ESC;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800378 break;
379 case 127:
380 case 8:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700381 readline_backspace(rs);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800382 break;
383 case 155:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700384 rs->esc_state = IS_CSI;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800385 break;
386 default:
387 if (ch >= 32) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700388 readline_insert_char(rs, ch);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800389 }
390 break;
391 }
392 break;
393 case IS_ESC:
394 if (ch == '[') {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700395 rs->esc_state = IS_CSI;
396 rs->esc_param = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800397 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700398 rs->esc_state = IS_NORM;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800399 }
400 break;
401 case IS_CSI:
402 switch(ch) {
403 case 'A':
404 case 'F':
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700405 readline_up_char(rs);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800406 break;
407 case 'B':
408 case 'E':
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700409 readline_down_char(rs);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800410 break;
411 case 'D':
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700412 readline_backward_char(rs);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800413 break;
414 case 'C':
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700415 readline_forward_char(rs);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800416 break;
417 case '0' ... '9':
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700418 rs->esc_param = rs->esc_param * 10 + (ch - '0');
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800419 goto the_end;
420 case '~':
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700421 switch(rs->esc_param) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800422 case 1:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700423 readline_bol(rs);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800424 break;
425 case 3:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700426 readline_delete_char(rs);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800427 break;
428 case 4:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700429 readline_eol(rs);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800430 break;
431 }
432 break;
433 default:
434 break;
435 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700436 rs->esc_state = IS_NORM;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800437 the_end:
438 break;
439 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700440 readline_update(rs);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800441}
442
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700443void readline_start(ReadLineState *rs, const char *prompt, int read_password,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800444 ReadLineFunc *readline_func, void *opaque)
445{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700446 pstrcpy(rs->prompt, sizeof(rs->prompt), prompt);
447 rs->readline_func = readline_func;
448 rs->readline_opaque = opaque;
449 rs->read_password = read_password;
450 readline_restart(rs);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800451}
452
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700453void readline_restart(ReadLineState *rs)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800454{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700455 rs->cmd_buf_index = 0;
456 rs->cmd_buf_size = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800457}
458
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700459const char *readline_get_history(ReadLineState *rs, unsigned int index)
460{
461 if (index >= READLINE_MAX_CMDS)
462 return NULL;
463 return rs->history[index];
464}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800465
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700466ReadLineState *readline_init(Monitor *mon,
467 ReadLineCompletionFunc *completion_finder)
468{
469 ReadLineState *rs = qemu_mallocz(sizeof(*rs));
470
471 rs->hist_entry = -1;
472 rs->mon = mon;
473 rs->completion_finder = completion_finder;
474
475 return rs;
476}
David 'Digit' Turnere92bc562010-09-07 06:21:25 -0700477
478void readline_free(ReadLineState *rs)
479{
480 if (rs) {
481 rs->mon = NULL;
482 rs->completion_finder = NULL;
483 qemu_free(rs);
484 }
485}