zenglOX v2.2.0 ee(easy editor)文本编辑器 C标准库函数 uheap(单独的用户堆空间) atapi驱动BUG zenglfs文件系统BUG 分页BUG 堆算法BUG等修复

先按照上一个v2.0.0版本的要求, 编译好bochs，让其支持e1000网卡,
将源代码解压后, 执行make和make iso命令, 分别得到initrd.img, zenglOX.bin及zenglOX.iso文件,
在root权限下运行startBochs来启动bochs虚拟机, 如果执行失败, 可能是bochsrc.txt配置不正确,
具体原因请参考v2.0.0的官方文章

启动好虚拟机后, 先进行分区格式化操作, 因为当前版本里的ee文本编辑器和它所依赖的
libc.so(包含一些C标准的库函数)的体积都比较大, 没有放在ramdisk里, 而是放在光盘镜像里,
需要通过下面要介绍的isoget命令来获取这两个文件到磁盘中, 然后从磁盘里启动运行。
分区格式化的相关操作, 请参考zenglOX v1.5.0版本对应的官方文章。

(如果是将生成的iso镜像放置到VirtualBox或VMware的虚拟机里, 并且在之前的版本,
你已经格式化了一个分区的话, 最好还是用format命令重新格式化一下, 因为当前版本
对zenglfs文件系统进行了BUG修复, 尽管理论上, 不重新格式化也可以正常使用,
但是重新格式化一下, 不容易出问题)

假设你的分区位于0号ide磁盘设备的1号分区里, 则输入如下命令来分别挂载光盘和磁盘分区:

zenglOX> mount iso
mount iso to [iso] success! you can use "ls iso".....
zenglOX> mount hd 0 1
mount to [hd] success! you can use "ls hd" to see.....

当挂载iso和hd成功后, 就可以使用isoget命令来获取ee编辑器和libc.so库文件到磁盘中:

zenglOX> isoget -all
copy content of iso/EXTRA/EE.;1 to hd/bin/ee success
copy content of iso/EXTRA/LIBC.SO;1 to hd/lib/libc.so success

上面的isoget -all命令执行时, 它会在内部调用file命令将iso的EXTRA目录内的EE.;1文件拷贝
到hd/bin目录内, 对应文件名为ee , 同理通过file命令将iso里的LIBC.SO;1文件拷贝到
hd/lib目录内，对应文件名为libc.so (这里要注意的是光盘镜像里的文件名有自己特殊的文件名格式
,比如都以;1结尾, 详情请参考zenglOX v1.2.0 ISO 9660文件系统对应的官方文章)

现在就可以使用ee编辑器来编辑文本文件了, 你可以给它输入一个文件名参数, 让它
去编辑该文件, 也可以啥参数也不输入, 在没输入任何参数的情况下, 它会将编辑的内容
保存到hd/Notes的默认文件中。

为了能全面的测试ee编辑器的所有功能, 我们下面还是以一个内容较多的文本文件为例来进行说明。

先通过file命令将iso里的测试用的ee.c文件拷贝到hd目录内:

zenglOX> file iso/EE.C;1 hd/ee.c
copy content of iso/EE.C;1 to hd/ee.c success
zenglOX>

上面的命令将iso里的EE.C;1文件拷贝到了hd目录里, 对应文件名为ee.c

下面就用ee来打开该文本文件(文件的内容是ee编辑器在开发过程中的v1.0.0版本的源代码)

zenglOX> ee hd/ee.c

上面命令执行时, shell会在内部自动在ee前面加上hd/bin/ , 因此完整的命令其实是
hd/bin/ee hd/ee.c , shell在当前版本里会自动在hd/bin目录内搜索可执行文件名,
这样, 我们就可以直接输入ee来启动编辑器了。

执行上面命令后, 就可以看到hd/ee.c里的内容了, 其显示界面类似如下所示:
 hd/ee.c     ....tp.. Line 1    Col 1     F1-Help F2-switch line col show
 #include <stdlib.h>

 #define EE_MAJOR_VERSION 1
 #define EE_MINOR_VERSION 0
 #define EE_REVISION 0

 #define EOL '\0' /* end of line marker */
 #define BLK ' ' /* blank */
 #define LF  '\n' /* new line */
 #define NLEN  80 /* buffer line for file name */
 #define LMAX  10000 /* max line length */
 #define XINC  20    /* increament of x */
 #define HLP 28

 .......................

内容较多, 1000多行, 因此, 这里就不全显示了。
其中第一行由几个部分组成:
1) 文件名(如上面的hd/ee.c),
2) 各种flag标志(例如上面的....tp..)
3) note区域(可以显示行列号等信息), note区域里一开始显示了当前光标的行列号,
   并提示用户可以按F1键来查看帮助信息

按F1键后, 可以看到如下所示的帮助信息:

Usage: ee [-+line(def=1) -lcol(def=1) -ttab(def=8) file(def=hd/Notes)]

ctrl+a: goto file bottom    ctrl+A: goto file top
ctrl+b: set block mark      ctrl+c: block copy
ctrl+d: block delete        ctrl+e: case sensitive for search
ctrl+f: forward search      ctrl+F: backward search
ctrl+g: goto line           ctrl+i: show status
ctrl+l: goto col            ctrl+m: line format
ctrl+q: forward tab move    ctrl+r: replace
ctrl+R: replace all         ctrl+s: save file
ctrl+t: switch tab mode     ctrl+v: block paste
ctrl+w: backward tab move   ctrl+x: block cut
ctrl+z: exit                ctrl+Backspace: backspace and delete tab
F1 key: show help           F2 key: switch line col show
Home key: goto line begin   End key: goto line end
Left key: cursor left       Right key: cursor right
Up key: cursor up           Down key: cursor down
Page Up key: page up        Page Down key: page down
Backspace key: backspace    Enter key: newline
Delete key: delete char     Insert key: insert mode
ESC+z: exit\n\r\
please note that you must use left ctrl key , not right ctrl!\n\r\
and the control letter is case sensitive!\n\r\
Press any key to continue ...

从上面的帮助信息里, 可以看到其功能还是很全面的, 虽然ee还不能与vi编辑器相比,
但是对于普通的文本编辑(脚本代码编辑)来说, 该有的都有了。
(ee源于FreeBSD系统, 由于其代码相当标准, 也非常小, 很适合移植, 所以作者就将其
移植到了zenglOX里, 同时对其按键和部分功能做了些调整, 并修复一些BUG)

通过帮助可以看到, ctrl+a组合可以跳转到文件的最后一行, ctrl+A组合可以
跳到文件的第一行。

这里要注意大小写, ctrl后面的控制字符都是case sensitive(区分大小写)的,
你可以通过Caps Lock(大小写锁键)来切换字母的大小写状态,
也可以在按键a为小写时, 通过ctrl+shift+a来达到ctrl+A的效果, 因为shift键可以
临时切换大小写的状态。

在进行复制, 剪切, 块删除操作时, 必须先用ctrl+b组合来设置块的起始位置,
然后在块的结束位置执行ctrl+c(拷贝)或者ctrl+x(剪切)或者ctrl+d(块删除)命令,
这里的块指的是你要操作的一块连续的字符区域(这块区域内可以包含任意字符,包括空格,
回车,换行等)。例如, 你要复制下面两行内容的话:

FILE  *fi = 0, *fo = 0;
MWIN  win, winnext, wincopy; /* current, next, other windows */

先将光标通过上下左右键或者通过稍候要提到的ctrl+q,ctrl+w,Home之类的按键,
移动到FILE的第一个字符F处, 在该处按下ctrl+b组合(该组合按下时,头部的note区域会显示
Mark Set, press any key to continue的提示),
再将光标移动到第二行的结束位置处, 在光标位于第二行时, 可以用End键来移动到
行尾, 在行尾位置处使用ctrl+c的组合(该组合按下时note区域会显示
Block copied [size:87], press any key to continue 的提示, 在该提示里还包含
了Block块的size尺寸即字符数信息, 你可以通过该信息来粗略的判断一下是否拷贝正确,
如果字符数信息和你要拷贝的内容感觉差距过大的话, 就说明你可能拷贝到了别的你不需要的数据了。

根据提示, 按任意键继续, 这样你就复制好了, 接着将光标移动到你要粘贴的地方,
执行ctrl+v的组合即可。

块剪切和块删除操作都是同理(块删除只执行删除操作, 不需要后续的ctrl+v的粘贴操作)。

这里, 同样要注意控制字符的大小写, 如果你发现某功能按下没反应时, 很可能就是
大小写的问题

通过ctrl+f与ctrl+F组合可以执行字符串的查找操作, 其中ctrl+f组合用于
从当前光标位置处向前查找, ctrl+F组合则进行向后查找。

通过ctrl+e组合可以设置字符串查找时, 是否区分大小写, 当第一次按下ctrl+e组合
时, 头部的flag标志区域里会显示出一个c字符, 头部类似如下显示：
hd/ee.c      ...ctp..
这个tp旁边多出来的c字符表示现在区分大小写, 那么查找操作时就会区分大小写,
再次按下ctrl+e组合时, 该c字符就会变回.(即小数点符号), 这样查找和替换操作时
就不会区分大小写了。

通过ctrl+r与ctrl+R组合可以执行字符串的替换操作, 这里需要注意的是
字符串的替换是根据查找操作来的, 必须先通过ctrl+f之类的组合查找定位到
要替换的字符串, 然后再执行替换操作, ctrl+r组合只执行一次替换操作,
ctrl+R组合则可以将当前光标位置处到文件结尾之间的所有的查找字符串
都进行替换操作(如果执行替换操作时, 光标不位于查找字符串的开头位置时,
note区域会显示Invalid Pos, must search first的提示, 就是告诉用户必须先进行
查找定位的操作)。

通过ctrl+g组合可以跳到指定的行, 输入行号时, 最多只能输入5个数字, 因为后面
会介绍到, ee编辑器有个字符容量限制。

通过ctrl+l组合可以跳到指定的列, 同样最多输入5个数字, 最大列数为10000

这里要注意的是, ee编辑器编辑文本时是不word wrap的, 当一行文本超过
75列时, 多出的文本内容会位于隐藏的视图区域, 需要通过上下左右键或ctrl+q, ctrl+w
之类的按键来移动到该视图区域中。

如果你想让很长的一行文本都位于第一个视图区域的话, 可以将光标移动到该行,
然后按下ctrl+m的组合, 该组合可以对该行文本进行格式化, 也就是通过自动换行,
让他由一行很长的文本, 变为多个小于75个字符的行。

通过ctrl+i组合可以查看一些文本统计信息, 例如总行数, 总字符数, 可容纳的最大
字符数等 (可容纳的最大字符数目前为851968个字符, 当你的文本字符数超过这个
容量时, 就会显示出Main buffer full的错误, 然后退出程式)。

通过ctrl+q和ctrl+w组合可以快速的向前和向后移动, ctrl+q的组合可以让光标向前
移动到下一个tab的边界(一个tab的边界是: 当某个列位置除以tab宽度, 得到余数为1时,
那么该列位置就是一个tab边界),
ctrl+w组合可以向后移动到上一个tab边界处。
(tab的宽度可以在执行ee程式时, 通过-t参数来指定, 下面会提到)。

ctrl+t组合可以切换tab模式, 当文本文件里存在'\t'的tab字符时, 默认就会启用
tab模式, 可以在头部的flag标志区域里看到一个t字符, 类似如下所示：
hd/ee.c     ....tp..
上面的t字符就表示当前处于tab模式, ctrl+t组合可以切换这种模式, 也就是说
如果当前是tab模式, ctrl+t就会取消tab模式, 当取消时, flag标志区域里的t字符就会
变为.(即小数点符号), 所谓tab模式, 是指ee编辑器会在保存文件时, 将位于tab
边界处的连续的空格符压缩为一个'\t'字符, 这里还有一点需要注意的是,
ee编辑器在打开文本文件时, 会自动将文件里的'\t'字符转换为空格符, 之所以这么
做, 是因为只有这样才能有效控制'\t'字符在显示时的tab边界效果, 才不会受到终端
对'\t'字符显示的影响, 在一定程度上也方便文本的编辑。

在非tab模式下, ee编辑器保存文件时, 就不会将tab边界处的连续的空格压缩为tab符,
这样非tab模式下保存的文本里就不会再包含任何\t字符了。

ctrl+s组合可以在不退出ee的情况下保存文件内容, ctrl+s组合保存文件内容时,
会先将文件内容保存到磁盘, 然后再重新执行一次读操作, 这样就可以确保文件
里的'\t'字符能够得到正确的处理。

ctrl+z组合可以退出ee编辑器, 当文本内容被修改时, flag标志区域中会显示
一个|即竖杠字符, 类似如下所示：
hd/ee.c    |...tp..

当ctrl+s保存文件时, 该竖杠字符就会变回.即小数点字符。
ctrl+z组合退出ee时, 如果文件内容被修改过, 则头部note区域会显示
Save file(yes/no/cancel)的提示, 通过输入y来保存文件并退出ee, 通过输入
n来不保存而退出ee, 通过输入c来取消退出操作。

通过F2键, 可以切换头部是否显示行列号信息, 默认一开始是显示行列号的, 在
头部flag标志区域会有个p字符, 表示当前note区域显示行列号, 当按下F2时,
p字符会变为.即小数点字符, 同时note区域的行列号信息会消失, 再次按下F2时,
p字符又会出现, 同时note区域的行列号信息又会显示出来。

Home和End键可以跳到当前行的开头和当前行的结束位置。

上下左右键可以移动光标位置。

PageUp键向上跳转一页。
PageDown键向下跳转一页。

Backspace退格符可以向后删除一个字符, ctrl+Backspace的组合则可以向后退一个
tab边界, 当然退一个tab边界的前提是当前光标移动的方向是空格符组成的情况,
对于非空格的普通字符, ctrl+Backspace与Backspace是一样的效果。
比如你按下了tab键, 向前产生了一个tab边界, 那么ctrl+Backspace就可以向后删掉
该tab边界, 而Backspace则只能一个个字符的删除。

Enter键产生一个新行。

Delete键删除当前光标位置处的字符。

Insert键设置为insert插入模式, 该模式下输入的字符会覆盖掉当前光标处的原来的字符。
插入模式下, flag标志区域里会显示一个o字符, 类似如下所示:
hd/ee.c      |.o.tp..
再次按下Insert可以取消插入模式, o字符就会变回小数点符号

ESC+z的组合也可以退出ee编辑器, 与ctrl+z不同的是, ESC和z不需要同时按下,
ctrl+z的组合则是ctrl键处于按下状态时, 按z键(当然z必须是小写字母状态),
当ESC键被按下时, 头部flag标志区域会出现~字符, 类似如下所示：
hd/ee.c      |...tp~.

再按下z字母时(同样z要是小写状态), 就会在note区域显示类似ctrl+z组合时的
Save file的提示了(前提是文件内容被修改过了, 如果没修改过, 则直接退出ee,
通过前面提到的|即竖杠字符来标识是否被修改了)。

上面提到的ctrl都是left ctrl即左ctrl键, 而非右ctrl键, zenglOX内核里
目前也没有对右ctrl键的任何处理代码。另外像VirtualBox虚拟机会对Right Ctrl
做特殊处理, 因此, 也就没添加右ctrl键的相关代码。

本来想加入alt键的, 但是alt键的释放在bochs里有点问题,
所以就没有alt, 全部都用的left ctrl控制键。

如果ee打开的是一个新文件的话, 在头部flag标志区域里就会显示出*字符,
类似如下所示:
hd/hello     .....p.*

可以通过ee -v命令来查看当前ee的版本信息:
zenglOX> ee -v
ee(easy editor) for zenglOX, ee's version is v1.3.8
zenglOX>

启动ee时, 可以使用-+参数来设置打开文件时, 自动跳到哪一行:
zenglOX> ee -+100 hd/ee.c
执行上面命令后, ee在打开hd/ee.c文件后, 一开始就会自动跳到第100行的第1列。
当你输入的行数超过文件内容的行数时, ee内部会自动设置为最后一行。
(前提是你输入的整数没有超过int的32位范围, 超过范围时就会发生溢出,
溢出情况下, 整数就有可能是正数或负数, 两种情况ee内部都会做处理)

使用-l参数可以设置打开文件时, 自动跳到哪一列:
zenglOX> ee -l10 hd/ee.c
执行上面命令后, ee就会在打开hd/ee.c文件后, 一开始就会自动跳到第1行的第10列。
当你设置的列数超过10000时, ee内部会自动将其设置到10000
(同样ee内部也考虑了输入值的溢出情况)

使用-t参数可以设置ee编辑时的tab边界宽度(默认为8, 最多只能设置到32):
zenglOX> ee -t16 hd/ee.c
执行上面命令后, 在ee编辑器中的tab宽度就会由默认的8变为16 , 如果你设置的值大于32,
则ee会在内部将其调整到32. (同样ee内部也考虑了输入整数溢出时或为负数时的情况)

当然, 上面的-+, -l与-t参数也可以组合在一起使用:
zenglOX> ee -+100 -l10 -t16 hd/ee.c
执行上面命令后, ee编辑器的光标一开始就会位于第100行的第10列, tab宽度为16.

当你的文本内容很大时, 过大的tab宽度会明显增加ee编辑的字符数, 因为\t字符
会按照tab宽度替换为对应数目的空格符, 当超过ee的容量上限时, ee打开文件时
也会有too big content...的警告信息。

这几个参数的顺序无关紧要, 也可以两两组合, 但是有一点需要注意的是
hd/ee.c之类的文件名必须位于所有参数的最后位置。

以上就是ee编辑器的相关用法。

ee编辑器是依赖libc.so库的, 该库里面包含了一些标准的C函数, 例如fopen, fclose
之类的, 和printf相关的函数代码是从Linux内核里提取出来的。
libc.so只包含了ee编辑器所需的库函数, 如果以后开发其他应用, 有需要的话,
会再向libc.so里添加更多的C库函数。
目前,所有C库函数的声明都位于stdlib.h的一个头文件里。
当然libc.so里也包含了一些像initscr, endwin这类的非C标准的库函数。

从v2.2.0版本开始, 每个任务(也可以称作进程), 都有自己独立的用户堆空间,
不再像以前的版本那样, 所有任务与内核都共用一个内核堆空间。
独立的用户堆空间的好处很多, 首先不会与内核堆空间里的数据相冲突。
用户堆空间会在任务结束时自动释放掉, 也就是说如果你使用syscall_umalloc
系统调用分配了一段堆空间的话, 那么即便忘记用syscall_ufree来释放该空间也没
有关系, 因为所有堆空间最后都会被统一释放掉, 可以有效防止内存泄漏。

用户堆空间的起始线性地址为：0xF0001000 , 该值定义在新增的zlox_uheap.h的头文件里。
和用户堆空间相关的函数代码位于新增的zlox_uheap.c文件里。

这样, 每个任务都有自己独立的用户栈, 内核栈, 以及用户堆了。

atapi驱动做了些调整, 取消原来的任务调度方式, 因为任务调度的方式下, 有时候
会收不到中断信号, 这样在读取光盘数据时, 就会一直处于睡眠状态。现在采用和
ata硬盘读写方式相同的poll循环进行状态检测的方式。

对zenglfs文件系统的BUG进行了相关修复, 之前的版本, 当对某文件进行覆盖写入操作时,
文件的原先多出来的数据块并不能得到有效的释放。

对zlox_paging.c文件的zlox_clone_directory函数做调整, 修复分页BUG 。
由于页目录有8K的大小, 而一个8K的虚拟内存空间，
可以对应两个非连续的物理内存页面，
因此简单的用phys(物理内存地址) + offset(偏移量)得到的结果不一定正确,
尤其是在多任务环境下，因此必须用zlox_get_page函数的方式
来得出实际的正确的物理内存地址，
否则，错误的cr3页表地址会让整个系统直接崩溃掉!

最后对一些堆算法BUG进行了处理, 键盘中断也进行了处理, 使之可以接受
F1, F2, Home, End之类的按键, 还可以接受小键盘里的数字输入(当按下小键盘锁时)。

bochs模拟器是比较消耗CPU资源的, 对于调试开发, 首选bochs , 如果是实际的运行
, 当然是首选VirtualBox与VMware了。bochs的好处在于开发硬件驱动时, 你可以
深入到bochs的源代码里去进行调试分析, 在上一个版本开发e1000网卡驱动时,
bochs的源代码就帮了很大的忙。

时间: 2014年10月6日
作者: zenglong
官网: www.zengl.com