10 ncst命令(harib23j)
本节要进行今天的最后一项修改。
用start命令启动应用程序看起来很不错,但如果运行color这样的程序的话,我们并不希望真的新开一个命令行窗口出来,反倒是没有这个多余的窗口比较好。那么下面我们就来做一个不打开新命令行窗口的start命令吧,给它起个名字,叫做“no console start”,简称ncst命令。
这样,我们可以根据需要来选择用哪个命令:当希望运行程序的同时打开新的命令行窗口时,用start命令;而当不需要打开新的命令行窗口时,就用ncst命令。
不过,不打开命令行窗口而直接运行应用程序到底应该怎样实现呢?想来想去,总觉得要改的地方实在太多了,我们还是一步一步慢慢来吧。其实我们可以换个思路,不要一味去想“没有命令行窗口该怎样处理”,而可以“想办法禁止向命令行显示内容”(换句话说,用ncst命令启动的应用程序会忽略字符串显示API的调用)。
■■■■■
好了,我们先从添加ncst命令开始做起吧。
我们将没有窗口的命令行任务的cons—>sht规定为0。在没有窗口的情况下,执行mem命令和cls命令也没有用,因此我们将这些命令全部忽略。
本次的console.c节选
void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, int memtotal)
{
if (strcmp(cmdline, "mem") == 0 && cons->sht != 0) { /*从此开始*/
cmd_mem(cons, memtotal);
} else if (strcmp(cmdline, "cls") == 0 && cons->sht != 0) {
cmd_cls(cons);
} else if (strcmp(cmdline, "dir") == 0 && cons->sht != 0) {
cmd_dir(cons);
} else if (strncmp(cmdline, "type ", 5) == 0 && cons->sht != 0) { /*到此结束*/
cmd_type(cons, fat, cmdline);
} else if (strcmp(cmdline, "exit") == 0) {
cmd_exit(cons, fat);
} else if (strncmp(cmdline, "start ", 6) == 0) {
cmd_start(cons, cmdline, memtotal);
} else if (strncmp(cmdline, "ncst ", 5) == 0) { /*这里!*/
cmd_ncst(cons, cmdline, memtotal); /*这里!*/
} else if (cmdline[0] != 0) {
(中略)
}
void cmd_ncst(struct CONSOLE *cons, char *cmdline, int memtotal)
{
struct TASK *task = open_constask(0, memtotal);
struct FIFO32 *fifo = &task->fifo;
int i;
/*将命令行输入的字符串逐字复制到新的命令行窗口中*/
for (i = 5; cmdline[i] != 0; i++) {
fifo32_put(fifo, cmdline[i] + 256);
}
fifo32_put(fifo, 10 + 256); /*回车键*/
cons_newline(cons);
return;
}
cmd_ncst是照着cmd_start的样子写的,其中open_constask这个函数我们接下来会写在bootpack.c中。
■■■■■
当cons—>sht为0时,要禁用命令行窗口的字符显示等所有操作,因此我们需要修改与其相关的函数。
本次的console.c节选
void cons_putchar(struct CONSOLE *cons, int chr, char move)
{
(中略)
if (s[0] == 0x09) { /*制表符*/
for (;;) {
if (cons->sht != 0) { /*从此开始*/
putfouts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, " ", 1);
} /*到此结束*/
cons->cur_x += 8;
(中略)
}
} else if (s[0] == 0x0a) { /*换行*/
cons_newline(cons);
} else if (s[0] == 0x0d) { /*回车*/
/*不执行任何操作*/
} else { /*一般字符*/
if (cons->sht != 0) { /*从此开始*/
putfouts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, s, 1);
} /*到此结束*/
if (move != 0) {
(中略)
}
}
return;
}
void cons_newline(struct CONSOLE *cons)
{
int x, y;
struct SHEET *sheet = cons->sht;
if (cons->cur_y < 28 + 112) {
cons->cur_y += 16; /*到下一行*/
} else {
/*滚动*/
if (sheet != 0) { /*这里!*/
for (y = 28; y < 28 + 112; y++) {
(中略)
}
for (y = 28 + 112; y < 28 + 128; y++) {
(中略)
}
sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128);
} /*这里!*/
}
cons->cur_x = 8;
return;
}
本以为相关的函数很多,所以要改动的地方也会很多,不过这么一看其实也没多少嘛。
■■■■■
接下来我们来修改console_task。修改的要点是,当不显示命令行窗口时,禁用一些不必要的处理,并且当命令执行完毕时,立即结束命令行窗口任务(应用程序运行完毕后,这个命令行窗口任务就派不上什么用场了。因为画面上不显示命令行窗口,也就无法输入其他命令,也不能执行关闭操作,所以我们需要使其在命令执行完毕时自动终止任务)。
本次的console.c节选
void console_task(struct SHEET *sheet, int memtotal)
{
(中略)
if (sheet != 0) { /*从此开始*/
cons.timer = timer_alloc();
timer_init(cons.timer, &task->fifo, 1);
timer_settime(cons.timer, 50);
} /*到此结束*/
(中略)
for (;;) {
io_cli();
if (fifo32_status(&task->fifo) == 0) {
task_sleep(task);
io_sti();
} else {
(中略)
if (256 <= i && i <= 511) { /*键盘数据(通过任务A)*/
(中略)
if (i == 8 + 256) {
(中略)
} else if (i == 10 + 256) {
/*回车键*/
/*用空白擦除光标后换行*/
cons_putchar(&cons, ' ', 0);
cmdline[cons.cur_x / 8 - 2] = 0;
cons_newline(&cons);
cons_runcmd(cmdline, &cons, fat, memtotal); /*执行命令*/
if (sheet == 0) { /*从此开始*/
cmd_exit(&cons, fat);
} /*到此结束*/
/*显示提示符*/
cons_putchar(&cons, '>', 1);
} else {
(中略)
}
}
/*重新显示光标*/
if (sheet != 0) { /*从此开始*/
if (cons.cur_c >= 0) {
boxfill8(sheet->buf, sheet->bxsize, cons.cur_c,
cons.cur_x, cons.cur_y, cons.cur_x + 7, cons.cur_y + 15);
}
sheet_refresh(sheet, cons.cur_x, cons.cur_y, cons.cur_x + 8, cons.cur_y + 16);
} /*到此结束*/
}
}
}
■■■■■
cmd_exit也需要修改一下,添加用于无命令行窗口情况下的任务结束处理。
本次的console.c节选
void cmd_exit(struct CONSOLE *cons, int *fat)
{
struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
struct TASK *task = task_now();
struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4);
struct FIFO32 *fifo = (struct FIFO32 *) *((int *) 0x0fec);
if (cons->sht != 0) {
timer_cancel(cons->timer);
}
memman_free_4k(memman, (int) fat, 4 * 2880);
io_cli();
if (cons->sht != 0) { /*从此开始*/
fifo32_put(fifo, cons->sht - shtctl->sheets0 + 768); /* 768~1023 */
} else {
fifo32_put(fifo, task - taskctl->tasks0 + 1024); /*1024~2023*/
} /*到此结束*/
io_sti();
for (;;) {
task_sleep(task);
}
}
有命令行窗口时,我们可以通过图层的地址告诉task_a需要结束哪个任务,而无命令行窗口的情况下,这种方法就用不了了,因此在这里我们将TASK结构的地址告诉task_a。
■■■■■
接下来轮到bootpack.c了,首先来编写与open_constask相关的部分。
本次的bootpack.c节选
struct TASK *open_constask(struct SHEET *sht, unsigned int memtotal)
{
struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
struct TASK *task = task_alloc();
int *cons_fifo = (int *) memman_alloc_4k(memman, 128 * 4);
task->cons_stack = memman_alloc_4k(memman, 64 * 1024);
task->tss.esp = task->cons_stack + 64 * 1024 - 12;
task->tss.eip = (int) &console_task;
task->tss.es = 1 * 8;
task->tss.cs = 2 * 8;
task->tss.ss = 1 * 8;
task->tss.ds = 1 * 8;
task->tss.fs = 1 * 8;
task->tss.gs = 1 * 8;
*((int *) (task->tss.esp + 4)) = (int) sht;
*((int *) (task->tss.esp + 8)) = memtotal;
task_run(task, 2, 2); /* level=2, priority=2 */
fifo32_init(&task->fifo, 128, cons_fifo, task);
return task;
}
struct SHEET *open_console(struct SHTCTL *shtctl, unsigned int memtotal)
{
struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
struct SHEET *sht = sheet_alloc(shtctl);
unsigned char *buf = (unsigned char *) memman_alloc_4k(memman, 256 * 165);
sheet_setbuf(sht, buf, 256, 165, -1); /*无透明色*/
make_window8(buf, 256, 165, "console", 0);
make_textbox8(sht, 8, 28, 240, 128, COL8_000000);
sht->task = open_constask(sht, memtotal);
sht->flags |= 0x20; /*有光标*/
return sht;
}
到底修改了哪里呢?其实我们把之前open_console的一部分内容拿出来放到open_constask中了,正如把关闭命令行窗口的函数close_console中的一部分分离到close_constask中一样。
■■■■■
最后我们来修改HariMain,只要在结束命令行窗口任务的部分添加一些代码即可。
本次的bootpack.c节选
void HariMain(void)
{
(中略)
for (;;) {
(中略)
if (fifo32_status(&fifo) == 0) {
(中略)
} else {
(中略)
if (256 <= i && i <= 511) { /*键盘数据*/
(中略)
} else if (512 <= i && i <= 767) { /*鼠标数据*/
(中略)
} else if (768 <= i && i <= 1023) { /*命令行窗口关闭处理*/
close_console(shtctl->sheets0 + (i - 768));
} else if (1024 <= i && i <= 2023) { /*从此开始*/
close_constask(taskctl->tasks0 + (i - 1024)); /*到此结束*/
}
}
}
}
呼,修改全部完成了,好累。
■■■■■
好了,我们来“make run”吧。首先试一下“ncst color”……撒花!成功了耶!碍眼的命令行窗口没有弹出来,画面上只有应用程序的窗口。开心之余,我们又运行了color2.hrb,当然,命令行窗口还是只有一个。
应用程序运行画面清清爽爽!
咦?用鼠标点击应用程序窗口的“×”按钮无法关闭窗口!用Shift+F1强制关闭也不行。这是怎么回事!不过,按回车键总算可以正常退出了,今晚就先这样将就一下吧。
话说,都已经半夜了,再不早点睡觉就要感冒了。大家晚安,这个bug我们留到明天解决吧。