linux系統命令大全分享 linux原理和方法( 二 )


還會加載一些 vim 插件 source_in_path,使用 load_start_packages 加載 package。
下面這種只是第一個交互了,等待客戶敲下 enter 鍵:
wait_return(TRUE);
我們總是看見的:“Press ENTER or type command to continue“ 只是在這里執行的 。確認完,就說明你真的是要打開文件,并展現到終端了 。
怎么打開文件?怎么展現字符到終端屏幕?
這一切都來自于 create_windows 這種函數 。名字也較好理解,只是初始化的時候創建終端窗口來著 。
/*
* Create the requested number of windows and edit buffers in them.
* Also does recovery if "recoverymode" set.
*/
create_windows(?ms);
這里其實涉及到兩個方面:
把資料讀出去,讀到內存;
把字符渲染到終端;
怎么把資料從磁盤上讀出去,只是 IO 。怎么渲染到終端這種我們不管,這種使用的是 termlib 或者 ncurses 等終端編程庫來實現的,有興趣的應該了解下 。
這種函數會調用到我們的第一個核心函數:open_buffer,這種函數做兩個時間:
create memfile:創建一個 memory + .swp 文件的抽象層,讀寫資料都會過這一層;
read file:讀原始文件,并解碼(用來展現到屏幕);
函數調用棧:-> readfile
-> open_buffer
-> create_windows
-> vim_main2
-> main
真正干活的是 readfile 這種函數,評論一下,readfile 是一個 2533 行的函數 。。。。。。
readfile 里面會擇機創建 swp 文件(曾經一些話,應該用來復原資料),調用的是 ml_open_file 這種函數,文件創建好之后,size 占用 4k,里面往往一般是一些特殊的元資料(用來復原資料用的) 。
劃重要時機:.{文件名}.swp 這種掩藏文件是有格式的,前 4k 為 header,后面的內容也是根據一個個block 團隊的 。
再往后走,會調用到 read_eintr 這種函數,讀取資料的內容:
long
read_eintr(int fd, void *buf, size_t bufsize)
{
long ret;
for (;;) {
ret = vim_read(fd, buf, bufsize);
if (ret >= 0 || errno != EINTR)
break;
}
return ret;
}
這是一個最底層的函數,是系統調用 read 的一個封裝,讀出去之后 。這里回答了一個關鍵問題:vim 的存儲原理是啥?
劃重要時機:本質上調用 read,write,lseek 這樣樸素的系統調用,而已 。
readfile 會把二進制的資料讀出去,之后進行字符轉變編碼(根據配置的模式),編碼不對只是亂碼嘍 。每次都是根據一個特殊 buffer 讀資料的,例如 8192。
劃重要時機:readfile 會讀完文件 。這只是怎么當 vim 打開一個超大文件的時候,會超級慢的原因 。
這里提一點題外話:memline 這種封裝是文件之上的,vim 改寫文件是改寫到內存 buffer,vim 根據策略來 sync memfile 到 swp 文件,一個是以免丟棄未保存的資料,第二是為了節省內存 。
mf_write 把內存資料寫到文件 。在 .test.txt.swp 中的只是這樣的資料結構:
block 0 的 header 主要標識:vim 的版本;
寫文件的路徑;
字符編碼方法;
這里實現提一個重要知識點:swp 文件里存儲的是 block,block 的管理是以一個樹形結構進行管理的 。block 有 3 種類別:
block0:頭部 4k,往往一般是存儲一些文件的元資料,例如路徑,編碼模式,時間戳等等;
pointer block:樹形內部節點;data block:樹形葉子節點,存儲客戶資料;
2 敲下 :w 背后的原理進程初始化我們講完了,現在來看下 :w 觸發的調用吧 。客戶敲下 :w 命令觸發 ex_write 回調(初始化的時候配置好的) 。全部的流程皆在 ex_write,我們來看下這種函數做了什么 。
先撇開代碼實現來說,客戶敲下 :w 命令其實只是想保存改寫而已 。
那么第一個問題?客戶的改寫在哪里?在 memline 的封裝,只要沒執行過 :w 保存,那么客戶的改寫就沒改寫到原文件上(小心哦,沒保存曾經,一定沒改寫原文件哦),這時候,客戶的改寫可能在內存,也很有可能在 swp 文件 。存儲的資料結構為 block。所以,:w 其實只是把 memline 里面的資料刷到客戶文件而已 。怎么刷?
重要時機步驟如下(以 test.txt 舉例):創建一個 backup 文件( test.txt~ ),把原文件拷貝出去;
把原文件 test.txt truancate 截斷為 0,等于清空原文件資料;
從 memline (內存 + .test.txt.swp)拷貝資料,從頭開始寫入原文件 test.txt;
刪除備份文件 test.txt~;以上只是 :w 做的全部事件了,下面我們看下代碼 。
觸發的回調是 ex_write,核心的函數是 buf_write,這種函數 1987 行 。

推薦閱讀