1
0

shell.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922
  1. /*
  2. * Shell library
  3. * Contains shell functions
  4. */
  5. // uses fs.c
  6. // uses hidfifo.c
  7. // uses gfx.c
  8. // uses stdlib.c
  9. // Max length of a single command
  10. #define SHELL_CMD_MAX_LENGTH 128
  11. // The number of commands to remember
  12. #define SHELL_CMD_HISTORY_LENGTH 32
  13. // Address of user program (already defined in BDOS.c)
  14. //#define RUN_ADDR 0x400000
  15. // Chunk size for reading files and programs
  16. // NOTE: must be dividable by 4
  17. #define SHELL_FILE_READ_CHUNK_SIZE 512
  18. #define SHELL_PROGRAM_READ_CHUNK_SIZE 32768
  19. // The current command that is being typed
  20. char SHELL_command[SHELL_CMD_MAX_LENGTH];
  21. word SHELL_commandIdx = 0; // index in current command
  22. word SHELL_promptCursorPos = 0;
  23. // History of commands
  24. char SHELL_history[SHELL_CMD_HISTORY_LENGTH][SHELL_CMD_MAX_LENGTH];
  25. word SHELL_historyPtr = 0; // index of next entry in history
  26. word SHELL_historySelectIdx = 0; // index of selected entry in history
  27. word SHELL_historyMovedBackwards = 0; // number of times that the user moved backwards in history
  28. word SHELL_historyLength = 0; // number of filled entries in history
  29. // Appends current CMD to history, ignores empty commands
  30. void SHELL_historyAppend()
  31. {
  32. // ignore empty command
  33. if (SHELL_command[0] == 0)
  34. {
  35. return;
  36. }
  37. // wrap around if full, overwriting the oldest entries
  38. if (SHELL_historyPtr == SHELL_CMD_HISTORY_LENGTH)
  39. {
  40. SHELL_historyPtr = 0;
  41. }
  42. strcpy(SHELL_history[SHELL_historyPtr], SHELL_command);
  43. SHELL_historyPtr++;
  44. // sync currently selected with the latest command
  45. SHELL_historySelectIdx = SHELL_historyPtr;
  46. // no need to update length if the history is already full
  47. if (SHELL_historyLength < SHELL_CMD_HISTORY_LENGTH)
  48. {
  49. SHELL_historyLength++;
  50. }
  51. }
  52. void SHELL_historyGoBack()
  53. {
  54. // ignore if we have gone fully back in time
  55. if (SHELL_historyMovedBackwards < SHELL_historyLength)
  56. {
  57. SHELL_historyMovedBackwards++;
  58. // go back in history, wrap around select idx
  59. if (SHELL_historySelectIdx == 0)
  60. {
  61. SHELL_historySelectIdx = SHELL_CMD_HISTORY_LENGTH;
  62. }
  63. else
  64. {
  65. SHELL_historySelectIdx--;
  66. }
  67. SHELL_setCommand(SHELL_history[SHELL_historySelectIdx]);
  68. }
  69. }
  70. void SHELL_historyGoForwards()
  71. {
  72. // only if we are in the past
  73. if (SHELL_historyMovedBackwards > 0)
  74. {
  75. SHELL_historyMovedBackwards--;
  76. // go forward in history, wrap around select idx
  77. if (SHELL_historySelectIdx == SHELL_CMD_HISTORY_LENGTH)
  78. {
  79. SHELL_historySelectIdx = 0;
  80. }
  81. else
  82. {
  83. SHELL_historySelectIdx++;
  84. }
  85. SHELL_setCommand(SHELL_history[SHELL_historySelectIdx]);
  86. // clear command if back in present
  87. if (SHELL_historyMovedBackwards == 0)
  88. {
  89. // use backspaces to clear the text on screen
  90. while (SHELL_commandIdx > 0)
  91. {
  92. GFX_PrintcConsole(0x8);
  93. SHELL_commandIdx--;
  94. }
  95. SHELL_clearCommand();
  96. }
  97. }
  98. }
  99. // Clears the current command in memory
  100. void SHELL_clearCommand()
  101. {
  102. SHELL_command[0] = 0;
  103. SHELL_commandIdx = 0;
  104. }
  105. // Clears current command and replaces it with cmd
  106. void SHELL_setCommand(char* cmd)
  107. {
  108. if (cmd[0] == 0)
  109. {
  110. return;
  111. }
  112. // clear current command on screen by doing backspaces
  113. while (SHELL_commandIdx > 0)
  114. {
  115. GFX_PrintcConsole(0x8);
  116. SHELL_commandIdx--;
  117. }
  118. strcpy(SHELL_command, cmd);
  119. // set new shell cmd index
  120. SHELL_commandIdx = strlen(SHELL_command);
  121. // print new command
  122. GFX_PrintConsole(SHELL_command);
  123. }
  124. // Prints current display prompt
  125. void SHELL_print_prompt()
  126. {
  127. // TODO: if path > X chars, only show last X-1 chars with some character in front
  128. GFX_PrintConsole(SHELL_path);
  129. GFX_PrintConsole("> ");
  130. SHELL_promptCursorPos = GFX_cursor;
  131. }
  132. // Initialize shell
  133. void SHELL_init()
  134. {
  135. // clear current command
  136. SHELL_clearCommand();
  137. // clear screen
  138. GFX_clearWindowtileTable();
  139. GFX_clearWindowpaletteTable();
  140. GFX_cursor = 0;
  141. SHELL_print_prompt();
  142. }
  143. // Checks if p starts with cmd, followed by a space or a \0
  144. // Returns 1 if true, 0 otherwise
  145. word SHELL_commandCompare(char* p, char* cmd)
  146. {
  147. word similar = 1;
  148. word i = 0;
  149. while (cmd[i] != 0)
  150. {
  151. if (cmd[i] != p[i])
  152. {
  153. similar = 0;
  154. }
  155. i += 1;
  156. }
  157. if (similar)
  158. {
  159. similar = 0;
  160. if (p[i] == 0 || p[i] == ' ')
  161. similar = 1;
  162. }
  163. return similar;
  164. }
  165. // Returns the number of arguments of a command line
  166. // Does this by counting the number times a character is placed
  167. // directly after a space
  168. word SHELL_numberOfArguments(char* p)
  169. {
  170. word args = 0;
  171. word foundSpace = 0;
  172. word i = 0;
  173. while (p[i] != 0)
  174. {
  175. if (p[i] == ' ')
  176. {
  177. foundSpace = 1;
  178. }
  179. else
  180. {
  181. if (foundSpace)
  182. {
  183. // if character after space
  184. if (p[i] != 0)
  185. {
  186. args += 1;
  187. }
  188. foundSpace = 0;
  189. }
  190. }
  191. i += 1;
  192. }
  193. return args;
  194. }
  195. // Implementation of ldir command
  196. // Lists directory given in arg
  197. // Argument is passed in arg and should end with a \0 (not space)
  198. void SHELL_ldir(char* arg)
  199. {
  200. // backup current path
  201. strcpy(SHELL_pathBackup, SHELL_path);
  202. // add arg to path
  203. if (FS_changePath(arg) == FS_ANSW_USB_INT_SUCCESS)
  204. {
  205. // do listdir
  206. char *b = (char *) TEMP_ADDR;
  207. if (FS_listDir(SHELL_path, b) == FS_ANSW_USB_INT_SUCCESS)
  208. {
  209. GFX_PrintConsole(b);
  210. }
  211. // restore path
  212. strcpy(SHELL_path, SHELL_pathBackup);
  213. }
  214. else
  215. {
  216. GFX_PrintConsole("E: Invalid path\n");
  217. }
  218. }
  219. // Implementation of run command
  220. // Loads file to memory at RUN_ADDR and jumps to it
  221. // Argument is passed in arg and should end with a \0 or space
  222. // If useBin is set, it will look for the file in the /BIN folder
  223. void SHELL_runFile(char* arg, word useBin)
  224. {
  225. // backup current path
  226. strcpy(SHELL_pathBackup, SHELL_path);
  227. // replace space with \0
  228. word i = 0;
  229. word putBackSpaceIndex = 0; // and put back later for args
  230. while(*(arg+i) != ' ' && *(arg+i) != 0)
  231. {
  232. i++;
  233. }
  234. if (*(arg+i) == ' ')
  235. {
  236. putBackSpaceIndex = i;
  237. }
  238. *(arg+i) = 0;
  239. if (useBin)
  240. {
  241. strcpy(SHELL_path, "/BIN/");
  242. strcat(SHELL_path, arg);
  243. }
  244. else
  245. {
  246. // create full path using arg
  247. FS_getFullPath(arg);
  248. }
  249. // if the resulting path is correct (can be file or directory)
  250. if (FS_sendFullPath(SHELL_path) == FS_ANSW_USB_INT_SUCCESS)
  251. {
  252. // if we can successfully open the file (not directory)
  253. if (FS_open() == FS_ANSW_USB_INT_SUCCESS)
  254. {
  255. word fileSize = FS_getFileSize();
  256. if ((unsigned int) fileSize <= (unsigned int) 0x300000)
  257. {
  258. if (FS_setCursor(0) == FS_ANSW_USB_INT_SUCCESS)
  259. {
  260. // read the file in chunks
  261. char *b = (char *) RUN_ADDR;
  262. word bytesSent = 0;
  263. GFX_PrintConsole("Loading");
  264. word loopCount = 0; // counter for animation
  265. // loop until all bytes are sent
  266. while (bytesSent != fileSize)
  267. {
  268. word partToSend = fileSize - bytesSent;
  269. // send in parts of SHELL_PROGRAM_READ_CHUNK_SIZE
  270. if ((unsigned int) partToSend > (unsigned int) SHELL_PROGRAM_READ_CHUNK_SIZE)
  271. partToSend = SHELL_PROGRAM_READ_CHUNK_SIZE;
  272. // read from usb to memory in word mode
  273. if (FS_readFile(b, partToSend, 1) != FS_ANSW_USB_INT_SUCCESS)
  274. uprintln("W: Error reading file\n");
  275. // indicate progress
  276. if (loopCount == 3)
  277. {
  278. GFX_PrintcConsole(0x8); // backspace
  279. GFX_PrintcConsole(0x8); // backspace
  280. GFX_PrintcConsole(0x8); // backspace
  281. loopCount = 0;
  282. }
  283. else
  284. {
  285. GFX_PrintcConsole('.');
  286. loopCount++;
  287. }
  288. // Update the amount of bytes sent
  289. bytesSent += partToSend;
  290. b += ((unsigned)partToSend>>2); // divide by 4 because one address is 4 bytes
  291. }
  292. // remove the dots
  293. for (loopCount; loopCount > 0; loopCount--)
  294. {
  295. GFX_PrintcConsole(0x8); // backspace
  296. }
  297. // close file after done
  298. FS_close();
  299. // remove the loading text
  300. word i;
  301. for (i = 0; i < 7; i++)
  302. {
  303. GFX_PrintcConsole(0x8); // backspace
  304. }
  305. // put back the space in the command
  306. if (putBackSpaceIndex != 0)
  307. {
  308. *(arg+putBackSpaceIndex) = ' ';
  309. }
  310. BDOS_Backup();
  311. // Indicate that a user program is running
  312. BDOS_userprogramRunning = 1;
  313. // jump to the program
  314. asm(
  315. "; backup registers\n"
  316. "push r1\n"
  317. "push r2\n"
  318. "push r3\n"
  319. "push r4\n"
  320. "push r5\n"
  321. "push r6\n"
  322. "push r7\n"
  323. "push r8\n"
  324. "push r9\n"
  325. "push r10\n"
  326. "push r11\n"
  327. "push r12\n"
  328. "push r13\n"
  329. "push r14\n"
  330. "push r15\n"
  331. //"ccache\n"
  332. "savpc r1\n"
  333. "push r1\n"
  334. "jump 0x400000\n"
  335. "; restore registers\n"
  336. "pop r15\n"
  337. "pop r14\n"
  338. "pop r13\n"
  339. "pop r12\n"
  340. "pop r11\n"
  341. "pop r10\n"
  342. "pop r9\n"
  343. "pop r8\n"
  344. "pop r7\n"
  345. "pop r6\n"
  346. "pop r5\n"
  347. "pop r4\n"
  348. "pop r3\n"
  349. "pop r2\n"
  350. "pop r1\n"
  351. );
  352. // Indicate that no user program is running anymore
  353. BDOS_userprogramRunning = 0;
  354. BDOS_Restore();
  355. }
  356. else
  357. GFX_PrintConsole("E: Could not move to start of file\n");
  358. }
  359. else
  360. GFX_PrintConsole("E: Program is too large\n");
  361. }
  362. else
  363. {
  364. if (useBin)
  365. GFX_PrintConsole("E: Unknown command\n");
  366. else
  367. GFX_PrintConsole("E: Could not open file\n");
  368. }
  369. }
  370. else
  371. {
  372. if (useBin)
  373. GFX_PrintConsole("E: Unknown command\n");
  374. else
  375. GFX_PrintConsole("E: Invalid path\n");
  376. }
  377. // restore path
  378. strcpy(SHELL_path, SHELL_pathBackup);
  379. }
  380. // Implementation of print command
  381. // Prints file to screen
  382. // Argument is passed in arg and should end with a \0 (not space)
  383. void SHELL_printFile(char* arg)
  384. {
  385. // backup current path
  386. strcpy(SHELL_pathBackup, SHELL_path);
  387. // create full path using arg
  388. FS_getFullPath(arg);
  389. // if the resulting path is correct (can be file or directory)
  390. if (FS_sendFullPath(SHELL_path) == FS_ANSW_USB_INT_SUCCESS)
  391. {
  392. // if we can successfully open the file (not directory)
  393. if (FS_open() == FS_ANSW_USB_INT_SUCCESS)
  394. {
  395. word fileSize = FS_getFileSize();
  396. if (FS_setCursor(0) == FS_ANSW_USB_INT_SUCCESS)
  397. {
  398. // read the file in chunks
  399. char *b = (char *) TEMP_ADDR;
  400. word bytesSent = 0;
  401. // loop until all bytes are sent
  402. while (bytesSent != fileSize)
  403. {
  404. word partToSend = fileSize - bytesSent;
  405. // send in parts of SHELL_FILE_READ_CHUNK_SIZE
  406. if ((unsigned int) partToSend > (unsigned int) SHELL_FILE_READ_CHUNK_SIZE)
  407. partToSend = SHELL_FILE_READ_CHUNK_SIZE;
  408. // read from usb to buffer in byte mode
  409. if (FS_readFile(b, partToSend, 0) != FS_ANSW_USB_INT_SUCCESS)
  410. uprintln("W: Error reading file\n");
  411. // append buffer with terminator
  412. *(b+partToSend) = 0;
  413. // print buffer to console
  414. GFX_PrintConsole(b);
  415. // Update the amount of bytes sent
  416. bytesSent += partToSend;
  417. }
  418. // close file after done
  419. FS_close();
  420. // end with a newline for the next shell prompt
  421. GFX_PrintcConsole('\n');
  422. }
  423. else
  424. GFX_PrintConsole("E: Could not move to start of file\n");
  425. }
  426. else
  427. GFX_PrintConsole("E: Could not open file\n");
  428. }
  429. else
  430. GFX_PrintConsole("E: Invalid path\n");
  431. // restore path
  432. strcpy(SHELL_path, SHELL_pathBackup);
  433. }
  434. // Removes file/dir
  435. void SHELL_remove(char* arg)
  436. {
  437. // backup current path
  438. strcpy(SHELL_pathBackup, SHELL_path);
  439. // create full path using arg
  440. FS_getFullPath(arg);
  441. // if the resulting path is correct (can be file or directory)
  442. if (FS_sendFullPath(SHELL_path) == FS_ANSW_USB_INT_SUCCESS)
  443. {
  444. // if we can successfully open the file (not directory)
  445. word retval = FS_open();
  446. if (retval == FS_ANSW_USB_INT_SUCCESS)
  447. {
  448. if (FS_delete() == FS_ANSW_USB_INT_SUCCESS)
  449. {
  450. GFX_PrintConsole("File removed\n");
  451. }
  452. else
  453. GFX_PrintConsole("E: Could not delete file\n");
  454. }
  455. else if (retval == FS_ANSW_ERR_OPEN_DIR)
  456. {
  457. if (FS_delete() == FS_ANSW_USB_INT_SUCCESS)
  458. {
  459. GFX_PrintConsole("Dir removed\n");
  460. }
  461. else
  462. GFX_PrintConsole("E: Could not delete dir\n");
  463. }
  464. else
  465. GFX_PrintConsole("E: Could not find file or dir\n");
  466. }
  467. else
  468. GFX_PrintConsole("E: Invalid path\n");
  469. // restore path
  470. strcpy(SHELL_path, SHELL_pathBackup);
  471. }
  472. // Creates file in current directory
  473. void SHELL_createFile(char* arg)
  474. {
  475. // backup current path
  476. strcpy(SHELL_pathBackup, SHELL_path);
  477. // if current path is correct (can be file or directory)
  478. if (FS_sendFullPath(SHELL_path) == FS_ANSW_USB_INT_SUCCESS)
  479. {
  480. word retval = FS_open();
  481. // check that we can open the path
  482. if (retval == FS_ANSW_USB_INT_SUCCESS || retval == FS_ANSW_ERR_OPEN_DIR)
  483. {
  484. // check length of filename
  485. if (strlen(arg) <= 12)
  486. {
  487. // uppercase filename
  488. strToUpper(arg);
  489. // send filename
  490. FS_sendSinglePath(arg);
  491. // create the file
  492. if (FS_createFile() == FS_ANSW_USB_INT_SUCCESS)
  493. {
  494. GFX_PrintConsole("File created\n");
  495. }
  496. else
  497. GFX_PrintConsole("E: Could not create file\n");
  498. }
  499. else
  500. GFX_PrintConsole("E: Filename too long\n");
  501. }
  502. else
  503. GFX_PrintConsole("E: Invalid path\n");
  504. }
  505. else
  506. GFX_PrintConsole("E: Invalid path\n");
  507. // restore path
  508. strcpy(SHELL_path, SHELL_pathBackup);
  509. }
  510. // Creates directory in current directory
  511. void SHELL_createDir(char* arg)
  512. {
  513. // backup current path
  514. strcpy(SHELL_pathBackup, SHELL_path);
  515. // if current path is correct (can be file or directory)
  516. if (FS_sendFullPath(SHELL_path) == FS_ANSW_USB_INT_SUCCESS)
  517. {
  518. word retval = FS_open();
  519. // check that we can open the path
  520. if (retval == FS_ANSW_USB_INT_SUCCESS || retval == FS_ANSW_ERR_OPEN_DIR)
  521. {
  522. // check length of directory, must be 8
  523. if (strlen(arg) <= 8)
  524. {
  525. // uppercase filename
  526. strToUpper(arg);
  527. // send filename
  528. FS_sendSinglePath(arg);
  529. // create the directory
  530. if (FS_createDir() == FS_ANSW_USB_INT_SUCCESS)
  531. {
  532. GFX_PrintConsole("Dir created\n");
  533. }
  534. else
  535. GFX_PrintConsole("E: Could not create dir\n");
  536. }
  537. else
  538. GFX_PrintConsole("E: Filename too long\n");
  539. }
  540. else
  541. GFX_PrintConsole("E: Invalid path\n");
  542. }
  543. else
  544. GFX_PrintConsole("E: Invalid path\n");
  545. // restore path
  546. strcpy(SHELL_path, SHELL_pathBackup);
  547. }
  548. // Print help text
  549. void SHELL_printHelp()
  550. {
  551. GFX_PrintConsole("BDOS for FPGC\n");
  552. GFX_PrintConsole("Supported OS commands:\n");
  553. GFX_PrintConsole("- ./file [args]\n");
  554. GFX_PrintConsole("- CD [arg1]\n");
  555. GFX_PrintConsole("- LS [arg1]\n");
  556. GFX_PrintConsole("- PRINT [arg1]\n");
  557. GFX_PrintConsole("- MKDIR [arg1]\n");
  558. GFX_PrintConsole("- MKFILE [arg1]\n");
  559. GFX_PrintConsole("- RM [arg1]\n");
  560. GFX_PrintConsole("- CLEAR\n");
  561. GFX_PrintConsole("- HELP\n");
  562. GFX_PrintConsole("\nExtra info:\n");
  563. GFX_PrintConsole("- Programs are executed form /BIN\n");
  564. GFX_PrintConsole("- Run LS /BIN to list all programs\n");
  565. GFX_PrintConsole("- Paths can be relative or absolute\n");
  566. }
  567. // Parses command line buffer and executes command if found
  568. // Commands to parse:
  569. // [x] ./ (RUN)
  570. // [x] CD
  571. // [x] LS
  572. // [x] CLEAR
  573. // [x] PRINT
  574. // [x] MKDIR
  575. // [x] MKFILE
  576. // [x] RM
  577. // [x] HELP
  578. // [] RENAME
  579. void SHELL_parseCommand(char* p)
  580. {
  581. // ./ (RUN)
  582. // No commandCompare, because special case with no space
  583. if (p[0] == '.' && p[1] == '/' && p[2] != 0)
  584. {
  585. SHELL_runFile(p+2, 0); // pointer to start of filename, which ends with \0 or space
  586. }
  587. // LS
  588. else if (SHELL_commandCompare(p, "ls"))
  589. {
  590. word args = SHELL_numberOfArguments(p);
  591. // if incorrect number of arguments
  592. if (args > 1)
  593. {
  594. GFX_PrintConsole("E: Too many arguments\n");
  595. return;
  596. }
  597. else if (args == 1)
  598. {
  599. SHELL_ldir(p+3); // pointer to start of first arg, which ends with \0
  600. }
  601. else // if no args
  602. {
  603. SHELL_ldir("");
  604. }
  605. }
  606. // CD
  607. else if (SHELL_commandCompare(p, "cd"))
  608. {
  609. word args = SHELL_numberOfArguments(p);
  610. // if incorrect number of arguments
  611. if (args > 1)
  612. {
  613. GFX_PrintConsole("E: Too many arguments\n");
  614. return;
  615. }
  616. else if (args == 1)
  617. {
  618. // pointer to start of first arg, which ends with \0
  619. if (FS_changePath(p+3) != FS_ANSW_USB_INT_SUCCESS)
  620. {
  621. GFX_PrintConsole("E: Invalid path\n");
  622. }
  623. }
  624. else // if no args, go to root
  625. {
  626. // reset path variable to /
  627. SHELL_path[0] = '/';
  628. SHELL_path[1] = 0; // terminate string
  629. }
  630. // update path backup
  631. strcpy(SHELL_pathBackup, SHELL_path);
  632. }
  633. // CLEAR
  634. else if (SHELL_commandCompare(p, "clear"))
  635. {
  636. // clear screen by clearing window tables and resetting the cursor
  637. GFX_clearWindowtileTable();
  638. GFX_clearWindowpaletteTable();
  639. GFX_cursor = 0;
  640. }
  641. // PRINT
  642. else if (SHELL_commandCompare(p, "print"))
  643. {
  644. word args = SHELL_numberOfArguments(p);
  645. // if incorrect number of arguments
  646. if (args != 1)
  647. {
  648. GFX_PrintConsole("E: Expected 1 argument\n");
  649. return;
  650. }
  651. else
  652. {
  653. SHELL_printFile(p+6); // pointer to start of first arg, which ends with \0
  654. }
  655. }
  656. // RM
  657. else if (SHELL_commandCompare(p, "rm"))
  658. {
  659. word args = SHELL_numberOfArguments(p);
  660. // if incorrect number of arguments
  661. if (args != 1)
  662. {
  663. GFX_PrintConsole("E: Expected 1 argument\n");
  664. return;
  665. }
  666. else
  667. {
  668. SHELL_remove(p+3); // pointer to start of first arg, which ends with \0
  669. }
  670. }
  671. // MKFILE
  672. else if (SHELL_commandCompare(p, "mkfile"))
  673. {
  674. word args = SHELL_numberOfArguments(p);
  675. // if incorrect number of arguments
  676. if (args != 1)
  677. {
  678. GFX_PrintConsole("E: Expected 1 argument\n");
  679. return;
  680. }
  681. else
  682. {
  683. SHELL_createFile(p+7); // pointer to start of first arg, which ends with \0
  684. }
  685. }
  686. // MKDIR
  687. else if (SHELL_commandCompare(p, "mkdir"))
  688. {
  689. word args = SHELL_numberOfArguments(p);
  690. // if incorrect number of arguments
  691. if (args != 1)
  692. {
  693. GFX_PrintConsole("E: Expected 1 argument\n");
  694. return;
  695. }
  696. else
  697. {
  698. SHELL_createDir(p+6); // pointer to start of first arg, which ends with \0
  699. }
  700. }
  701. // HELP
  702. else if (SHELL_commandCompare(p, "help"))
  703. {
  704. SHELL_printHelp();
  705. }
  706. // No command
  707. else if (p[0] == 0)
  708. {
  709. // do nothing on enter
  710. }
  711. // Check if the command is in /BIN as a file
  712. else
  713. {
  714. // copy p to commandBuf but without the arguments
  715. char commandBuf[16]; // filenames cannot be larger than 12 characters anyways, so this should be enough
  716. word i = 0;
  717. commandBuf[0] = 0;
  718. while (p[i] != 0 && p[i] != ' ' && i < 15)
  719. {
  720. commandBuf[i] = p[i];
  721. i++;
  722. }
  723. commandBuf[i] = 0; // terminate buffer
  724. SHELL_runFile(commandBuf, 1);
  725. return;
  726. }
  727. }
  728. void SHELL_loop()
  729. {
  730. if (HID_FifoAvailable())
  731. {
  732. word c = HID_FifoRead();
  733. // special keys, like arrow keys
  734. if (c > 255)
  735. {
  736. if (c == 258) // arrow up
  737. {
  738. SHELL_historyGoBack();
  739. }
  740. else if (c == 259) // arrow down
  741. {
  742. SHELL_historyGoForwards();
  743. }
  744. }
  745. else if (c == 0x8) // backspace
  746. {
  747. // replace last char in buffer by 0 (if not at start)
  748. if (SHELL_commandIdx != 0)
  749. {
  750. SHELL_commandIdx--;
  751. SHELL_command[SHELL_commandIdx] = 0;
  752. }
  753. // prevent removing characters from the shell prompt
  754. if (GFX_cursor > SHELL_promptCursorPos)
  755. {
  756. // print backspace to console to remove last typed character
  757. GFX_PrintcConsole(c);
  758. }
  759. }
  760. else if (c == 0x9) // tab
  761. {
  762. // do nothing for now when tab
  763. }
  764. else if (c == 0x1b) // escape
  765. {
  766. // do nothing for now when escape
  767. }
  768. else if (c == 0xa) // newline/enter
  769. {
  770. // reset history counter
  771. SHELL_historyMovedBackwards = 0;
  772. // append command to history
  773. SHELL_historyAppend();
  774. // start on new line
  775. GFX_PrintcConsole(c);
  776. // parse/execute command
  777. SHELL_parseCommand(SHELL_command);
  778. // clear buffer
  779. SHELL_clearCommand();
  780. // print shell prompt
  781. SHELL_print_prompt();
  782. }
  783. else
  784. {
  785. if (SHELL_commandIdx < SHELL_CMD_MAX_LENGTH)
  786. {
  787. // add to command buffer and print character
  788. SHELL_command[SHELL_commandIdx] = c;
  789. SHELL_commandIdx++;
  790. SHELL_command[SHELL_commandIdx] = 0; // terminate
  791. GFX_PrintcConsole(c);
  792. }
  793. }
  794. }
  795. }