操作系统-Lab3

准备

实验以《orange's:一个操作系统的实现》的代码为基础

运行

问题1

make image失败

解决方法

结果

问题2

make image结束之后,执行下面的命令失败

1
bochs -f bochsrc

报错信息

1
dlopen failed for module 'x': file not found

解决方法

1
sudo apt-get install bochs-x

结果显示

已实现和待实现

已实现

  1. 从屏幕左上角开始,以白色显示键盘输入的字符,可以输入并显示a-z, A-Z和0-9字符。
  2. 支持大小写切换包括 Shift 组合键以及大写锁定两种方式,大写锁定后再用 Shift 组合键将会输入小写字母
  3. 支持回车键换行
  4. 支持用退格键删除输入内容
  5. 支持空格键
  6. 有光标显示
  7. 输入字符无上限

待实现

理解代码

首先,需要理解代码,可以照着《orange's:一个操作系统的实现》第七章的讲解一起看。

输出一个字符的函数调用逻辑

当初始化结束后,就会进入到task_tty()函数中,进行不断的循环。

探究CONSOLE结构体中四个变量的含义

分析过程

屏幕一行80个字符,屏幕总共25行。

在敲字符过程中,cursor在不断加1original_addr始终为0x0current_start_addr当前屏幕可见范围的开始位置距离最开始显示位置的偏移。

按到最后

可以发现cursor的值最大只能到0x1554,因为被v_mem_limit所限制。

经过分析就可以基本确定CONSOLE结构体四个变量的含义,用一张图来表示一下

实现功能

TAB

keyboard.h中可以发现TAB是一个不可显示的字符,所以在tty.cin_process中要增加对于TAB的识别,将其放进缓冲区内。然后在console.cout_char函数中增加对\t的输出处理。

清屏

清屏的功能实现在逻辑上比较简单,只要不断地调用out_char()函数,传入\b,直到cursor回到original_addr位置。

但是如何在实现每20秒清屏一次呢?要理解kernel_main()函数中的任务,可以新增一个任务,task_clear_screen,然后在其中执行清屏任务,并且每次执行完毕后延迟20s。

1、将task_clear_screen声明成一个任务,不断执行

global.c中做相应修改,并修改对应的宏

2、在task_clear_screen任务中完成清屏逻辑,并且延迟20s

每个任务中while循环不能break,否则执行会报错。

退格一次完成

源代码的删除功能只实现了一个一个删除,即使是对于\n\t也是如此,不符合实际情况,需要做修改,实现一次删除\t\n

思路

要想实现一次退格,就需要知道前一个字符是什么,如果是普通字符那么让光标位置减一即可,如果是特殊的\n\t就需要特殊处理,使光标回到按下\n\t前的位置。

对于\t还好说,只要把光标减4即可;但是对于\n来说,就有点麻烦了。

一开始,想让光标一直往回移动直到遇到不是空格的字符。但是如果在输入\n之前刚输入了空格呢?这样显然就不对,而且实现起来还很复杂。

所以需要借助新的数据结构来存储已经显示的字符,并且对显示的字符做一个包装,做成一个结构体。

再构建一个存储当前屏幕中所有显示的字符的结构体

然后需要在适当的地方将这个数据结构插入

过程

1、初始化C_BUF结构体

2、在将字符放入TTY中的同时,也将封装起来的字符放进C_BUF中

3、out_char函数中实现对应逻辑

在其他输出字符的位置需要加上对CHAR结构体中before_cursor和after_cursor的赋值,例如:

然后在处理退格键时就可以用如下一段代码解决

4、显示字符结束后,需要修改C_BUF中的buf_cur_idx

这么设计就可以把所有的字符统一起来处理,在退格时只要回到按下该键前的光标位置即可。

注意需要把p_cbuf作为全局变量声明,这样可以在所有文件中使用,而不用作为函数参数传来传去。

在global.c和global.h中做声明即可

查找功能

思路

明确几个状态(代码也是依据状态编写的)

1、正常状态。以黑底白字显示字符,一切正常

2、搜索状态。在正常状态按下esc后,以黑底红字显示字符,并记录这段时间敲下的字符

3、匹配状态。搜索状态按下enter后,进行match,思路是从头遍历C_BUF结构体数组,找到匹配的字符串后把相应的字符颜色改成黑底红字,再从头显示

4、从匹配态退出。删去搜索字符串把黑底红字的改成黑底白字重新显示

过程

1、定义一些全局变量和常量,对CHAR结构体进行调整(增加color字段)

状态的变化

1
INIT(按ESC) -> SEARCH(按Enter) -> MATCH(按ESC) -> INIT

2、在每个状态编写相应逻辑

INIT

in_process函数中增加对ESC的识别

这个初始化要小心,每次进入搜索状态都要进行初始化

SEARCH

改变in_process中对Enter键的处理

MATCH

在in_process函数开头加上判断,只接收ESC

在out_char函数中也要做相应处理

1、MATCH状态下是不需要向C_BUF数组中增添CHAR的,只做输出。

2、SEARCH状态下要记录搜索字符串,并且注意SEARCH状态下是黑底红色。

注意:在退格搜索字符串时(SEARCH状态),不能将原来的字符串删除。

control+z撤销

这个也很简单,首先要判断出是否是按下ctrl+z组合键,然后执行退格操作即可。

似乎没有那么简单,因为既要撤销显示出来的字符,还要撤销删除,以及需要能够一直撤销直到初始状态。

想法1:再建立一个ACTION的列表,记录所有的操作。但是实现起来可能比较复杂,因为需要同步好几个数据结构数组之间的关系。

想法2:改造C_BUF数据结构。其实撤销的主要难点在于撤销退格,所以在C_BUF中使用两个指针。也不行,可操作性不高,指针移动比较复杂。

最终采用想法1,需要理清ACTION数组在什么位置更新!

1、创建数据结构

其中MAX_ACTION为1000,即支持大约1000次撤销。

2、初始化ACTION列表

在task_tty函数中调用初始化函数即可

3、向列表中增加ACTION

经过思考,选在tty_do_write函数的out_char后面

4、撤销操作

在in_process函数中增加以下逻辑,就是在判断出是Ctrl+z组合键后,回退ACTION数组,做逆操作。

注意虚拟机中的热键 VirtualBox默认是 Right Ctrl

导致Right Ctrl按不出来

总结

由于上面的描述是写完一个功能后立刻写下的,所以导致代码前后会出现不一致。

感觉十分重要的调整是 【将字符加进C_BUF结构体中buf 】的位置 和 【更新 C_BUF结构体中 buf_cur_idx】 的位置,最后是都放在了out_char函数中。


操作系统-Lab3
http://example.com/2022/11/21/nju-os-labs/OS-Lab3/
作者
zhc
发布于
2022年11月21日
许可协议