Mauro Iazzi

lua-users home
wiki

mailto:mauro.iazzi@gmail.com

Ex API

至於 ExtensionProposal,我在重新實作的時候有想到了一些想法。由兩個不同的實作方式來實作 API 並沒有用處,因此我只需要將程式碼 [放在這裡],這樣您便可以自行檢視。這符合 POSIX.1-2001,但我不確定它是否符合其他標準(肯定不符合早期的 POSIX)。

此提案為 API,而非實作。我的實作僅旨在作為參考實作。因此,您無需再使用 / 實作。 :) 我不認為使用同一 API 的多個實作方式沒有用處。 -Mark

若由您繼續維護,您的程式碼或許會比我的更好。然而,建議變更 API… --mi

我實作的方式儘量簡單,可能與 Mark 的方式相同

 * getenv,
 * setenv,
 * environ,
 * chdir,
 * mkdir (setting perms to 0777, plus implied umask),
 * currentdir

然而,介面是相同的,因此 Mark 的程式碼肯定更好。我甚至沒有複製其他一些函式,因為我不需要它們。

「封鎖」的功能與 Mark 的相同,但它可以接受 'u' 模式的解鎖

function ex.unlock = function (file, offset, length)
  return ex.lock(file, 'u', offset, length)
end
我想這是品味的問題。

我看不出為什麼 ex 不能讓封鎖函式使用「u」模式字串。參考實作已經允許它了。事實上,可能也只有封鎖函式。 -Mark

不知道,因此這個也一樣。 --mi

我增加了 getid 函式

  local uid, euid, gid, egid = ex.getid()

這個如何,可能有用 --mi

我在最佳化上遇到了某些問題,因此實作了「opendir」、「closedir」和「readdir」,它們只是圍繞於對應 POSIX 函式所做的包裝函式。

local d = assert(ex.opendir(name))
  for filename in ex.readdir, d do
    print(filename)
    --- you can even break out of the loop
    if (string.match(filename, pattern)) then break end
  end
ex.closedir(d)

可以用這些函式來模擬 Mark 的 ex.dir,如下所示

function ex.dir (name)
  local d = assert(ex.opendir(name))
  return function ()
    local f = ex.readdir(d)
    if (f)==nil then ex.closedir(d) end
    return f
  end
end

for fn in ex.dir(name) do
  print(fn)
  -- you cannot break or dir will remain open until collected
end

我相信這樣會更靈活,因為您可以在目錄中反覆巡覽,還可以跳出迴圈並關閉目錄,因此如果您正在 *HUGE* 目錄中搜尋檔案時在第一個檔案就找到,您可以節省很多時間。您甚至可以使用我所封裝的「rewinddir」重複使用該目錄。實作方式也很簡單,使用一個 C 函式對應一個 Lua 函式。

local d = assert(ex.opendir(name))
local name = "first"
while name ~= "last" do
  ex.rewinddir(d)
  for filename in ex.readdir, d do
    print(filename)
    --- you can even break out of the loop
    if (filename == name) then 
      local f = assert(io.open(filename))
      name = f:read('*l')
      f:close()
      break
    end
  end
end
ex.closedir(d)

此外,readdir 僅回傳檔案名稱,但我實作了一個 fstat(和 lstat),它會回傳關於檔案的某些資訊。

我匯出了 stat 和 lstat。它們也僅是包裝函式。我相信像這樣將函式分開會比較簡單,而且這些名稱比起「dirent」更直觀。

因此,ex 不僅僅為目錄巡覽匯出「open/read/close」風格的 API 的原因是,目前最常見的使用案例是迴圈巡覽。如果您真的需要針對很多目錄進行部分巡覽(這種情況下,收集的動作可能無法夠快),那麼您仍然可以使用 os.dir(),但它並未在 API 中記載。 -Mark

好吧!我不知道。因此,我猜想將部分 API 實作於 Lua 本身中應該是不錯的,對吧?--mi

d,ds,di = assert(os.dir(name))
for entry in d,ds,di do
  if name==entry.name then
    break
  end
end
d.getmetatable().__gc(d)

我只是擔心如果將此納入 API 需求,這將會大量限制實作... 以我為例,我堅持使用迭代器函數、用於標準串列的不透明資料模型(例如依次為 k、v,t 做... 結束)。我的迭代器只是一個簡單函數,沒有個別的 metatable,因此我無法提供方法讓此程式碼正常執行。另一方面,API 實際上應該指定一個明確關閉目錄的方法... 我沒有頭緒。--mi

話說回來,我不認為 opendir/readdir/closedir 有什麼不好。stat 和 lstat 也不錯。不過,您仍需要實作 ex.dir 和 ex.dirent。dirent 可能不是個好名字,儘管 stat 可能比較直覺(對 UNIX 程式設計人員來說至少如此),但我不想讓 ex 和 POSIX 混淆。您對這個函數名稱有比較好的建議嗎?-Mark

我同意您的看法,我的命名方式的確是嚴格基於 POSIX,因為那時我只需要這樣做。我想 ex.fileinfo 應該完美符合 Lua 的命名風格。至於 fstat - lstat 的差別,您有什麼看法?--mi

請注意,如果您真正想要的只是 POSIX API,您應該使用 lhf 的 POSIX 封裝程式 http://www.tecgraf.puc-rio.br/~lhf/ftp/lua/#lposix,而不是 ex。-Mark

''呵,但看起來他將負擔留給了這個提議,因為我發現以下連結到 5.1 的實作: https://lua-users.dev.org.tw/lists/lua-l/2006-10/msg00499.html 順帶一提,我完全同意這不應該只是一個 POSIX 封裝程式,並贊成變更名稱。--mi''

然後是「建立子行程」:以下是重大的變更。我定義它可以輕易實作,基本上如此。它使用類似以下 Lua 程式碼的引數

function lua_spawn(t)
  if type(t)=='string' then t = { t } end
  assert(type(t)=='table') -- "spawn must receive a table or a string"
  local argv = t.argv or t
  local argc = #argv
  local command = t.command or argv[1] or error'command not given'
  if not argv then argv = { command } end
  local env = t.env or ( type(t.env)==nil and ex.environ() or {} )
  if t.stdin then set_redirect_to(redirections, t.stdin) end
  if t.stderr then set_redirect_to(redirections, t.stderr) end
  if t.stdout then set_redirect_to(redirections, t.stdout) end
  return posix_spawn(command, argv, argc, env, redirections)
end
以類似方式使用(它使用 argv 而不是 args)
proc = ex.spawn"/bin/echo"
proc = ex.spawn{"/bin/echo", "hello", "world"}
proc = ex.spawn{command="/bin/echo", "echo", "hello", "world"} --big difference
proc = ex.spawn{argv = {"lua", "-e", 'print"Hello world\n"'}} -- equivalent to Mark's example
proc = ex.spawn{"lua", "-e", 'print"Hello world\n"'}
proc = ex.spawn{"lua", "-e", 'print"Hello world\n"', env=ex.environ()}
proc = ex.spawn{"/usr/bin/lua", "-e", 'print"Hello world\n"', env=false} -- this uses a void env
proc = ex.spawn{"/usr/bin/lua", "-e", 'print"Hello world\n"', env="equivalent"} -- this uses a void env
proc = ex.spawn{command='/usr/bin/vim', "ex", "ex.c"} -- starts vim in "ex" mode
proc = ex.spawn{command='/bin/busybox', argv = {"ls", "ex.c" }} -- ls ex.c
proc = ex.spawn{command='/bin/busybox', argv = {"cp", "ex.c", 'ex2.c'}} -- cp ex.c ex2.c, same binary
proc = ex.spawn{"echo", "hello", "world", env={ PATH="/bin" } }
proc = ex.spawn{"echo", "hello", "world", env={ "PATH=/bin" } } -- same as before
請注意,如果您將 env 設為無效,PATH 搜尋將無法運作。

為什麼使用 argv 而不是 args?-Mark

因為我很笨,寫這些程式碼時沒有記住您的名字。而且從未想要變更。這只是寫給我自己用的,我展示它只是為了測試我如何詮釋 API 規格。這不是「改變您的 API 的參考實作」,也沒有假裝是那樣的東西... 只是單純的程式碼,我寫這些程式碼時想到了一些事情。其中大部分都是錯的,您懂吧 :) --mi

接著可由 waitpid(pid) 使用 PID 使用者資料,它也是一種方法

ex.waitpid(pid)
pid:waitpid()
並傳回兩個值,代表行程是結束、已殺死或(我記不得的其他選項),另一個分別為結束程式碼、造成殺死的訊號(... 我必須再看看我寫了什麼)。

為什麼使用 waitpid 而不是 wait?wait() 傳回結束程式碼和包含額外資訊的第二個傳回值應該就夠了。-Mark

我堅持使用 POSIX 名稱,並想要說明這不適用於你的名稱。它會將退出程式碼當做第二個參數傳回,所以不相容。如果傳回其他資訊,它應該是第二個傳回值而不是第一個,才能符合你的 API --mi

這看起來很容易使用,與 Mark 的主要不同在於,env 可以是呼叫環境或空值,以及指定命令 AND argv 必須使用附加的 argv[1] 字串。我想應該是可以接受的,因為如果你需要如此控制 spawn 參數,你可以仔細檢查並可能想要選擇用不同的第零個參數透過路徑呼叫程式(例如 vim 會注意這個)

我不確定當你說環境可以「空值」時,你的意思是?你指的是空環境,還是繼承的環境?ex 已經允許兩者。也請注意,ex API 實際上支援第零個參數,不論是否有「參數」

''對於 env 來說,我誤讀了提案,很抱歉。至於第零個參數,我發現如果參數中出現命令欄位,它會以非直覺的方式改變參數清單的解譯方式。特別是,我比較了

os.spawn{"echo", "hello", "world"}
os.spawn{command="/bin/echo", [0]="echo", "hello", "world"}
我解讀為對敘述做了兩個變更(我是說,當我想到變更時,這就是我的認知)。如果它無法新增任何項目至沒有使用 [0]= 項目時,為何有命令欄位會有用?它看起來就像一個商品,且似乎不是應該包含在 API 本身,因為任何人可以在它的上方實作它。也表示相同的參數表格可以在不需變動的情況下,使用於這兩種語法。如果你(像我一樣)使用這個自動化處理許多檔案,這會很有用。--mi''

os.spawn{command="/bin/echo", [0]="echo", "hello", "world"}
os.spawn{command="/usr/bin/vim", [0]="ex", "ex.c"}
os.spawn{command="/bin/busybox", args={[0]="ls", "ex.c"}}
os.spawn{command="/bin/busybox", args={[0]="cp", "ex.c", "ex2.c"}}

-Mark


RecentChanges · 偏好設定
編輯 · 歷史
上一次編輯時間為 2007 年 7 月 11 日下午 12:40 GMT (差異)