发布于 

30天自制操作系统(19)

DAY19_应用程序

1.type命令

  • 在Windows的命令行中,有一个叫做type的命令,输入“type 文件名”就会显示出文件的内容。

磁盘映像中的地址 = clustno * 512 + 0x003e00

  • 将s[0~10]这11个字节用空格的字符编码填充,然后读取cmdline[5~]并复制到s[0~],在复制的同时,将其中的小写字母转换为大写字母。随后,当遇到句点时,则可以断定接下来的部分为扩展名,于是将复制的目标改为s[8~]。经过这样的转换,我们就得到了和磁盘内格式相同的文件名。
  • “寻找文件”这一段中,我们在磁盘中寻找与所输入的文件名相符的文件。如果成功找到指
    定文件,则用break跳出for循环;如果找不到,则会在x到达224或者finfo[x].name[0]为0x00时结束循环。
/* type命令*/ 
/*准备文件名*/
for (y = 0; y < 11; y++) {
s[y] = ' ';
}
y = 0;
for (x = 5; y < 11 && cmdline[x] != 0; x++) {
if (cmdline[x] == '.' && y <= 8) {
y = 8;
} else {
s[y] = cmdline[x];
if ('a' <= s[y] && s[y] <= 'z') {
/*将小写字母转换成大写字母 */
s[y] -= 0x20;
}
y++;
}
}
/*寻找文件*/
for (x = 0; x < 224; ) {
if (finfo[x].name[0] == 0x00) {
break;
}
if ((finfo[x].type & 0x18) == 0) {
for (y = 0; y < 11; y++) {
if (finfo[x].name[y] != s[y]) {
goto type_next_file;
}
}
break; /*找到文件*/
}
type_next_file:
x++;
}
if (x < 224 && finfo[x].name[0] != 0x00) {
/*找到文件的情况*/
y = finfo[x].size;
p = (char *) (finfo[x].clustno * 512 + 0x003e00 + ADR_DISKIMG);
cursor_x = 8;
for (x = 0; x < y; x++) {
/*逐字输出*/
s[0] = p[x];
s[1] = 0;
putfonts8_asc_sht(sheet, cursor_x, cursor_y, COL8_FFFFFF, COL8_000000, s, 1);
cursor_x += 8;
if (cursor_x == 8 + 240) { /*到达最右端后换行*/
cursor_x = 8;
cursor_y = cons_newline(cursor_y, sheet);
}
}
} else {
/*没有找到文件的情况*/
putfonts8_asc_sht(sheet, 8, cursor_y, COL8_FFFFFF, COL8_000000, "File
not found.", 15);
cursor_y = cons_newline(cursor_y, sheet);
}

2.type命令改良

  • 目标:实现对换行的支持。

    0x09……制表符:显示空格直到 x 被 4 整除为止
    0x0a……换行符:换行
    0x0d……回车符:忽略
  • 我们这里所说的制表符也称为水平制表符(horizonal tab),因为对齐字符位置是在水平方向上移动。相对的,还有一种垂直制表符(vertical tab)

  • 在Windows中换行的字符编码为“0x0d 0x0a”两个字节,而Linux中只有“0x0a”一个字节。
    • 字符编码0x0a原本代表折行(line feed)的意思,即只是移动到下一行。
    • 0x0d,也就是回车符的文字编码,代表“让打印头(或者打字机的辊筒)回到行首”的意思,因此才被称为“回车”(carriage return)。

3.对FAT的支持

  • 现在的type命令,肯定可以正确显示文件开头的512个字节的内容,但是如果遇到大于512个字节的文件,中间可能就会突然显示出其他文件的内容。
  • 对于文件的下一段存放在哪里,在磁盘中是有记录的,我们只要分析这个记录,就可以正确读取文件内容了。
  • 它位于从0柱面、0磁头、2扇区开始的9个扇区中,在磁盘映像中相当于0x000200~0x0013ff。这个记录被称为FAT,是“file allocation table”的缩写,翻译过来叫作“文件分配表”(即记录文件在磁盘中存放位置的表)。

4.代码整理

  • 窗口相关函数 → window.c
  • 命令行窗口相关函数 → console.c
  • 文件相关函数 → file.c

5.第一个应用程序

[BITS 32] 
fin:
HLT
JMP fin

  • 像type命令一样,我们用file_loadfile将文件的内容读到内存中
  • 应用程序不知道自己被读到哪个内存地址,这里暂且由ORG0来生成。因此,为了应用程序能够顺利运行,我们需要为其创建一个内存段。
  • 段创建好之后,接下来只要goto到该段中的程序,程序应该就会开始运行了。要goto到其他的内存段,在汇编语言中用farjmp指令。
    for (y = 0; y < 11; y++) { 
    s[y] = ' ';
    }
    s[0] = 'H';
    s[1] = 'L';
    s[2] = 'T';
    s[8] = 'H';
    s[9] = 'R';
    s[10] = 'B';
    for (x = 0; x < 224; ) {
    if (finfo[x].name[0] == 0x00) {
    break;
    }
    if ((finfo[x].type & 0x18) == 0) {
    for (y = 0; y < 11; y++) {
    if (finfo[x].name[y] != s[y]) {
    goto hlt_next_file;
    }
    }
    break; /*找到文件*/
    }
    hlt_next_file:
    x++;
    }
    if (x < 224 && finfo[x].name[0] != 0x00) {
    /*找到文件的情况*/
    p = (char *) memman_alloc_4k(memman, finfo[x].size);
    file_loadfile(finfo[x].clustno, finfo[x].size, p, fat, (char *)
    (ADR_DISKIMG + 0x003e00));
    set_segmdesc(gdt + 1003, finfo[x].size - 1, (int) p, AR_CODE32_ER);
    farjmp(0, 1003 * 8);
    memman_free_4k(memman, (int) p, finfo[x].size);
    } else {
    /*没有找到文件的情况*/
    putfonts8_asc_sht(sheet, 8, cursor_y, COL8_FFFFFF, COL8_000000, "File
    not found.", 15);
    cursor_y = cons_newline(cursor_y, sheet);
    }
    /*到此结束*/