[ Skill ] load 函式優化,識別相對路徑

YEUNGCHIE發表於2022-03-13

https://www.cnblogs.com/yeungchie/

cds.lib 檔案中定義庫的路徑,為了規範庫定義的管理,經常這樣做:

.
|-- cds.lib ------------------- cat --> 1| INCLUDE ./common/cds.lib
`-- common
    |-- cds.lib --------------- cat --> 1| INCLUDE ./project/cds.lib
    |                                   2| INCLUDE ./project/cds.lib
    |-- project
    |   |-- cds.lib ----------- cat --> 1| INCLUDE ./layout/cds.lib
    |   |                               2| INCLUDE ./sch/cds.lib
    |   |                               3| 略 ...
    |   |-- layout
    |   |   `-- cds.lib ------- cat --> 1| DEFINE layout_lib1 ./layout_lib1
    |   |                               2| DEFINE layout_lib2 ./layout_lib2
    |   |                               3| 略略 ...
    |   |-- sch
    |   |   `-- cds.lib ------- cat --> 1| 略略略 ...
    |   `-- 略略略略 ...
    `-- 略略略略略 ...

可以看到,對於 cds.lib 檔案來說,INCLDUE / DEFINE 都可以使用相對路徑。
而在 Skill 中使用 load() / loadi() 函式卻不能支援相對路徑:

*Error* load: can't access file - "./dir/test.il"
*Error* load: error while loading file - "/home/yeung/tmp/load.il" at line 1

在上一篇隨筆 檔案讀寫 & IO 控制程式碼 整理的內容中,發現內建的控制程式碼 piport 可以獲取當前檔案的路徑這一特性,於是有了這一篇。

幾個函式

__FILE__

在 Perl 中 __FILE__ 用來獲取當前檔案的路徑,這裡模仿一個。

procedure(__FILE__()
    get_filename(piport)
); __FILE__
  • 執行:

    printf("Current path: %s\n" (__FILE__))
    ; Current path: /home/yeung/tmp/load.il
    

__DIR__

正則處理,從 __FILE__ 函式結果中提取父目錄的路徑。
需要注意的是,如果是在 CIW 中執行 __FILE__ 函式,它的返回值會是 *ciwInPort*,這種情況直接用 getWorkingDir() 作為 __DIR__ 函式的返回值。

procedure(__DIR__(\@optional path((__FILE__)) "t")
    if(pcreMatchp("^\\*.+\\*$" path)
        getWorkingDir()
        pcreReplace(pcreCompile("(?<=/)[^/]+/*$") path "" 0)
    )
); __DIR__
  • 執行:

    printf("Current directory: %s\n" (__DIR__))
    ; Current directory: /home/yeung/tmp/
    

ycReadRelPath

這個函式用來將 相對路徑 轉為 絕對路徑
當輸入路徑 path 為 ~ 或者 / 開頭時,說明已經是絕對路徑了,這種情況直接原封不動返回。

procedure(ycReadRelPath(\@optional file("") "t")
    let((path)
        path = if(pcreMatchp("^[~/]" file)
            file
            sprintf(nil "%s/%s" (__DIR__) file)
        )
        simplifyFilename(path t)
    ); let
); ycReadRelPath
  • 執行:

    printf("Target path: %s\n" ycReadRelPath("./init/load.il"))
    ; Target path: /home/yeung/tmp/dir/test.il
    

ycLoad

優化 load 函式。
預留一個 ignores 引數用來優化 loadi 函式。

procedure(ycLoad(file \@optional ignore "tg")
    let((path)
        path = ycReadRelPath(file)
        unless(isFile(path)
            error("ycLoad: not a valid file - %A" path)
        )
        unless(isReadable(path)
            error("ycLoad: can't access file - %A" path)
        )
        if(ignore loadi(path) load(path))
    )
); ycLoad

ycLoadi

優化 loadi 函式。
同樣可以忽略 load 過程中遇到的錯誤,列印錯誤訊息,然後繼續 load 。

procedure(ycLoadi(file "t")
    ycLoad(file t)
); ycLoadi

效果

  • 沒有 ycLoad 之前

    let((home wind sync)
        home = "/home/yeung/script/skill/tools/"
        wind = list("hiForm.il" "windCtrl.il")
        sync = list("syncView.il" "support3rd.il")
        foreach(x wind
            load(strcat(home "src/wind/" x))
        )
        foreach(x sync
            load(strcat(home "/src/sync/" x))
        )
    ); let
    

    非常囉嗦。
    其次如果父資料夾改了名,或者移動了位置,還得一個個檔案開啟檢查路徑並修改,還要增加無意義的版本。
    copy 給別人也不能傻瓜式操作,直接 load 報個錯:

    *Error* load: can't access
    " 唉 你 這 腳 本 有 問 題 啊 ? "
  • 有了 ycLoad 之後

    ycLoad("src/wind/hiForm.il")
    ycLoad("src/wind/windCtrl.il")
    ycLoad("src/sync/syncView.il")
    ycLoad("src/sync/support3rd.il")
    

    "優雅地" load 完所有檔案。

    [ Skill ] load 函式優化,識別相對路徑

繼續優化可以再識別 Shell 環境中的變數。

相關文章