Commit aa455485c97afa6096a97b54b3bfdf784e5ea9fd
1 parent
9307c4c1
history support (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@704 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
123 additions
and
0 deletions
monitor.c
... | ... | @@ -31,6 +31,7 @@ |
31 | 31 | #endif |
32 | 32 | |
33 | 33 | #define TERM_CMD_BUF_SIZE 4095 |
34 | +#define TERM_MAX_CMDS 64 | |
34 | 35 | |
35 | 36 | #define IS_NORM 0 |
36 | 37 | #define IS_ESC 1 |
... | ... | @@ -44,6 +45,9 @@ static int term_cmd_buf_size; |
44 | 45 | static int term_esc_state; |
45 | 46 | static int term_esc_param; |
46 | 47 | |
48 | +static char *term_history[TERM_MAX_CMDS]; | |
49 | +static int term_hist_entry; | |
50 | + | |
47 | 51 | /* |
48 | 52 | * Supported types: |
49 | 53 | * |
... | ... | @@ -190,6 +194,17 @@ static void do_info_registers(void) |
190 | 194 | #endif |
191 | 195 | } |
192 | 196 | |
197 | +static void do_info_history (void) | |
198 | +{ | |
199 | + int i; | |
200 | + | |
201 | + for (i = 0; i < TERM_MAX_CMDS; i++) { | |
202 | + if (term_history[i] == NULL) | |
203 | + break; | |
204 | + term_printf("%d: '%s'\n", i, term_history[i]); | |
205 | + } | |
206 | +} | |
207 | + | |
193 | 208 | static void do_quit(void) |
194 | 209 | { |
195 | 210 | exit(0); |
... | ... | @@ -499,6 +514,8 @@ static term_cmd_t info_cmds[] = { |
499 | 514 | "", "show the block devices" }, |
500 | 515 | { "registers", "", do_info_registers, |
501 | 516 | "", "show the cpu registers" }, |
517 | + { "history", "", do_info_history, | |
518 | + "", "show the command line history", }, | |
502 | 519 | { NULL, NULL, }, |
503 | 520 | }; |
504 | 521 | |
... | ... | @@ -1056,6 +1073,13 @@ static void term_show_prompt(void) |
1056 | 1073 | term_esc_state = IS_NORM; |
1057 | 1074 | } |
1058 | 1075 | |
1076 | +static void term_print_cmdline (const char *cmdline) | |
1077 | +{ | |
1078 | + term_show_prompt(); | |
1079 | + term_printf(cmdline); | |
1080 | + term_flush(); | |
1081 | +} | |
1082 | + | |
1059 | 1083 | static void term_insert_char(int ch) |
1060 | 1084 | { |
1061 | 1085 | if (term_cmd_buf_index < TERM_CMD_BUF_SIZE) { |
... | ... | @@ -1120,6 +1144,92 @@ static void term_eol(void) |
1120 | 1144 | term_forward_char(); |
1121 | 1145 | } |
1122 | 1146 | |
1147 | +static void term_up_char(void) | |
1148 | +{ | |
1149 | + int idx; | |
1150 | + | |
1151 | + if (term_hist_entry == 0) | |
1152 | + return; | |
1153 | + if (term_hist_entry == -1) { | |
1154 | + /* Find latest entry */ | |
1155 | + for (idx = 0; idx < TERM_MAX_CMDS; idx++) { | |
1156 | + if (term_history[idx] == NULL) | |
1157 | + break; | |
1158 | + } | |
1159 | + term_hist_entry = idx; | |
1160 | + } | |
1161 | + term_hist_entry--; | |
1162 | + if (term_hist_entry >= 0) { | |
1163 | + strcpy(term_cmd_buf, term_history[term_hist_entry]); | |
1164 | + term_printf("\n"); | |
1165 | + term_print_cmdline(term_cmd_buf); | |
1166 | + term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf); | |
1167 | + } | |
1168 | +} | |
1169 | + | |
1170 | +static void term_down_char(void) | |
1171 | +{ | |
1172 | + if (term_hist_entry == TERM_MAX_CMDS - 1 || term_hist_entry == -1) | |
1173 | + return; | |
1174 | + if (term_history[++term_hist_entry] != NULL) { | |
1175 | + strcpy(term_cmd_buf, term_history[term_hist_entry]); | |
1176 | + } else { | |
1177 | + term_hist_entry = -1; | |
1178 | + } | |
1179 | + term_printf("\n"); | |
1180 | + term_print_cmdline(term_cmd_buf); | |
1181 | + term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf); | |
1182 | +} | |
1183 | + | |
1184 | +static void term_hist_add(const char *cmdline) | |
1185 | +{ | |
1186 | + char *hist_entry, *new_entry; | |
1187 | + int idx; | |
1188 | + | |
1189 | + if (cmdline[0] == '\0') | |
1190 | + return; | |
1191 | + new_entry = NULL; | |
1192 | + if (term_hist_entry != -1) { | |
1193 | + /* We were editing an existing history entry: replace it */ | |
1194 | + hist_entry = term_history[term_hist_entry]; | |
1195 | + idx = term_hist_entry; | |
1196 | + if (strcmp(hist_entry, cmdline) == 0) { | |
1197 | + goto same_entry; | |
1198 | + } | |
1199 | + } | |
1200 | + /* Search cmdline in history buffers */ | |
1201 | + for (idx = 0; idx < TERM_MAX_CMDS; idx++) { | |
1202 | + hist_entry = term_history[idx]; | |
1203 | + if (hist_entry == NULL) | |
1204 | + break; | |
1205 | + if (strcmp(hist_entry, cmdline) == 0) { | |
1206 | + same_entry: | |
1207 | + new_entry = hist_entry; | |
1208 | + /* Put this entry at the end of history */ | |
1209 | + memmove(&term_history[idx], &term_history[idx + 1], | |
1210 | + &term_history[TERM_MAX_CMDS] - &term_history[idx + 1]); | |
1211 | + term_history[TERM_MAX_CMDS - 1] = NULL; | |
1212 | + for (; idx < TERM_MAX_CMDS; idx++) { | |
1213 | + if (term_history[idx] == NULL) | |
1214 | + break; | |
1215 | + } | |
1216 | + break; | |
1217 | + } | |
1218 | + } | |
1219 | + if (idx == TERM_MAX_CMDS) { | |
1220 | + /* Need to get one free slot */ | |
1221 | + free(term_history[0]); | |
1222 | + memcpy(term_history, &term_history[1], | |
1223 | + &term_history[TERM_MAX_CMDS] - &term_history[1]); | |
1224 | + term_history[TERM_MAX_CMDS - 1] = NULL; | |
1225 | + idx = TERM_MAX_CMDS - 1; | |
1226 | + } | |
1227 | + if (new_entry == NULL) | |
1228 | + new_entry = strdup(cmdline); | |
1229 | + term_history[idx] = new_entry; | |
1230 | + term_hist_entry = -1; | |
1231 | +} | |
1232 | + | |
1123 | 1233 | /* return true if command handled */ |
1124 | 1234 | static void term_handle_byte(int ch) |
1125 | 1235 | { |
... | ... | @@ -1135,6 +1245,7 @@ static void term_handle_byte(int ch) |
1135 | 1245 | case 10: |
1136 | 1246 | case 13: |
1137 | 1247 | term_cmd_buf[term_cmd_buf_size] = '\0'; |
1248 | + term_hist_add(term_cmd_buf); | |
1138 | 1249 | term_printf("\n"); |
1139 | 1250 | term_handle_command(term_cmd_buf); |
1140 | 1251 | term_show_prompt(); |
... | ... | @@ -1146,6 +1257,9 @@ static void term_handle_byte(int ch) |
1146 | 1257 | case 8: |
1147 | 1258 | term_backspace(); |
1148 | 1259 | break; |
1260 | + case 155: | |
1261 | + term_esc_state = IS_CSI; | |
1262 | + break; | |
1149 | 1263 | default: |
1150 | 1264 | if (ch >= 32) { |
1151 | 1265 | term_insert_char(ch); |
... | ... | @@ -1163,6 +1277,14 @@ static void term_handle_byte(int ch) |
1163 | 1277 | break; |
1164 | 1278 | case IS_CSI: |
1165 | 1279 | switch(ch) { |
1280 | + case 'A': | |
1281 | + case 'F': | |
1282 | + term_up_char(); | |
1283 | + break; | |
1284 | + case 'B': | |
1285 | + case 'E': | |
1286 | + term_down_char(); | |
1287 | + break; | |
1166 | 1288 | case 'D': |
1167 | 1289 | term_backward_char(); |
1168 | 1290 | break; |
... | ... | @@ -1290,5 +1412,6 @@ void monitor_init(void) |
1290 | 1412 | QEMU_VERSION); |
1291 | 1413 | term_show_prompt(); |
1292 | 1414 | } |
1415 | + term_hist_entry = -1; | |
1293 | 1416 | qemu_add_fd_read_handler(0, term_can_read, term_read, NULL); |
1294 | 1417 | } | ... | ... |