Mauro Iazzi

lua-users home
wiki

mailto:[email protected]

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 的代码肯定更好。我甚至没有复制一些其他函数,因为我不需要它们。

“lock” 的工作方式与 Mark 的相同,但它可以接受“u” 模式来解锁。

function ex.unlock = function (file, offset, length)
  return ex.lock(file, 'u', offset, length)
end
我想这只是一个品味问题。

我不明白为什么 ex 不能允许对 lock 函数使用“u” 模式字符串。参考实现已经允许这样做。事实上,可能只需要 lock 函数。-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

我认为这更加灵活,因为你可以多次迭代一个目录,并且可以退出循环并关闭目录,这样如果你在一个 *非常大的* 目录中搜索文件并找到它作为第一个,你就可以节省很多时间。你甚至可以使用我包装的“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

好的,我不知道。所以我想在 Lua 本身实现一些 API 应该没问题,是吗? --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 in next, t do ... end)。我的迭代器是一个简单的函数,没有单独的元表,因此我无法提供一种方法来使这段代码工作。另一方面,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

''eheh,但似乎他把这个提议的负担留给了我,因为我发现链接到 5.1 实现:https://lua-users.lua.ac.cn/lists/lua-l/2006-10/msg00499.html 顺便说一句,我完全同意这不仅仅应该是 POSIX 的包装器,并且支持更改名称,至少。 --mi''

然后是 "spawn":这里有很大的变化。我定义它很简单,基本上。它使用参数就像这段 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
注意,如果你清空了环境,PATH 搜索将无法工作。

为什么是 argv 而不是 args? -Mark

因为我太蠢了,写这段代码的时候没记住你的名字。而且从没想过要改。这只是为了我自己,我把它展示出来只是为了测试我对 API 规范的理解。它不是一个“用于更改你的 API 的参考实现”或类似的东西……只是一些简单的代码,写的时候我想到了一些东西。其中大部分都是错误的,你懂的 :) --mi

然后,PID 用户数据可以被 waitpid(pid) 使用,它也是一个方法

ex.waitpid(pid)
pid:waitpid()
并返回两个值,一个表示进程是否退出,是被杀死还是(另一个选项我不记得了),另一个分别是退出代码、杀死它的信号或(……我必须再看看我写了什么)。

为什么是 waitpid 而不是 wait?让 wait() 返回退出代码和第二个返回值,其中包含额外信息,应该没问题。-Mark

我坚持使用 POSIX 名称,并且想明确表示这与你的方法不同。它将退出代码作为第二个参数返回,因此不兼容。如果返回其他信息,它应该是第二个返回值,而不是第一个,以符合你的 API --mi

这似乎很容易使用,主要区别在于 Mark 的方法在于 env 可以是调用环境或清空,并且必须使用额外的 argv[1] 字符串来指定命令和 argv。我认为这是可以接受的,因为如果你需要对 spawn 参数进行如此多的控制,你可以仔细检查,并且可能希望能够使用不同的第 0 个参数按路径调用程序(例如,vim 会注意这一点)

我不确定你说环境可以“清空”是什么意思。你是指一个空环境,还是一个继承的环境?ex 已经允许这两种情况。另外请注意,ex API 实际上支持第 0 个参数,无论是否有 'args'

''对于 env 来说是正确的,我误读了提案,对不起。至于第 0 个参数,我发现参数中存在命令字段会改变对 args 列表的解释,这一点有点违反直觉。具体来说,我比较了

os.spawn{"echo", "hello", "world"}
os.spawn{command="/bin/echo", [0]="echo", "hello", "world"}
我认为这相当于对语句进行两次修改(我的意思是,当我思考更改时,这是我的理解)。如果命令字段没有增加任何功能,而我不用 [0]= 的话,它有什么用呢?它看起来就像是一种商品,似乎不应该包含在 API 本身中,因为任何人都可以在其之上实现它。此外,这意味着相同的 args 表可以在两种语法中使用,而无需进行移位。如果你(像我一样)用它来自动处理大量文件,它可能会很有用。--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


最近更改 · 偏好设置
编辑 · 历史记录
最后编辑于 2007 年 7 月 11 日下午 12:40 GMT (差异)