shell.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. #include "cmd.h"
  2. #include <fcntl.h>
  3. #include <libKeyboard/keyboard.h>
  4. #include <printf.h>
  5. #include <stddef.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <sys/stat.h>
  10. #include <unistd.h>
  11. #define pause_cpu() asm volatile("pause\n\t");
  12. #define MEM_HISTORY 1024
  13. /**
  14. * @brief 循环读取每一行
  15. *
  16. * @param fd 键盘文件描述符
  17. * @param buf 输入缓冲区
  18. * @return 读取的字符数
  19. */
  20. int shell_readline(int fd, char *buf);
  21. void print_ascii_logo();
  22. extern char *shell_current_path;
  23. // 保存的历史命令(瞬时更改)
  24. char history_commands[MEM_HISTORY][INPUT_BUFFER_SIZE];
  25. // 真正的历史命令
  26. char real_history_commands[MEM_HISTORY][INPUT_BUFFER_SIZE];
  27. int count_history;
  28. // 现在对应的命令
  29. int current_command_index;
  30. /**
  31. * @brief shell主循环
  32. *
  33. * @param kb_fd 键盘文件描述符
  34. */
  35. void main_loop(int kb_fd)
  36. {
  37. count_history = 0;
  38. current_command_index = 0;
  39. unsigned char input_buffer[INPUT_BUFFER_SIZE] = {0};
  40. // 初始化当前工作目录的路径
  41. shell_current_path = (char *)malloc(3);
  42. memset(shell_current_path, 0, 3);
  43. shell_current_path[0] = '/';
  44. shell_current_path[1] = '\0';
  45. // shell命令行的主循环
  46. while (true)
  47. {
  48. int argc = 0;
  49. char **argv;
  50. printf("[DragonOS] %s # ", shell_current_path);
  51. memset(input_buffer, 0, INPUT_BUFFER_SIZE);
  52. // 添加初始光标
  53. put_string(" ", COLOR_BLACK, COLOR_WHITE);
  54. // 循环读取每一行到buffer
  55. count_history++;
  56. int count = shell_readline(kb_fd, input_buffer);
  57. if (!count || current_command_index < count_history - 1)
  58. count_history--;
  59. if (count)
  60. {
  61. strcpy(real_history_commands[count_history - 1], input_buffer);
  62. count_history++;
  63. memset(history_commands, 0, sizeof(history_commands));
  64. for (int i = 0; i <= count_history - 2; i++)
  65. strcpy(history_commands[i], real_history_commands[i]);
  66. current_command_index = count_history - 1;
  67. }
  68. if (count)
  69. {
  70. char command_origin[strlen(input_buffer)];
  71. strcpy(command_origin, input_buffer);
  72. int cmd_num = parse_command(input_buffer, &argc, &argv);
  73. printf("\n");
  74. if (cmd_num >= 0)
  75. shell_run_built_in_command(cmd_num, argc, argv);
  76. }
  77. else
  78. printf("\n");
  79. }
  80. }
  81. int main()
  82. {
  83. // 打开键盘文件
  84. // char kb_file_path[] = "/dev/char/ps2_keyboard";
  85. // int kb_fd = open(kb_file_path, 0);
  86. print_ascii_logo();
  87. // printf("before mkdir\n");
  88. // mkdir("/aaac", 0);
  89. // printf("after mkdir\n");
  90. main_loop(0);
  91. while (1)
  92. ;
  93. }
  94. /**
  95. * @brief 清除缓冲区
  96. *
  97. * @param count 缓冲区大小
  98. * @param buf 缓冲区内容
  99. */
  100. void clear_command(int count, char *buf)
  101. {
  102. for (int i = 0; i < count; i++)
  103. printf("%c", '\b');
  104. memset(buf, 0, sizeof(buf));
  105. }
  106. /**
  107. * @brief 切换命令(写入到缓冲区)
  108. *
  109. * @param buf 缓冲区
  110. * @param type 如果为1,就向上,如果为-1,就向下
  111. */
  112. void change_command(char *buf, int type)
  113. {
  114. current_command_index -= type;
  115. // 处理边界
  116. if (current_command_index < 0)
  117. current_command_index++;
  118. if (current_command_index >= count_history - 1)
  119. {
  120. // 初始只含一条空历史记录,需单独考虑
  121. if (count_history == 1)
  122. {
  123. // 防止出现多条空历史记录
  124. if (current_command_index > 1)
  125. current_command_index = 1;
  126. }
  127. else
  128. current_command_index = count_history - 2;
  129. }
  130. strcpy(buf, history_commands[current_command_index]);
  131. printf("%s", buf);
  132. put_string(" ", COLOR_BLACK, COLOR_WHITE);
  133. }
  134. /**
  135. * @brief 循环读取每一行
  136. *
  137. * @param fd 键盘文件描述符
  138. * @param buf 输入缓冲区
  139. * @return 读取的字符数
  140. */
  141. int shell_readline(int fd, char *buf)
  142. {
  143. int key = 0;
  144. int count = 0;
  145. while (1)
  146. {
  147. // key = keyboard_analyze_keycode(fd);
  148. key = getchar();
  149. // printf("key = %d\n", key);
  150. if (key == 224)
  151. {
  152. key = getchar();
  153. // printf("key = %d\n", key);
  154. switch (key)
  155. {
  156. case 72:
  157. // 向上方向键
  158. if (count_history != 0)
  159. {
  160. // put_string(" ", COLOR_WHITE, COLOR_BLACK);
  161. printf("%c", '\b');
  162. clear_command(count, buf);
  163. count = 0;
  164. // 向历史
  165. change_command(buf, 1);
  166. count = strlen(buf);
  167. }
  168. key = 0xc8;
  169. break;
  170. case 80:
  171. // 向下方向键
  172. if (count_history != 0)
  173. {
  174. // put_string(" ", COLOR_WHITE, COLOR_BLACK);
  175. printf("%c", '\b');
  176. clear_command(count, buf);
  177. count = 0;
  178. // 向历史
  179. change_command(buf, -1);
  180. count = strlen(buf);
  181. }
  182. key = 0x50;
  183. break;
  184. default:
  185. break;
  186. }
  187. }
  188. if (key == '\n')
  189. {
  190. if (count > 0 && current_command_index >= count_history)
  191. {
  192. memset(history_commands[current_command_index - 1], 0,
  193. sizeof(history_commands[current_command_index - 1]));
  194. count_history--;
  195. }
  196. printf("%c", '\b');
  197. return count;
  198. }
  199. if (key && key != 0xc8)
  200. {
  201. if (key == '\b')
  202. {
  203. if (count > 0)
  204. {
  205. // 回退去除先前光标
  206. printf("%c", '\b');
  207. // 去除字符
  208. printf("%c", '\b');
  209. buf[--count] = 0;
  210. // 在最后一个字符处加光标
  211. put_string(" ", COLOR_BLACK, COLOR_WHITE);
  212. }
  213. }
  214. else
  215. {
  216. printf("%c", '\b');
  217. buf[count++] = key;
  218. printf("%c", key);
  219. // 在最后一个字符处加光标
  220. put_string(" ", COLOR_BLACK, COLOR_WHITE);
  221. }
  222. if (count > 0 && current_command_index >= count_history)
  223. {
  224. memset(history_commands[count_history], 0, sizeof(history_commands[count_history]));
  225. strcpy(history_commands[count_history], buf);
  226. }
  227. else if (count > 0)
  228. {
  229. memset(history_commands[current_command_index], 0, sizeof(history_commands[current_command_index]));
  230. strcpy(history_commands[current_command_index], buf);
  231. }
  232. }
  233. // 输入缓冲区满了之后,直接返回
  234. if (count >= INPUT_BUFFER_SIZE - 1)
  235. {
  236. printf("%c", '\b');
  237. return count;
  238. }
  239. pause_cpu();
  240. }
  241. }
  242. void print_ascii_logo()
  243. {
  244. printf("\n\n");
  245. printf(" ____ ___ ____ \n");
  246. printf("| _ \\ _ __ __ _ __ _ ___ _ __ / _ \\ / ___| \n");
  247. printf("| | | || '__| / _` | / _` | / _ \\ | '_ \\ | | | |\\___ \\ \n");
  248. printf("| |_| || | | (_| || (_| || (_) || | | || |_| | ___) |\n");
  249. printf("|____/ |_| \\__,_| \\__, | \\___/ |_| |_| \\___/ |____/ \n");
  250. printf(" |___/ \n");
  251. printf("\n\n");
  252. }