shell.c 25 KB

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