10 ncst命令(harib23j)

本节要进行今天的最后一项修改。

用start命令启动应用程序看起来很不错,但如果运行color这样的程序的话,我们并不希望真的新开一个命令行窗口出来,反倒是没有这个多余的窗口比较好。那么下面我们就来做一个不打开新命令行窗口的start命令吧,给它起个名字,叫做“no console start”,简称ncst命令。

这样,我们可以根据需要来选择用哪个命令:当希望运行程序的同时打开新的命令行窗口时,用start命令;而当不需要打开新的命令行窗口时,就用ncst命令。

不过,不打开命令行窗口而直接运行应用程序到底应该怎样实现呢?想来想去,总觉得要改的地方实在太多了,我们还是一步一步慢慢来吧。其实我们可以换个思路,不要一味去想“没有命令行窗口该怎样处理”,而可以“想办法禁止向命令行显示内容”(换句话说,用ncst命令启动的应用程序会忽略字符串显示API的调用)。

■■■■■

好了,我们先从添加ncst命令开始做起吧。

我们将没有窗口的命令行任务的cons—>sht规定为0。在没有窗口的情况下,执行mem命令和cls命令也没有用,因此我们将这些命令全部忽略。

本次的console.c节选

  1. void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, int memtotal)
  2. {
  3. if (strcmp(cmdline, "mem") == 0 && cons->sht != 0) { /*从此开始*/
  4. cmd_mem(cons, memtotal);
  5. } else if (strcmp(cmdline, "cls") == 0 && cons->sht != 0) {
  6. cmd_cls(cons);
  7. } else if (strcmp(cmdline, "dir") == 0 && cons->sht != 0) {
  8. cmd_dir(cons);
  9. } else if (strncmp(cmdline, "type ", 5) == 0 && cons->sht != 0) { /*到此结束*/
  10. cmd_type(cons, fat, cmdline);
  11. } else if (strcmp(cmdline, "exit") == 0) {
  12. cmd_exit(cons, fat);
  13. } else if (strncmp(cmdline, "start ", 6) == 0) {
  14. cmd_start(cons, cmdline, memtotal);
  15. } else if (strncmp(cmdline, "ncst ", 5) == 0) { /*这里!*/
  16. cmd_ncst(cons, cmdline, memtotal); /*这里!*/
  17. } else if (cmdline[0] != 0) {
  18. (中略)
  19. }
  20. void cmd_ncst(struct CONSOLE *cons, char *cmdline, int memtotal)
  21. {
  22. struct TASK *task = open_constask(0, memtotal);
  23. struct FIFO32 *fifo = &task->fifo;
  24. int i;
  25. /*将命令行输入的字符串逐字复制到新的命令行窗口中*/
  26. for (i = 5; cmdline[i] != 0; i++) {
  27. fifo32_put(fifo, cmdline[i] + 256);
  28. }
  29. fifo32_put(fifo, 10 + 256); /*回车键*/
  30. cons_newline(cons);
  31. return;
  32. }

cmd_ncst是照着cmd_start的样子写的,其中open_constask这个函数我们接下来会写在bootpack.c中。

■■■■■

当cons—>sht为0时,要禁用命令行窗口的字符显示等所有操作,因此我们需要修改与其相关的函数。

本次的console.c节选

  1. void cons_putchar(struct CONSOLE *cons, int chr, char move)
  2. {
  3. (中略)
  4. if (s[0] == 0x09) { /*制表符*/
  5. for (;;) {
  6. if (cons->sht != 0) { /*从此开始*/
  7. putfouts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, " ", 1);
  8. } /*到此结束*/
  9. cons->cur_x += 8;
  10. (中略)
  11. }
  12. } else if (s[0] == 0x0a) { /*换行*/
  13. cons_newline(cons);
  14. } else if (s[0] == 0x0d) { /*回车*/
  15. /*不执行任何操作*/
  16. } else { /*一般字符*/
  17. if (cons->sht != 0) { /*从此开始*/
  18. putfouts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, s, 1);
  19. } /*到此结束*/
  20. if (move != 0) {
  21. (中略)
  22. }
  23. }
  24. return;
  25. }
  26. void cons_newline(struct CONSOLE *cons)
  27. {
  28. int x, y;
  29. struct SHEET *sheet = cons->sht;
  30. if (cons->cur_y < 28 + 112) {
  31. cons->cur_y += 16; /*到下一行*/
  32. } else {
  33. /*滚动*/
  34. if (sheet != 0) { /*这里!*/
  35. for (y = 28; y < 28 + 112; y++) {
  36. (中略)
  37. }
  38. for (y = 28 + 112; y < 28 + 128; y++) {
  39. (中略)
  40. }
  41. sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128);
  42. } /*这里!*/
  43. }
  44. cons->cur_x = 8;
  45. return;
  46. }

本以为相关的函数很多,所以要改动的地方也会很多,不过这么一看其实也没多少嘛。

■■■■■

接下来我们来修改console_task。修改的要点是,当不显示命令行窗口时,禁用一些不必要的处理,并且当命令执行完毕时,立即结束命令行窗口任务(应用程序运行完毕后,这个命令行窗口任务就派不上什么用场了。因为画面上不显示命令行窗口,也就无法输入其他命令,也不能执行关闭操作,所以我们需要使其在命令执行完毕时自动终止任务)。

本次的console.c节选

  1. void console_task(struct SHEET *sheet, int memtotal)
  2. {
  3. (中略)
  4. if (sheet != 0) { /*从此开始*/
  5. cons.timer = timer_alloc();
  6. timer_init(cons.timer, &task->fifo, 1);
  7. timer_settime(cons.timer, 50);
  8. } /*到此结束*/
  9. (中略)
  10. for (;;) {
  11. io_cli();
  12. if (fifo32_status(&task->fifo) == 0) {
  13. task_sleep(task);
  14. io_sti();
  15. } else {
  16. (中略)
  17. if (256 <= i && i <= 511) { /*键盘数据(通过任务A)*/
  18. (中略)
  19. if (i == 8 + 256) {
  20. (中略)
  21. } else if (i == 10 + 256) {
  22. /*回车键*/
  23. /*用空白擦除光标后换行*/
  24. cons_putchar(&cons, ' ', 0);
  25. cmdline[cons.cur_x / 8 - 2] = 0;
  26. cons_newline(&cons);
  27. cons_runcmd(cmdline, &cons, fat, memtotal); /*执行命令*/
  28. if (sheet == 0) { /*从此开始*/
  29. cmd_exit(&cons, fat);
  30. } /*到此结束*/
  31. /*显示提示符*/
  32. cons_putchar(&cons, '>', 1);
  33. } else {
  34. (中略)
  35. }
  36. }
  37. /*重新显示光标*/
  38. if (sheet != 0) { /*从此开始*/
  39. if (cons.cur_c >= 0) {
  40. boxfill8(sheet->buf, sheet->bxsize, cons.cur_c,
  41. cons.cur_x, cons.cur_y, cons.cur_x + 7, cons.cur_y + 15);
  42. }
  43. sheet_refresh(sheet, cons.cur_x, cons.cur_y, cons.cur_x + 8, cons.cur_y + 16);
  44. } /*到此结束*/
  45. }
  46. }
  47. }

■■■■■

cmd_exit也需要修改一下,添加用于无命令行窗口情况下的任务结束处理。

本次的console.c节选

  1. void cmd_exit(struct CONSOLE *cons, int *fat)
  2. {
  3. struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
  4. struct TASK *task = task_now();
  5. struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4);
  6. struct FIFO32 *fifo = (struct FIFO32 *) *((int *) 0x0fec);
  7. if (cons->sht != 0) {
  8. timer_cancel(cons->timer);
  9. }
  10. memman_free_4k(memman, (int) fat, 4 * 2880);
  11. io_cli();
  12. if (cons->sht != 0) { /*从此开始*/
  13. fifo32_put(fifo, cons->sht - shtctl->sheets0 + 768); /* 768~1023 */
  14. } else {
  15. fifo32_put(fifo, task - taskctl->tasks0 + 1024); /*1024~2023*/
  16. } /*到此结束*/
  17. io_sti();
  18. for (;;) {
  19. task_sleep(task);
  20. }
  21. }

有命令行窗口时,我们可以通过图层的地址告诉task_a需要结束哪个任务,而无命令行窗口的情况下,这种方法就用不了了,因此在这里我们将TASK结构的地址告诉task_a。

■■■■■

接下来轮到bootpack.c了,首先来编写与open_constask相关的部分。

本次的bootpack.c节选

  1. struct TASK *open_constask(struct SHEET *sht, unsigned int memtotal)
  2. {
  3. struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
  4. struct TASK *task = task_alloc();
  5. int *cons_fifo = (int *) memman_alloc_4k(memman, 128 * 4);
  6. task->cons_stack = memman_alloc_4k(memman, 64 * 1024);
  7. task->tss.esp = task->cons_stack + 64 * 1024 - 12;
  8. task->tss.eip = (int) &console_task;
  9. task->tss.es = 1 * 8;
  10. task->tss.cs = 2 * 8;
  11. task->tss.ss = 1 * 8;
  12. task->tss.ds = 1 * 8;
  13. task->tss.fs = 1 * 8;
  14. task->tss.gs = 1 * 8;
  15. *((int *) (task->tss.esp + 4)) = (int) sht;
  16. *((int *) (task->tss.esp + 8)) = memtotal;
  17. task_run(task, 2, 2); /* level=2, priority=2 */
  18. fifo32_init(&task->fifo, 128, cons_fifo, task);
  19. return task;
  20. }
  21. struct SHEET *open_console(struct SHTCTL *shtctl, unsigned int memtotal)
  22. {
  23. struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
  24. struct SHEET *sht = sheet_alloc(shtctl);
  25. unsigned char *buf = (unsigned char *) memman_alloc_4k(memman, 256 * 165);
  26. sheet_setbuf(sht, buf, 256, 165, -1); /*无透明色*/
  27. make_window8(buf, 256, 165, "console", 0);
  28. make_textbox8(sht, 8, 28, 240, 128, COL8_000000);
  29. sht->task = open_constask(sht, memtotal);
  30. sht->flags |= 0x20; /*有光标*/
  31. return sht;
  32. }

到底修改了哪里呢?其实我们把之前open_console的一部分内容拿出来放到open_constask中了,正如把关闭命令行窗口的函数close_console中的一部分分离到close_constask中一样。

■■■■■

最后我们来修改HariMain,只要在结束命令行窗口任务的部分添加一些代码即可。

本次的bootpack.c节选

  1. void HariMain(void)
  2. {
  3. (中略)
  4. for (;;) {
  5. (中略)
  6. if (fifo32_status(&fifo) == 0) {
  7. (中略)
  8. } else {
  9. (中略)
  10. if (256 <= i && i <= 511) { /*键盘数据*/
  11. (中略)
  12. } else if (512 <= i && i <= 767) { /*鼠标数据*/
  13. (中略)
  14. } else if (768 <= i && i <= 1023) { /*命令行窗口关闭处理*/
  15. close_console(shtctl->sheets0 + (i - 768));
  16. } else if (1024 <= i && i <= 2023) { /*从此开始*/
  17. close_constask(taskctl->tasks0 + (i - 1024)); /*到此结束*/
  18. }
  19. }
  20. }
  21. }

呼,修改全部完成了,好累。

■■■■■

好了,我们来“make run”吧。首先试一下“ncst color”……撒花!成功了耶!碍眼的命令行窗口没有弹出来,画面上只有应用程序的窗口。开心之余,我们又运行了color2.hrb,当然,命令行窗口还是只有一个。

10 ncst命令(harib23j) - 图1

应用程序运行画面清清爽爽!

咦?用鼠标点击应用程序窗口的“×”按钮无法关闭窗口!用Shift+F1强制关闭也不行。这是怎么回事!不过,按回车键总算可以正常退出了,今晚就先这样将就一下吧。

话说,都已经半夜了,再不早点睡觉就要感冒了。大家晚安,这个bug我们留到明天解决吧。