5 mem命令(harib15e)
之前我们已经成功实现了屏幕滚动,现在该是到了让它执行命令的时候了。不过这值得纪念的第一个命令到底该花落谁家呢?纠结了一番之后,还是决定来做mem命令吧。
mem命令就是memory的缩写,也就是用来显示内存使用情况的命令。画面上虽然已经显示了剩余内存,不过现在被命令行窗口挡住看不见了。因此我们就不让它继续显示了,改成用命令来查询好了。
而且,这种功能对于一个命令来说也是很容易实现的,比起之前在背景上面显示剩余内存来说,还是用命令来查询比较像个操作系统的样子。既然如此,那我们干脆顺便把按键编码、鼠标坐标的显示也一起去掉吧。
■■■■■
既然方针已定,那就开工吧。首先从去掉多余的显示开始,这个非常容易,我们给这次去掉的行加上了“//”注释标记。
本次的bootpack.c节选
void HariMain(void)
{
(中略)
// sprintf(s, "(%3d, %3d)", mx, my);
// putfonts8_asc_sht(sht_back, 0, 0, COL8_FFFFFF, COL8_008484, s, 10);
// sprintf(s, "memory %dMB free : %dKB",
// memtotal / (1024 * 1024), memman_total(memman) / 1024);
// putfonts8_asc_sht(sht_back, 0, 32, COL8_FFFFFF, COL8_008484, s, 40);
(中略)
for (;;) {
(中略)
if (fifo32_status(&fifo) == 0) {
(中略)
} else {
(中略)
if (256 <= i && i <= 511) { /*键盘数据 */
// sprintf(s, "%02X", i - 256);
// putfonts8_asc_sht(sht_back, 0, 16, COL8_FFFFFF, COL8_008484, s, 2);
(中略)
} else if (512 <= i && i <= 767) { /*鼠标数据*/
if (mouse_decode(&mdec, i - 512) != 0) {
// /*数据已达到3个字节,显示*/
// sprintf(s, "[lcr %4d %4d]", mdec.x, mdec.y);
// if ((mdec.btn & 0x01) != 0) {
// s[1] = 'L';
// }
// if ((mdec.btn & 0x02) != 0) {
// s[3] = 'R';
// }
// if ((mdec.btn & 0x04) != 0) {
// s[2] = 'C';
// }
// putfonts8_asc_sht(sht_back, 32, 16, COL8_FFFFFF, COL8_008484, s, 15);
(中略)
// sprintf(s, "(%3d, %3d)", mx, my);
// putfonts8_asc_sht(sht_back, 0, 0, COL8_FFFFFF, COL8_008484, s, 10);
(中略)
}
} else if (i <= 1) { /*光标用定时器*/
(中略)
}
}
}
}
噢噢,代码居然减少了21行,真不错呢。不过接下来我们要实现mem命令,行数又会变多啦。
■■■■■
增加了mem命令的部分后,就变成了这样。
本次的bootpack.c节选
void console_task(struct SHEET *sheet, unsigned int memtotal)
{
(中略)
char s[30], cmdline[30]; /*这里!*/
struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; /*这里! */
(中略)
for (;;) {
io_cli();
if (fifo32_status(&task->fifo) == 0) {
(中略)
} else {
(中略)
if (256 <= i && i <= 511) { /*键盘数据(通过任务A) */
if (i == 8 + 256) {
/*退格键*/
(中略)
} else if (i == 10 + 256) {
/*回车键*/
/*将光标用空格擦除后换行*/
putfonts8_asc_sht(sheet, cursor_x, cursor_y, COL8_FFFFFF, COL8_000000, " ", 1);
/*从此开始 */ cmdline[cursor_x / 8 - 2] = 0;
cursor_y = cons_newline(cursor_y, sheet);
/*执行命令*/
if (cmdline[0] == 'm' && cmdline[1] == 'e' && cmdline[2] == 'm' && cmdline[3] == 0) {
/* mem命令*/
sprintf(s, "total %dMB", memtotal / (1024 * 1024));
putfonts8_asc_sht(sheet, 8, cursor_y, COL8_FFFFFF, COL8_000000, s, 30);
cursor_y = cons_newline(cursor_y, sheet);
sprintf(s, "free %dKB", memman_total(memman) / 1024);
putfonts8_asc_sht(sheet, 8, cursor_y, COL8_FFFFFF, COL8_000000, s, 30);
cursor_y = cons_newline(cursor_y, sheet);
cursor_y = cons_newline(cursor_y, sheet);
} else if (cmdline[0] != 0) {
/*不是命令,也不是空行 */
putfonts8_asc_sht(sheet, 8, cursor_y, COL8_FFFFFF, COL8_000000, "Bad
command.", 12);
cursor_y = cons_newline(cursor_y, sheet);
cursor_y = cons_newline(cursor_y, sheet);
/*到此结束*/ }
/*显示提示符*/
putfonts8_asc_sht(sheet, 8, cursor_y, COL8_FFFFFF, COL8_000000, ">", 1);
cursor_x = 16;
} else {
/*一般字符*/
if (cursor_x < 240) {
/*显示一个字符之后将光标后移一位 */
s[0] = i - 256;
s[1] = 0;
/*这里! */ cmdline[cursor_x / 8 - 2] = i - 256;
putfonts8_asc_sht(sheet, cursor_x, cursor_y, COL8_FFFFFF, COL8_000000, s,1);
cursor_x += 8;
}
}
}
(中略)
}
}
}
介绍一下重点。首先我们添加了memtotal和memman两个变量,它们是执行mem命令所必需的。关于memtotal,我们采用和sheet相同的方法从HariMain传递过来,因此我们还需要改写一下HariMain。
本次的bootpack.c节选
void HariMain(void)
{
(中略)
/* sht_cons */
sht_cons = sheet_alloc(shtctl);
(中略)
task_cons->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024 - 12; /*这里! */
(中略)
*((int *) (task_cons->tss.esp + 4)) = (int) sht_cons;
*((int *) (task_cons->tss.esp + 8)) = memtotal; /*这里! */
(中略)
}
回来继续讲解console_task,我们还添加了一个cmdline变量,也就是“命令行”(command line)的缩写。这个变量用来记录通过键盘输入的内容,在“键盘数据”处理的“一般字符”部分,将输入的内容顺次累积起来。
然后,处理回车键输入的部分我们已经完全改写了。在这里出现的cons_newline是一个用来换行的函数,当到达最后一行的时候还会自动滚动。如果把换行处理直接写在程序中会导致代码非常难读,因此我们把它做成了一个单独的函数,函数的内容如下。
本次的bootpack.c节选
int cons_newline(int cursor_y, struct SHEET *sheet)
{
int x, y;
if (cursor_y < 28 + 112) {
cursor_y += 16; /*换行*/
} else {
/*滚动*/
for (y = 28; y < 28 + 112; y++) {
for (x = 8; x < 8 + 240; x++) {
sheet->buf[x + y * sheet->bxsize] = sheet->buf[x + (y + 16) * sheet->bxsize];
}
}
for (y = 28 + 112; y < 28 + 128; y++) {
for (x = 8; x < 8 + 240; x++) {
sheet->buf[x + y * sheet->bxsize] = COL8_000000;
}
}
sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128);
}
return cursor_y;
}
这里应该没有什么难点,我们继续回到console_task。
当按下回车键时,换行后程序会读取cmdline的值,分析所输入的内容。如果输入的内容为“mem”,则执行mem命令,显示内存的相关信息;如不为“mem”,程序无法理解这个命令,则显示“Bad command”错误信息。不过,在什么都不输入的情况下按回车键不会显示错误信息,也不会执行什么操作。
我们的系统能够出现错误信息了,看上去是不是超有操作系统范儿呢?笔者认为错误信息特别有操作系统的感觉,于是就给加上去啦(笑)。
讲解到此结束。
■■■■■
我们来运行一下,“make run”,然后输入一些东西试试看。结果如下。
哇,好酷!
天啊,这实在是酷毙了!操作系统的感觉大幅上升,真是越来越有干劲了!