readline.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. /*
  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. */
  24. #include "qemu/osdep.h"
  25. #include "qemu/readline.h"
  26. #include "qemu/ctype.h"
  27. #include "qemu/cutils.h"
  28. #define IS_NORM 0
  29. #define IS_ESC 1
  30. #define IS_CSI 2
  31. #define IS_SS3 3
  32. void readline_show_prompt(ReadLineState *rs)
  33. {
  34. rs->printf_func(rs->opaque, "%s", rs->prompt);
  35. rs->flush_func(rs->opaque);
  36. rs->last_cmd_buf_index = 0;
  37. rs->last_cmd_buf_size = 0;
  38. rs->esc_state = IS_NORM;
  39. }
  40. /* update the displayed command line */
  41. static void readline_update(ReadLineState *rs)
  42. {
  43. int i, delta, len;
  44. if (rs->cmd_buf_size != rs->last_cmd_buf_size ||
  45. memcmp(rs->cmd_buf, rs->last_cmd_buf, rs->cmd_buf_size) != 0) {
  46. for (i = 0; i < rs->last_cmd_buf_index; i++) {
  47. rs->printf_func(rs->opaque, "\033[D");
  48. }
  49. rs->cmd_buf[rs->cmd_buf_size] = '\0';
  50. if (rs->read_password) {
  51. len = strlen(rs->cmd_buf);
  52. for (i = 0; i < len; i++) {
  53. rs->printf_func(rs->opaque, "*");
  54. }
  55. } else {
  56. rs->printf_func(rs->opaque, "%s", rs->cmd_buf);
  57. }
  58. rs->printf_func(rs->opaque, "\033[K");
  59. memcpy(rs->last_cmd_buf, rs->cmd_buf, rs->cmd_buf_size);
  60. rs->last_cmd_buf_size = rs->cmd_buf_size;
  61. rs->last_cmd_buf_index = rs->cmd_buf_size;
  62. }
  63. if (rs->cmd_buf_index != rs->last_cmd_buf_index) {
  64. delta = rs->cmd_buf_index - rs->last_cmd_buf_index;
  65. if (delta > 0) {
  66. for (i = 0; i < delta; i++) {
  67. rs->printf_func(rs->opaque, "\033[C");
  68. }
  69. } else {
  70. delta = -delta;
  71. for (i = 0; i < delta; i++) {
  72. rs->printf_func(rs->opaque, "\033[D");
  73. }
  74. }
  75. rs->last_cmd_buf_index = rs->cmd_buf_index;
  76. }
  77. rs->flush_func(rs->opaque);
  78. }
  79. static void readline_insert_char(ReadLineState *rs, int ch)
  80. {
  81. if (rs->cmd_buf_index < READLINE_CMD_BUF_SIZE) {
  82. memmove(rs->cmd_buf + rs->cmd_buf_index + 1,
  83. rs->cmd_buf + rs->cmd_buf_index,
  84. rs->cmd_buf_size - rs->cmd_buf_index);
  85. rs->cmd_buf[rs->cmd_buf_index] = ch;
  86. rs->cmd_buf_size++;
  87. rs->cmd_buf_index++;
  88. }
  89. }
  90. static void readline_backward_char(ReadLineState *rs)
  91. {
  92. if (rs->cmd_buf_index > 0) {
  93. rs->cmd_buf_index--;
  94. }
  95. }
  96. static void readline_forward_char(ReadLineState *rs)
  97. {
  98. if (rs->cmd_buf_index < rs->cmd_buf_size) {
  99. rs->cmd_buf_index++;
  100. }
  101. }
  102. static void readline_delete_char(ReadLineState *rs)
  103. {
  104. if (rs->cmd_buf_index < rs->cmd_buf_size) {
  105. memmove(rs->cmd_buf + rs->cmd_buf_index,
  106. rs->cmd_buf + rs->cmd_buf_index + 1,
  107. rs->cmd_buf_size - rs->cmd_buf_index - 1);
  108. rs->cmd_buf_size--;
  109. }
  110. }
  111. static void readline_backspace(ReadLineState *rs)
  112. {
  113. if (rs->cmd_buf_index > 0) {
  114. readline_backward_char(rs);
  115. readline_delete_char(rs);
  116. }
  117. }
  118. static void readline_backword(ReadLineState *rs)
  119. {
  120. int start;
  121. if (rs->cmd_buf_index == 0 || rs->cmd_buf_index > rs->cmd_buf_size) {
  122. return;
  123. }
  124. start = rs->cmd_buf_index - 1;
  125. /* find first word (backwards) */
  126. while (start > 0) {
  127. if (!qemu_isspace(rs->cmd_buf[start])) {
  128. break;
  129. }
  130. --start;
  131. }
  132. /* find first space (backwards) */
  133. while (start > 0) {
  134. if (qemu_isspace(rs->cmd_buf[start])) {
  135. ++start;
  136. break;
  137. }
  138. --start;
  139. }
  140. /* remove word */
  141. if (start < rs->cmd_buf_index) {
  142. memmove(rs->cmd_buf + start,
  143. rs->cmd_buf + rs->cmd_buf_index,
  144. rs->cmd_buf_size - rs->cmd_buf_index);
  145. rs->cmd_buf_size -= rs->cmd_buf_index - start;
  146. rs->cmd_buf_index = start;
  147. }
  148. }
  149. static void readline_bol(ReadLineState *rs)
  150. {
  151. rs->cmd_buf_index = 0;
  152. }
  153. static void readline_eol(ReadLineState *rs)
  154. {
  155. rs->cmd_buf_index = rs->cmd_buf_size;
  156. }
  157. static void readline_up_char(ReadLineState *rs)
  158. {
  159. int idx;
  160. if (rs->hist_entry == 0) {
  161. return;
  162. }
  163. if (rs->hist_entry == -1) {
  164. /* Find latest entry */
  165. for (idx = 0; idx < READLINE_MAX_CMDS; idx++) {
  166. if (rs->history[idx] == NULL) {
  167. break;
  168. }
  169. }
  170. rs->hist_entry = idx;
  171. }
  172. rs->hist_entry--;
  173. if (rs->hist_entry >= 0) {
  174. pstrcpy(rs->cmd_buf, sizeof(rs->cmd_buf),
  175. rs->history[rs->hist_entry]);
  176. rs->cmd_buf_index = rs->cmd_buf_size = strlen(rs->cmd_buf);
  177. }
  178. }
  179. static void readline_down_char(ReadLineState *rs)
  180. {
  181. if (rs->hist_entry == -1) {
  182. return;
  183. }
  184. if (rs->hist_entry < READLINE_MAX_CMDS - 1 &&
  185. rs->history[++rs->hist_entry] != NULL) {
  186. pstrcpy(rs->cmd_buf, sizeof(rs->cmd_buf),
  187. rs->history[rs->hist_entry]);
  188. } else {
  189. rs->cmd_buf[0] = 0;
  190. rs->hist_entry = -1;
  191. }
  192. rs->cmd_buf_index = rs->cmd_buf_size = strlen(rs->cmd_buf);
  193. }
  194. static void readline_hist_add(ReadLineState *rs, const char *cmdline)
  195. {
  196. char *hist_entry, *new_entry;
  197. int idx;
  198. if (cmdline[0] == '\0') {
  199. return;
  200. }
  201. new_entry = NULL;
  202. if (rs->hist_entry != -1) {
  203. /* We were editing an existing history entry: replace it */
  204. hist_entry = rs->history[rs->hist_entry];
  205. idx = rs->hist_entry;
  206. if (strcmp(hist_entry, cmdline) == 0) {
  207. goto same_entry;
  208. }
  209. }
  210. /* Search cmdline in history buffers */
  211. for (idx = 0; idx < READLINE_MAX_CMDS; idx++) {
  212. hist_entry = rs->history[idx];
  213. if (hist_entry == NULL) {
  214. break;
  215. }
  216. if (strcmp(hist_entry, cmdline) == 0) {
  217. same_entry:
  218. if (idx == READLINE_MAX_CMDS - 1) {
  219. return;
  220. }
  221. new_entry = hist_entry;
  222. /* Put this entry at the end of history */
  223. memmove(&rs->history[idx], &rs->history[idx + 1],
  224. (READLINE_MAX_CMDS - (idx + 1)) * sizeof(char *));
  225. rs->history[READLINE_MAX_CMDS - 1] = NULL;
  226. for (; idx < READLINE_MAX_CMDS; idx++) {
  227. if (rs->history[idx] == NULL) {
  228. break;
  229. }
  230. }
  231. break;
  232. }
  233. }
  234. if (idx == READLINE_MAX_CMDS) {
  235. /* Need to get one free slot */
  236. g_free(rs->history[0]);
  237. memmove(rs->history, &rs->history[1],
  238. (READLINE_MAX_CMDS - 1) * sizeof(char *));
  239. rs->history[READLINE_MAX_CMDS - 1] = NULL;
  240. idx = READLINE_MAX_CMDS - 1;
  241. }
  242. if (new_entry == NULL) {
  243. new_entry = g_strdup(cmdline);
  244. }
  245. rs->history[idx] = new_entry;
  246. rs->hist_entry = -1;
  247. }
  248. static void readline_kill_line(ReadLineState *rs)
  249. {
  250. while (rs->cmd_buf_index > 0) {
  251. readline_backward_char(rs);
  252. readline_delete_char(rs);
  253. }
  254. }
  255. /* completion support */
  256. void readline_add_completion(ReadLineState *rs, const char *str)
  257. {
  258. if (rs->nb_completions < READLINE_MAX_COMPLETIONS) {
  259. int i;
  260. for (i = 0; i < rs->nb_completions; i++) {
  261. if (!strcmp(rs->completions[i], str)) {
  262. return;
  263. }
  264. }
  265. rs->completions[rs->nb_completions++] = g_strdup(str);
  266. }
  267. }
  268. void readline_add_completion_of(ReadLineState *rs,
  269. const char *pfx, const char *str)
  270. {
  271. if (!strncmp(str, pfx, strlen(pfx))) {
  272. readline_add_completion(rs, str);
  273. }
  274. }
  275. void readline_set_completion_index(ReadLineState *rs, int index)
  276. {
  277. rs->completion_index = index;
  278. }
  279. static int completion_comp(const void *a, const void *b)
  280. {
  281. return strcmp(*(const char **) a, *(const char **) b);
  282. }
  283. static void readline_completion(ReadLineState *rs)
  284. {
  285. int len, i, j, max_width, nb_cols, max_prefix;
  286. char *cmdline;
  287. rs->nb_completions = 0;
  288. cmdline = g_strndup(rs->cmd_buf, rs->cmd_buf_index);
  289. rs->completion_finder(rs->opaque, cmdline);
  290. g_free(cmdline);
  291. /* no completion found */
  292. if (rs->nb_completions <= 0) {
  293. return;
  294. }
  295. if (rs->nb_completions == 1) {
  296. len = strlen(rs->completions[0]);
  297. for (i = rs->completion_index; i < len; i++) {
  298. readline_insert_char(rs, rs->completions[0][i]);
  299. }
  300. /* extra space for next argument. XXX: make it more generic */
  301. if (len > 0 && rs->completions[0][len - 1] != '/') {
  302. readline_insert_char(rs, ' ');
  303. }
  304. } else {
  305. qsort(rs->completions, rs->nb_completions, sizeof(char *),
  306. completion_comp);
  307. rs->printf_func(rs->opaque, "\n");
  308. max_width = 0;
  309. max_prefix = 0;
  310. for (i = 0; i < rs->nb_completions; i++) {
  311. len = strlen(rs->completions[i]);
  312. if (i == 0) {
  313. max_prefix = len;
  314. } else {
  315. if (len < max_prefix) {
  316. max_prefix = len;
  317. }
  318. for (j = 0; j < max_prefix; j++) {
  319. if (rs->completions[i][j] != rs->completions[0][j]) {
  320. max_prefix = j;
  321. }
  322. }
  323. }
  324. if (len > max_width) {
  325. max_width = len;
  326. }
  327. }
  328. if (max_prefix > 0)
  329. for (i = rs->completion_index; i < max_prefix; i++) {
  330. readline_insert_char(rs, rs->completions[0][i]);
  331. }
  332. max_width += 2;
  333. if (max_width < 10) {
  334. max_width = 10;
  335. } else if (max_width > 80) {
  336. max_width = 80;
  337. }
  338. nb_cols = 80 / max_width;
  339. j = 0;
  340. for (i = 0; i < rs->nb_completions; i++) {
  341. rs->printf_func(rs->opaque, "%-*s", max_width, rs->completions[i]);
  342. if (++j == nb_cols || i == (rs->nb_completions - 1)) {
  343. rs->printf_func(rs->opaque, "\n");
  344. j = 0;
  345. }
  346. }
  347. readline_show_prompt(rs);
  348. }
  349. for (i = 0; i < rs->nb_completions; i++) {
  350. g_free(rs->completions[i]);
  351. }
  352. }
  353. static void readline_clear_screen(ReadLineState *rs)
  354. {
  355. rs->printf_func(rs->opaque, "\033[2J\033[1;1H");
  356. readline_show_prompt(rs);
  357. }
  358. /* return true if command handled */
  359. void readline_handle_byte(ReadLineState *rs, int ch)
  360. {
  361. switch (rs->esc_state) {
  362. case IS_NORM:
  363. switch (ch) {
  364. case 1:
  365. readline_bol(rs);
  366. break;
  367. case 4:
  368. readline_delete_char(rs);
  369. break;
  370. case 5:
  371. readline_eol(rs);
  372. break;
  373. case 9:
  374. readline_completion(rs);
  375. break;
  376. case 12:
  377. readline_clear_screen(rs);
  378. break;
  379. case 10: /* fallthrough */
  380. case 13:
  381. rs->cmd_buf[rs->cmd_buf_size] = '\0';
  382. if (!rs->read_password) {
  383. readline_hist_add(rs, rs->cmd_buf);
  384. }
  385. rs->printf_func(rs->opaque, "\n");
  386. rs->cmd_buf_index = 0;
  387. rs->cmd_buf_size = 0;
  388. rs->last_cmd_buf_index = 0;
  389. rs->last_cmd_buf_size = 0;
  390. rs->readline_func(rs->opaque, rs->cmd_buf, rs->readline_opaque);
  391. break;
  392. case 14:
  393. /* ^N Next line in history */
  394. readline_down_char(rs);
  395. break;
  396. case 16:
  397. /* ^P Prev line in history */
  398. readline_up_char(rs);
  399. break;
  400. case 21:
  401. /* ^U Kill backward from point to the beginning of the line. */
  402. readline_kill_line(rs);
  403. break;
  404. case 23:
  405. /* ^W */
  406. readline_backword(rs);
  407. break;
  408. case 27:
  409. rs->esc_state = IS_ESC;
  410. break;
  411. case 127: /* fallthrough */
  412. case 8:
  413. readline_backspace(rs);
  414. break;
  415. case 155:
  416. rs->esc_state = IS_CSI;
  417. break;
  418. default:
  419. if (ch >= 32) {
  420. readline_insert_char(rs, ch);
  421. }
  422. break;
  423. }
  424. break;
  425. case IS_ESC:
  426. if (ch == '[') {
  427. rs->esc_state = IS_CSI;
  428. rs->esc_param = 0;
  429. } else if (ch == 'O') {
  430. rs->esc_state = IS_SS3;
  431. rs->esc_param = 0;
  432. } else {
  433. rs->esc_state = IS_NORM;
  434. }
  435. break;
  436. case IS_CSI:
  437. switch (ch) {
  438. case 'A': /* fallthrough */
  439. case 'F':
  440. readline_up_char(rs);
  441. break;
  442. case 'B': /* fallthrough */
  443. case 'E':
  444. readline_down_char(rs);
  445. break;
  446. case 'D':
  447. readline_backward_char(rs);
  448. break;
  449. case 'C':
  450. readline_forward_char(rs);
  451. break;
  452. case '0' ... '9':
  453. rs->esc_param = rs->esc_param * 10 + (ch - '0');
  454. goto the_end;
  455. case '~':
  456. switch (rs->esc_param) {
  457. case 1:
  458. readline_bol(rs);
  459. break;
  460. case 3:
  461. readline_delete_char(rs);
  462. break;
  463. case 4:
  464. readline_eol(rs);
  465. break;
  466. default:
  467. break;
  468. }
  469. break;
  470. default:
  471. break;
  472. }
  473. rs->esc_state = IS_NORM;
  474. /* fallthrough */
  475. the_end:
  476. break;
  477. case IS_SS3:
  478. switch (ch) {
  479. case 'F':
  480. readline_eol(rs);
  481. break;
  482. case 'H':
  483. readline_bol(rs);
  484. break;
  485. default:
  486. break;
  487. }
  488. rs->esc_state = IS_NORM;
  489. break;
  490. default:
  491. break;
  492. }
  493. readline_update(rs);
  494. }
  495. void readline_start(ReadLineState *rs, const char *prompt, int read_password,
  496. ReadLineFunc *readline_func, void *opaque)
  497. {
  498. pstrcpy(rs->prompt, sizeof(rs->prompt), prompt);
  499. rs->readline_func = readline_func;
  500. rs->readline_opaque = opaque;
  501. rs->read_password = read_password;
  502. readline_restart(rs);
  503. }
  504. void readline_restart(ReadLineState *rs)
  505. {
  506. rs->cmd_buf_index = 0;
  507. rs->cmd_buf_size = 0;
  508. }
  509. const char *readline_get_history(ReadLineState *rs, unsigned int index)
  510. {
  511. if (index >= READLINE_MAX_CMDS) {
  512. return NULL;
  513. }
  514. return rs->history[index];
  515. }
  516. void readline_free(ReadLineState *rs)
  517. {
  518. int i;
  519. if (!rs) {
  520. return;
  521. }
  522. for (i = 0; i < READLINE_MAX_CMDS; i++) {
  523. g_free(rs->history[i]);
  524. }
  525. g_free(rs);
  526. }
  527. ReadLineState *readline_init(ReadLinePrintfFunc *printf_func,
  528. ReadLineFlushFunc *flush_func,
  529. void *opaque,
  530. ReadLineCompletionFunc *completion_finder)
  531. {
  532. ReadLineState *rs = g_new0(ReadLineState, 1);
  533. rs->hist_entry = -1;
  534. rs->opaque = opaque;
  535. rs->printf_func = printf_func;
  536. rs->flush_func = flush_func;
  537. rs->completion_finder = completion_finder;
  538. return rs;
  539. }