Lua源码笔记–命令行参数
Lua的命令行参数放在一个arg的table里面。arg[0]存放脚本文件,arg[1…n]存放参数。
@(语法)
lua [options] [script [args]]
注意:从源码上看最大参数个数不能超过8000,由宏LUAI_MAXCSTACK定义。
#define LUAI_MAXCSTACK 8000
一个简单的例子
@(arg.lua)
for i, v in pairs(arg) do
print(i, v)
end
运行结果:
[root@VM_89_131_centos lua]# lua arg.lua 1 2 3
1 1
2 2
3 3
-1 lua
0 arg.lua
由上面运行情况可知:
arg[-1]: lua执行文件
arg[0]: 执行脚本
arg[1]: 第一个参数
arg[2]: 第二个参数
arg[n]: 第n个参数
源码分析
下面的源码分析将用到上面的例子做讲解,命令行的源码主要集中在两个函数:
@(lua.c)
static int getargs (lua_State *L, char **argv, int n) {
int narg;
int i;
int argc = 0;
while (argv[argc]) argc++;
narg = argc - (n + 1);
luaL_checkstack(L, narg + 3, "too many arguments to script");
for (i=n+1; i < argc; i++)
lua_pushstring(L, argv[i]);
lua_createtable(L, narg, n + 1);
for (i=0; i < argc; i++) {
lua_pushstring(L, argv[i]);
lua_rawseti(L, -2, i - n);
}
return narg;
}
这个函数主要做如下:
- 第5行: 获取所有参数个数。
- 第6行: 计算出narg脚本参数个数。
- 第7行: 检查参数个数是否超过最大,如有则返回错误。
- 第8,9行: 将参数值PUSH到堆栈。
- 第10行: 创建一个table,并压入堆栈。这个table就是我们在脚本用到的arg,只是现在还没有命名。
- 第11-14行: 把argv[0-4]的值插入到新创建table,且插入索引为-1,0,1,2,3,这也印证了上面示例运行的情况。
static int handle_script (lua_State *L, char **argv, int n) {
...
int narg = getargs(L, argv, n);
lua_setglobal(L, "arg");
...
}
这个函数3-4行的作用通俗讲就是把新建的table命名为arg,实现的方式就是把这个新table放入全局的_G表。这样就可以直接在lua脚本中使用arg数组了。
@(伪代码:)
_G["arg"] = newTable
进阶
@(arg1.lua)
print(...)
运行结果:
[root@VM_89_131_centos lua]# lua arg1.lua 1 2 3
1 2 3
可以看到直接输出了脚本运行参数。
原因:
一个Lua脚本在实现的时候是当做一个函数的,在脚本内定义的函数可以理解成内嵌函数。可以想象成每个脚本都有个main函数,main函数接受可变成参数。
function main(...)
-- script content
print(...)
end
getargs函数的8-9行所做的工作就是为这个函数设置参数。
困惑
在getargs函数中的参数 int n 是什么意思?从代码上看,这个参数n在整个参数解析的时候还挺重要的。
static int getargs (lua_State *L, char **argv, int n) {
narg = argc - (n + 1);
}
参数n: 表示脚本文件在整个命令行参数的位置(从0开始),如
- /usr/bin/lua test.lua 1 2 3 n=1
- /usr/bin/lua -e “print(“start”)” test.lua 1 2 3 n=3
总结:
命令行参数的代码很短,但想看懂确不容易,主要是要弄懂Lua堆栈的实现,这个会在后面详细介绍。