shell.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254
  1. /*
  2. * Copyright (c) 2015-2018 Richard Braun.
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. *
  17. * Upstream site with license notes :
  18. * http://git.sceen.net/rbraun/librbraun.git/
  19. */
  20. #include <assert.h>
  21. #include <errno.h>
  22. #include <stdarg.h>
  23. #include <stddef.h>
  24. #include <stdio.h>
  25. #include <stdint.h>
  26. #include <string.h>
  27. #include <kern/bulletin.h>
  28. #include <kern/hash.h>
  29. #include <kern/init.h>
  30. #include <kern/log.h>
  31. #include <kern/macros.h>
  32. #include <kern/mutex.h>
  33. #include <kern/printf.h>
  34. #include <kern/shell.h>
  35. #include <kern/shell_i.h>
  36. #include <kern/thread.h>
  37. #define SHELL_COMPLETION_MATCH_FMT "-16s"
  38. #define SHELL_COMPLETION_NR_MATCHES_PER_LINE 4
  39. /*
  40. * Escape sequence states.
  41. *
  42. * Here is an incomplete description of escape sequences :
  43. * http://en.wikipedia.org/wiki/ANSI_escape_code
  44. *
  45. * These values must be different from 0.
  46. */
  47. #define SHELL_ESC_STATE_START 1
  48. #define SHELL_ESC_STATE_CSI 2
  49. typedef void (*shell_esc_seq_fn)(struct shell *shell);
  50. struct shell_esc_seq {
  51. const char *str;
  52. shell_esc_seq_fn fn;
  53. };
  54. #define SHELL_SEPARATOR ' '
  55. /*
  56. * Commonly used backspace control characters.
  57. *
  58. * XXX Adjust for your needs.
  59. */
  60. #define SHELL_ERASE_BS '\b'
  61. #define SHELL_ERASE_DEL '\x7f'
  62. static struct bulletin_sub shell_log_bulletin_sub;
  63. static const char *
  64. shell_find_word(const char *str)
  65. {
  66. for (;;) {
  67. if ((*str == '\0') || (*str != SHELL_SEPARATOR)) {
  68. break;
  69. }
  70. str++;
  71. }
  72. return str;
  73. }
  74. void
  75. shell_cmd_init(struct shell_cmd *cmd, const char *name,
  76. shell_fn_t fn, const char *usage,
  77. const char *short_desc, const char *long_desc)
  78. {
  79. cmd->ht_next = NULL;
  80. cmd->ls_next = NULL;
  81. cmd->name = name;
  82. cmd->fn = fn;
  83. cmd->usage = usage;
  84. cmd->short_desc = short_desc;
  85. cmd->long_desc = long_desc;
  86. }
  87. static const char *
  88. shell_cmd_name(const struct shell_cmd *cmd)
  89. {
  90. return cmd->name;
  91. }
  92. static int
  93. shell_cmd_check_char(char c)
  94. {
  95. if (((c >= 'a') && (c <= 'z'))
  96. || ((c >= 'A') && (c <= 'Z'))
  97. || ((c >= '0') && (c <= '9'))
  98. || (c == '-')
  99. || (c == '_')) {
  100. return 0;
  101. }
  102. return EINVAL;
  103. }
  104. static int
  105. shell_cmd_check(const struct shell_cmd *cmd)
  106. {
  107. size_t len;
  108. int error;
  109. len = strlen(cmd->name);
  110. if (len == 0) {
  111. return EINVAL;
  112. }
  113. for (size_t i = 0; i < len; i++) {
  114. error = shell_cmd_check_char(cmd->name[i]);
  115. if (error) {
  116. return error;
  117. }
  118. }
  119. return 0;
  120. }
  121. static const char *
  122. shell_line_str(const struct shell_line *line)
  123. {
  124. return line->str;
  125. }
  126. static size_t
  127. shell_line_size(const struct shell_line *line)
  128. {
  129. return line->size;
  130. }
  131. static void
  132. shell_line_reset(struct shell_line *line)
  133. {
  134. line->str[0] = '\0';
  135. line->size = 0;
  136. }
  137. static void
  138. shell_line_copy(struct shell_line *dest, const struct shell_line *src)
  139. {
  140. strcpy(dest->str, src->str);
  141. dest->size = src->size;
  142. }
  143. static int
  144. shell_line_cmp(const struct shell_line *a, const struct shell_line *b)
  145. {
  146. return strcmp(a->str, b->str);
  147. }
  148. static int
  149. shell_line_insert(struct shell_line *line, size_t index, char c)
  150. {
  151. size_t remaining_chars;
  152. if (index > line->size) {
  153. return EINVAL;
  154. }
  155. if ((line->size + 1) == sizeof(line->str)) {
  156. return ENOMEM;
  157. }
  158. remaining_chars = line->size - index;
  159. if (remaining_chars != 0) {
  160. memmove(&line->str[index + 1], &line->str[index], remaining_chars);
  161. }
  162. line->str[index] = c;
  163. line->size++;
  164. line->str[line->size] = '\0';
  165. return 0;
  166. }
  167. static int
  168. shell_line_erase(struct shell_line *line, size_t index)
  169. {
  170. size_t remaining_chars;
  171. if (index >= line->size) {
  172. return EINVAL;
  173. }
  174. remaining_chars = line->size - index - 1;
  175. if (remaining_chars != 0) {
  176. memmove(&line->str[index], &line->str[index + 1], remaining_chars);
  177. }
  178. line->size--;
  179. line->str[line->size] = '\0';
  180. return 0;
  181. }
  182. static struct shell_line *
  183. shell_history_get(struct shell_history *history, size_t index)
  184. {
  185. return &history->lines[index % ARRAY_SIZE(history->lines)];
  186. }
  187. static void
  188. shell_history_init(struct shell_history *history)
  189. {
  190. for (size_t i = 0; i < ARRAY_SIZE(history->lines); i++) {
  191. shell_line_reset(shell_history_get(history, i));
  192. }
  193. history->newest = 0;
  194. history->oldest = 0;
  195. history->index = 0;
  196. }
  197. static struct shell_line *
  198. shell_history_get_newest(struct shell_history *history)
  199. {
  200. return shell_history_get(history, history->newest);
  201. }
  202. static struct shell_line *
  203. shell_history_get_index(struct shell_history *history)
  204. {
  205. return shell_history_get(history, history->index);
  206. }
  207. static void
  208. shell_history_reset_index(struct shell_history *history)
  209. {
  210. history->index = history->newest;
  211. }
  212. static int
  213. shell_history_same_newest(struct shell_history *history)
  214. {
  215. return (history->newest != history->oldest)
  216. && (shell_line_cmp(shell_history_get_newest(history),
  217. shell_history_get(history, history->newest - 1))
  218. == 0);
  219. }
  220. static void
  221. shell_history_push(struct shell_history *history)
  222. {
  223. if ((shell_line_size(shell_history_get_newest(history)) == 0)
  224. || shell_history_same_newest(history)) {
  225. shell_history_reset_index(history);
  226. return;
  227. }
  228. history->newest++;
  229. shell_history_reset_index(history);
  230. /* Mind integer overflows */
  231. if ((history->newest - history->oldest) >= ARRAY_SIZE(history->lines)) {
  232. history->oldest = history->newest - ARRAY_SIZE(history->lines) + 1;
  233. }
  234. }
  235. static void
  236. shell_history_back(struct shell_history *history)
  237. {
  238. if (history->index == history->oldest) {
  239. return;
  240. }
  241. history->index--;
  242. shell_line_copy(shell_history_get_newest(history),
  243. shell_history_get_index(history));
  244. }
  245. static void
  246. shell_history_forward(struct shell_history *history)
  247. {
  248. if (history->index == history->newest) {
  249. return;
  250. }
  251. history->index++;
  252. if (history->index == history->newest) {
  253. shell_line_reset(shell_history_get_newest(history));
  254. } else {
  255. shell_line_copy(shell_history_get_newest(history),
  256. shell_history_get_index(history));
  257. }
  258. }
  259. static void
  260. shell_history_print(struct shell_history *history, struct shell *shell)
  261. {
  262. const struct shell_line *line;
  263. /* Mind integer overflows */
  264. for (size_t i = history->oldest; i != history->newest; i++) {
  265. line = shell_history_get(history, i);
  266. shell_printf(shell, "%6lu %s\n",
  267. (unsigned long)(i - history->oldest),
  268. shell_line_str(line));
  269. }
  270. }
  271. static void
  272. shell_cmd_set_lock(struct shell_cmd_set *cmd_set)
  273. {
  274. mutex_lock(&cmd_set->lock);
  275. }
  276. static void
  277. shell_cmd_set_unlock(struct shell_cmd_set *cmd_set)
  278. {
  279. mutex_unlock(&cmd_set->lock);
  280. }
  281. static struct shell_bucket *
  282. shell_cmd_set_get_bucket(struct shell_cmd_set *cmd_set, const char *name)
  283. {
  284. size_t index;
  285. index = hash_str(name, SHELL_HTABLE_BITS);
  286. assert(index < ARRAY_SIZE(cmd_set->htable));
  287. return &cmd_set->htable[index];
  288. }
  289. static const struct shell_cmd *
  290. shell_cmd_set_lookup(struct shell_cmd_set *cmd_set, const char *name)
  291. {
  292. const struct shell_bucket *bucket;
  293. const struct shell_cmd *cmd;
  294. shell_cmd_set_lock(cmd_set);
  295. bucket = shell_cmd_set_get_bucket(cmd_set, name);
  296. for (cmd = bucket->cmd; cmd != NULL; cmd = cmd->ht_next) {
  297. if (strcmp(cmd->name, name) == 0) {
  298. break;
  299. }
  300. }
  301. shell_cmd_set_unlock(cmd_set);
  302. return cmd;
  303. }
  304. /*
  305. * Look up the first command that matches a given string.
  306. *
  307. * The input string is defined by the given string pointer and size.
  308. *
  309. * The global lock must be acquired before calling this function.
  310. */
  311. static const struct shell_cmd *
  312. shell_cmd_set_match(const struct shell_cmd_set *cmd_set, const char *str,
  313. size_t size)
  314. {
  315. const struct shell_cmd *cmd;
  316. cmd = cmd_set->cmd_list;
  317. while (cmd != NULL) {
  318. if (strncmp(cmd->name, str, size) == 0) {
  319. return cmd;
  320. }
  321. cmd = cmd->ls_next;
  322. }
  323. return NULL;
  324. }
  325. /*
  326. * Attempt command auto-completion.
  327. *
  328. * The given string is the beginning of a command, or the empty string.
  329. * The sizep parameter initially points to the size of the given string.
  330. * If the string matches any registered command, the cmdp pointer is
  331. * updated to point to the first matching command in the sorted list of
  332. * commands, and sizep is updated to the number of characters in the
  333. * command name that are common in subsequent commands. The command
  334. * pointer and the returned size can be used to print a list of commands
  335. * eligible for completion.
  336. *
  337. * If there is a single match for the given string, return 0. If there
  338. * are more than one match, return EAGAIN. If there is no match,
  339. * return EINVAL.
  340. */
  341. static int
  342. shell_cmd_set_complete(struct shell_cmd_set *cmd_set, const char *str,
  343. size_t *sizep, const struct shell_cmd **cmdp)
  344. {
  345. const struct shell_cmd *cmd, *next;
  346. size_t size;
  347. size = *sizep;
  348. /*
  349. * Start with looking up a command that matches the given argument.
  350. * If there is no match, return an error.
  351. */
  352. cmd = shell_cmd_set_match(cmd_set, str, size);
  353. if (cmd == NULL) {
  354. return EINVAL;
  355. }
  356. *cmdp = cmd;
  357. /*
  358. * If at least one command matches, try to complete it.
  359. * There can be two cases :
  360. * 1/ There is one and only one match, which is directly returned.
  361. * 2/ There are several matches, in which case the common length is
  362. * computed.
  363. */
  364. next = cmd->ls_next;
  365. if ((next == NULL) || (strncmp(cmd->name, next->name, size) != 0)) {
  366. *sizep = strlen(cmd->name);
  367. return 0;
  368. }
  369. /*
  370. * When computing the common length, all the commands that can match
  371. * must be evaluated. Considering the current command is the first
  372. * that can match, the only other variable missing is the last
  373. * command that can match.
  374. */
  375. while (next->ls_next != NULL) {
  376. if (strncmp(cmd->name, next->ls_next->name, size) != 0) {
  377. break;
  378. }
  379. next = next->ls_next;
  380. }
  381. if (size == 0) {
  382. size = 1;
  383. }
  384. while ((cmd->name[size - 1] != '\0')
  385. && (cmd->name[size - 1] == next->name[size - 1])) {
  386. size++;
  387. }
  388. size--;
  389. *sizep = size;
  390. return EAGAIN;
  391. }
  392. struct shell_cmd_set *
  393. shell_get_cmd_set(struct shell *shell)
  394. {
  395. return shell->cmd_set;
  396. }
  397. static struct shell_history *
  398. shell_get_history(struct shell *shell)
  399. {
  400. return &shell->history;
  401. }
  402. static void
  403. shell_cb_help(struct shell *shell, int argc, char *argv[])
  404. {
  405. struct shell_cmd_set *cmd_set;
  406. const struct shell_cmd *cmd;
  407. cmd_set = shell_get_cmd_set(shell);
  408. if (argc > 2) {
  409. argc = 2;
  410. argv[1] = "help";
  411. }
  412. if (argc == 2) {
  413. cmd = shell_cmd_set_lookup(cmd_set, argv[1]);
  414. if (cmd == NULL) {
  415. shell_printf(shell, "shell: help: %s: command not found\n",
  416. argv[1]);
  417. return;
  418. }
  419. shell_printf(shell, "usage: %s\n%s\n", cmd->usage, cmd->short_desc);
  420. if (cmd->long_desc != NULL) {
  421. shell_printf(shell, "\n%s\n", cmd->long_desc);
  422. }
  423. return;
  424. }
  425. shell_cmd_set_lock(cmd_set);
  426. for (cmd = cmd_set->cmd_list; cmd != NULL; cmd = cmd->ls_next) {
  427. shell_printf(shell, "%19s %s\n", cmd->name, cmd->short_desc);
  428. }
  429. shell_cmd_set_unlock(cmd_set);
  430. }
  431. static void
  432. shell_cb_history(struct shell *shell, int argc, char *argv[])
  433. {
  434. (void)argc;
  435. (void)argv;
  436. shell_history_print(shell_get_history(shell), shell);
  437. }
  438. static struct shell_cmd shell_default_cmds[] = {
  439. SHELL_CMD_INITIALIZER("help", shell_cb_help,
  440. "help [command]",
  441. "obtain help about shell commands"),
  442. SHELL_CMD_INITIALIZER("history", shell_cb_history,
  443. "history",
  444. "display history list"),
  445. };
  446. void
  447. shell_cmd_set_init(struct shell_cmd_set *cmd_set)
  448. {
  449. mutex_init(&cmd_set->lock);
  450. memset(cmd_set->htable, 0, sizeof(cmd_set->htable));
  451. cmd_set->cmd_list = NULL;
  452. SHELL_REGISTER_CMDS(shell_default_cmds, cmd_set);
  453. }
  454. static int
  455. shell_cmd_set_add_htable(struct shell_cmd_set *cmd_set, struct shell_cmd *cmd)
  456. {
  457. struct shell_bucket *bucket;
  458. struct shell_cmd *tmp;
  459. bucket = shell_cmd_set_get_bucket(cmd_set, cmd->name);
  460. tmp = bucket->cmd;
  461. if (tmp == NULL) {
  462. bucket->cmd = cmd;
  463. return 0;
  464. }
  465. for (;;) {
  466. if (strcmp(cmd->name, tmp->name) == 0) {
  467. return EEXIST;
  468. }
  469. if (tmp->ht_next == NULL) {
  470. break;
  471. }
  472. tmp = tmp->ht_next;
  473. }
  474. tmp->ht_next = cmd;
  475. return 0;
  476. }
  477. static void
  478. shell_cmd_set_add_list(struct shell_cmd_set *cmd_set, struct shell_cmd *cmd)
  479. {
  480. struct shell_cmd *prev, *next;
  481. prev = cmd_set->cmd_list;
  482. if ((prev == NULL) || (strcmp(cmd->name, prev->name) < 0)) {
  483. cmd_set->cmd_list = cmd;
  484. cmd->ls_next = prev;
  485. return;
  486. }
  487. for (;;) {
  488. next = prev->ls_next;
  489. if ((next == NULL) || (strcmp(cmd->name, next->name) < 0)) {
  490. break;
  491. }
  492. prev = next;
  493. }
  494. prev->ls_next = cmd;
  495. cmd->ls_next = next;
  496. }
  497. static int
  498. shell_cmd_set_add(struct shell_cmd_set *cmd_set, struct shell_cmd *cmd)
  499. {
  500. int error;
  501. error = shell_cmd_set_add_htable(cmd_set, cmd);
  502. if (error) {
  503. return error;
  504. }
  505. shell_cmd_set_add_list(cmd_set, cmd);
  506. return 0;
  507. }
  508. int
  509. shell_cmd_set_register(struct shell_cmd_set *cmd_set, struct shell_cmd *cmd)
  510. {
  511. int error;
  512. error = shell_cmd_check(cmd);
  513. if (error) {
  514. return error;
  515. }
  516. shell_cmd_set_lock(cmd_set);
  517. error = shell_cmd_set_add(cmd_set, cmd);
  518. shell_cmd_set_unlock(cmd_set);
  519. return error;
  520. }
  521. void
  522. shell_init(struct shell *shell, struct shell_cmd_set *cmd_set,
  523. shell_getc_fn_t getc_fn, shell_vfprintf_fn_t vfprintf_fn,
  524. void *io_object)
  525. {
  526. shell->cmd_set = cmd_set;
  527. shell->getc_fn = getc_fn;
  528. shell->vfprintf_fn = vfprintf_fn;
  529. shell->io_object = io_object;
  530. shell_history_init(&shell->history);
  531. shell->esc_seq_index = 0;
  532. }
  533. static void
  534. shell_prompt(struct shell *shell)
  535. {
  536. shell_printf(shell, "shell> ");
  537. }
  538. static void
  539. shell_reset(struct shell *shell)
  540. {
  541. shell_line_reset(shell_history_get_newest(&shell->history));
  542. shell->cursor = 0;
  543. shell_prompt(shell);
  544. }
  545. static void
  546. shell_erase(struct shell *shell)
  547. {
  548. struct shell_line *current_line;
  549. size_t remaining_chars;
  550. current_line = shell_history_get_newest(&shell->history);
  551. remaining_chars = shell_line_size(current_line);
  552. while (shell->cursor != remaining_chars) {
  553. shell_printf(shell, " ");
  554. shell->cursor++;
  555. }
  556. while (remaining_chars != 0) {
  557. shell_printf(shell, "\b \b");
  558. remaining_chars--;
  559. }
  560. shell->cursor = 0;
  561. }
  562. static void
  563. shell_restore(struct shell *shell)
  564. {
  565. struct shell_line *current_line;
  566. current_line = shell_history_get_newest(&shell->history);
  567. shell_printf(shell, "%s", shell_line_str(current_line));
  568. shell->cursor = shell_line_size(current_line);
  569. }
  570. static int
  571. shell_is_ctrl_char(char c)
  572. {
  573. return ((c < ' ') || (c >= 0x7f));
  574. }
  575. static void
  576. shell_process_left(struct shell *shell)
  577. {
  578. if (shell->cursor == 0) {
  579. return;
  580. }
  581. shell->cursor--;
  582. shell_printf(shell, "\e[1D");
  583. }
  584. static int
  585. shell_process_right(struct shell *shell)
  586. {
  587. size_t size;
  588. size = shell_line_size(shell_history_get_newest(&shell->history));
  589. if (shell->cursor >= size) {
  590. return EAGAIN;
  591. }
  592. shell->cursor++;
  593. shell_printf(shell, "\e[1C");
  594. return 0;
  595. }
  596. static void
  597. shell_process_up(struct shell *shell)
  598. {
  599. shell_erase(shell);
  600. shell_history_back(&shell->history);
  601. shell_restore(shell);
  602. }
  603. static void
  604. shell_process_down(struct shell *shell)
  605. {
  606. shell_erase(shell);
  607. shell_history_forward(&shell->history);
  608. shell_restore(shell);
  609. }
  610. static void
  611. shell_process_backspace(struct shell *shell)
  612. {
  613. struct shell_line *current_line;
  614. size_t remaining_chars;
  615. int error;
  616. current_line = shell_history_get_newest(&shell->history);
  617. error = shell_line_erase(current_line, shell->cursor - 1);
  618. if (error) {
  619. return;
  620. }
  621. shell->cursor--;
  622. shell_printf(shell, "\b%s ", shell_line_str(current_line) + shell->cursor);
  623. remaining_chars = shell_line_size(current_line) - shell->cursor + 1;
  624. while (remaining_chars != 0) {
  625. shell_printf(shell, "\b");
  626. remaining_chars--;
  627. }
  628. }
  629. static int
  630. shell_process_raw_char(struct shell *shell, char c)
  631. {
  632. struct shell_line *current_line;
  633. size_t remaining_chars;
  634. int error;
  635. current_line = shell_history_get_newest(&shell->history);
  636. error = shell_line_insert(current_line, shell->cursor, c);
  637. if (error) {
  638. shell_printf(shell, "\nshell: line too long\n");
  639. return error;
  640. }
  641. shell->cursor++;
  642. if (shell->cursor == shell_line_size(current_line)) {
  643. shell_printf(shell, "%c", c);
  644. goto out;
  645. }
  646. /*
  647. * This assumes that the backspace character only moves the cursor
  648. * without erasing characters.
  649. */
  650. shell_printf(shell, "%s", shell_line_str(current_line) + shell->cursor - 1);
  651. remaining_chars = shell_line_size(current_line) - shell->cursor;
  652. while (remaining_chars != 0) {
  653. shell_printf(shell, "\b");
  654. remaining_chars--;
  655. }
  656. out:
  657. return 0;
  658. }
  659. /*
  660. * Print a list of commands eligible for completion, starting at the
  661. * given command. Other eligible commands share the same prefix, as
  662. * defined by the size argument.
  663. *
  664. * The global lock must be acquired before calling this function.
  665. */
  666. static void
  667. shell_print_cmd_matches(struct shell *shell, const struct shell_cmd *cmd,
  668. unsigned long size)
  669. {
  670. const struct shell_cmd *tmp;
  671. unsigned int i;
  672. shell_printf(shell, "\n");
  673. for (tmp = cmd, i = 1; tmp != NULL; tmp = tmp->ls_next, i++) {
  674. if (strncmp(cmd->name, tmp->name, size) != 0) {
  675. break;
  676. }
  677. shell_printf(shell, "%" SHELL_COMPLETION_MATCH_FMT, tmp->name);
  678. if ((i % SHELL_COMPLETION_NR_MATCHES_PER_LINE) == 0) {
  679. shell_printf(shell, "\n");
  680. }
  681. }
  682. if ((i % SHELL_COMPLETION_NR_MATCHES_PER_LINE) != 1) {
  683. shell_printf(shell, "\n");
  684. }
  685. }
  686. static int
  687. shell_process_tabulation(struct shell *shell)
  688. {
  689. struct shell_cmd_set *cmd_set;
  690. const struct shell_cmd *cmd = NULL; /* GCC */
  691. const char *name, *str, *word;
  692. size_t size, cmd_cursor;
  693. int error;
  694. cmd_set = shell->cmd_set;
  695. shell_cmd_set_lock(cmd_set);
  696. str = shell_line_str(shell_history_get_newest(&shell->history));
  697. word = shell_find_word(str);
  698. size = shell->cursor - (word - str);
  699. cmd_cursor = shell->cursor - size;
  700. error = shell_cmd_set_complete(cmd_set, word, &size, &cmd);
  701. if (error && (error != EAGAIN)) {
  702. error = 0;
  703. goto out;
  704. }
  705. if (error == EAGAIN) {
  706. size_t cursor;
  707. cursor = shell->cursor;
  708. shell_print_cmd_matches(shell, cmd, size);
  709. shell_prompt(shell);
  710. shell_restore(shell);
  711. /* Keep existing arguments as they are */
  712. while (shell->cursor != cursor) {
  713. shell_process_left(shell);
  714. }
  715. }
  716. name = shell_cmd_name(cmd);
  717. while (shell->cursor != cmd_cursor) {
  718. shell_process_backspace(shell);
  719. }
  720. for (size_t i = 0; i < size; i++) {
  721. error = shell_process_raw_char(shell, name[i]);
  722. if (error) {
  723. goto out;
  724. }
  725. }
  726. error = 0;
  727. out:
  728. shell_cmd_set_unlock(cmd_set);
  729. return error;
  730. }
  731. static void
  732. shell_esc_seq_up(struct shell *shell)
  733. {
  734. shell_process_up(shell);
  735. }
  736. static void
  737. shell_esc_seq_down(struct shell *shell)
  738. {
  739. shell_process_down(shell);
  740. }
  741. static void
  742. shell_esc_seq_next(struct shell *shell)
  743. {
  744. shell_process_right(shell);
  745. }
  746. static void
  747. shell_esc_seq_prev(struct shell *shell)
  748. {
  749. shell_process_left(shell);
  750. }
  751. static void
  752. shell_esc_seq_home(struct shell *shell)
  753. {
  754. while (shell->cursor != 0) {
  755. shell_process_left(shell);
  756. }
  757. }
  758. static void
  759. shell_esc_seq_del(struct shell *shell)
  760. {
  761. int error;
  762. error = shell_process_right(shell);
  763. if (error) {
  764. return;
  765. }
  766. shell_process_backspace(shell);
  767. }
  768. static void
  769. shell_esc_seq_end(struct shell *shell)
  770. {
  771. size_t size;
  772. size = shell_line_size(shell_history_get_newest(&shell->history));
  773. while (shell->cursor < size) {
  774. shell_process_right(shell);
  775. }
  776. }
  777. static const struct shell_esc_seq shell_esc_seqs[] = {
  778. { "A", shell_esc_seq_up },
  779. { "B", shell_esc_seq_down },
  780. { "C", shell_esc_seq_next },
  781. { "D", shell_esc_seq_prev },
  782. { "H", shell_esc_seq_home },
  783. { "1~", shell_esc_seq_home },
  784. { "3~", shell_esc_seq_del },
  785. { "F", shell_esc_seq_end },
  786. { "4~", shell_esc_seq_end },
  787. };
  788. static const struct shell_esc_seq *
  789. shell_esc_seq_lookup(const char *str)
  790. {
  791. for (size_t i = 0; i < ARRAY_SIZE(shell_esc_seqs); i++) {
  792. if (strcmp(shell_esc_seqs[i].str, str) == 0) {
  793. return &shell_esc_seqs[i];
  794. }
  795. }
  796. return NULL;
  797. }
  798. /*
  799. * Process a single escape sequence character.
  800. *
  801. * Return the next escape state or 0 if the sequence is complete.
  802. */
  803. static int
  804. shell_process_esc_sequence(struct shell *shell, char c)
  805. {
  806. const struct shell_esc_seq *seq;
  807. if (shell->esc_seq_index >= (ARRAY_SIZE(shell->esc_seq) - 1)) {
  808. shell_printf(shell, "shell: escape sequence too long\n");
  809. goto reset;
  810. }
  811. shell->esc_seq[shell->esc_seq_index] = c;
  812. shell->esc_seq_index++;
  813. shell->esc_seq[shell->esc_seq_index] = '\0';
  814. if ((c >= '@') && (c <= '~')) {
  815. seq = shell_esc_seq_lookup(shell->esc_seq);
  816. if (seq != NULL) {
  817. seq->fn(shell);
  818. }
  819. goto reset;
  820. }
  821. return SHELL_ESC_STATE_CSI;
  822. reset:
  823. shell->esc_seq_index = 0;
  824. return 0;
  825. }
  826. static int
  827. shell_process_args(struct shell *shell)
  828. {
  829. char c, prev;
  830. size_t i;
  831. int j;
  832. snprintf(shell->tmp_line, sizeof(shell->tmp_line), "%s",
  833. shell_line_str(shell_history_get_newest(&shell->history)));
  834. for (i = 0, j = 0, prev = SHELL_SEPARATOR;
  835. (c = shell->tmp_line[i]) != '\0';
  836. i++, prev = c) {
  837. if (c == SHELL_SEPARATOR) {
  838. if (prev != SHELL_SEPARATOR) {
  839. shell->tmp_line[i] = '\0';
  840. }
  841. } else {
  842. if (prev == SHELL_SEPARATOR) {
  843. shell->argv[j] = &shell->tmp_line[i];
  844. j++;
  845. if (j == ARRAY_SIZE(shell->argv)) {
  846. shell_printf(shell, "shell: too many arguments\n");
  847. return EINVAL;
  848. }
  849. shell->argv[j] = NULL;
  850. }
  851. }
  852. }
  853. shell->argc = j;
  854. return 0;
  855. }
  856. static void
  857. shell_process_line(struct shell *shell)
  858. {
  859. const struct shell_cmd *cmd;
  860. int error;
  861. cmd = NULL;
  862. error = shell_process_args(shell);
  863. if (error) {
  864. goto out;
  865. }
  866. if (shell->argc == 0) {
  867. goto out;
  868. }
  869. cmd = shell_cmd_set_lookup(shell->cmd_set, shell->argv[0]);
  870. if (cmd == NULL) {
  871. shell_printf(shell, "shell: %s: command not found\n", shell->argv[0]);
  872. goto out;
  873. }
  874. out:
  875. shell_history_push(&shell->history);
  876. if (cmd != NULL) {
  877. cmd->fn(shell, shell->argc, shell->argv);
  878. }
  879. }
  880. /*
  881. * Process a single control character.
  882. *
  883. * Return an error if the caller should reset the current line state.
  884. */
  885. static int
  886. shell_process_ctrl_char(struct shell *shell, char c)
  887. {
  888. switch (c) {
  889. case SHELL_ERASE_BS:
  890. case SHELL_ERASE_DEL:
  891. shell_process_backspace(shell);
  892. break;
  893. case '\t':
  894. return shell_process_tabulation(shell);
  895. case '\n':
  896. case '\r':
  897. shell_printf(shell, "\n");
  898. shell_process_line(shell);
  899. return EAGAIN;
  900. default:
  901. return 0;
  902. }
  903. return 0;
  904. }
  905. static void
  906. shell_run(struct shell *shell)
  907. {
  908. int c, error, escape;
  909. for (;;) {
  910. shell_reset(shell);
  911. escape = 0;
  912. for (;;) {
  913. c = shell->getc_fn(shell->io_object);
  914. if (escape) {
  915. switch (escape) {
  916. case SHELL_ESC_STATE_START:
  917. /* XXX CSI and SS3 sequence processing is the same */
  918. if ((c == '[') || (c == 'O')) {
  919. escape = SHELL_ESC_STATE_CSI;
  920. } else {
  921. escape = 0;
  922. }
  923. break;
  924. case SHELL_ESC_STATE_CSI:
  925. escape = shell_process_esc_sequence(shell, c);
  926. break;
  927. default:
  928. escape = 0;
  929. }
  930. error = 0;
  931. } else if (shell_is_ctrl_char(c)) {
  932. if (c == '\e') {
  933. escape = SHELL_ESC_STATE_START;
  934. error = 0;
  935. } else {
  936. error = shell_process_ctrl_char(shell, c);
  937. if (error) {
  938. break;
  939. }
  940. }
  941. } else {
  942. error = shell_process_raw_char(shell, c);
  943. }
  944. if (error) {
  945. break;
  946. }
  947. }
  948. }
  949. }
  950. void
  951. shell_printf(struct shell *shell, const char *format, ...)
  952. {
  953. va_list ap;
  954. va_start(ap, format);
  955. shell_vprintf(shell, format, ap);
  956. va_end(ap);
  957. }
  958. void
  959. shell_vprintf(struct shell *shell, const char *format, va_list ap)
  960. {
  961. shell->vfprintf_fn(shell->io_object, format, ap);
  962. }
  963. /*
  964. * XXX Temporary glue until the console module is reworked.
  965. */
  966. static struct shell_cmd_set shell_main_cmd_set;
  967. static struct shell shell_main;
  968. static int
  969. shell_main_getc(void *io_object)
  970. {
  971. (void)io_object;
  972. return getchar();
  973. }
  974. static void
  975. shell_main_vfprintf(void *io_object, const char *format, va_list ap)
  976. {
  977. (void)io_object;
  978. vprintf(format, ap);
  979. }
  980. static void
  981. shell_main_run(void *arg)
  982. {
  983. shell_run(arg);
  984. }
  985. static void
  986. shell_start(uintptr_t value, void *arg)
  987. {
  988. struct thread_attr attr;
  989. struct thread *thread;
  990. int error;
  991. (void)value;
  992. (void)arg;
  993. thread_attr_init(&attr, THREAD_KERNEL_PREFIX "shell");
  994. thread_attr_set_detached(&attr);
  995. error = thread_create(&thread, &attr, shell_main_run, &shell_main);
  996. error_check(error, "thread_create");
  997. }
  998. static int __init
  999. shell_setup(void)
  1000. {
  1001. shell_cmd_set_init(&shell_main_cmd_set);
  1002. shell_init(&shell_main, &shell_main_cmd_set,
  1003. shell_main_getc, shell_main_vfprintf, NULL);
  1004. bulletin_subscribe(log_get_bulletin(), &shell_log_bulletin_sub,
  1005. shell_start, NULL);
  1006. return 0;
  1007. }
  1008. INIT_OP_DEFINE(shell_setup,
  1009. INIT_OP_DEP(log_setup, true),
  1010. INIT_OP_DEP(mutex_setup, true),
  1011. INIT_OP_DEP(printf_setup, true));
  1012. struct shell_cmd_set * __init
  1013. shell_get_main_cmd_set(void)
  1014. {
  1015. return &shell_main_cmd_set;
  1016. }