首先这里需要宣传一下,qtun的 网站 已经开张了,功能正在逐步添加中。
一、嵌入lua的原因
由于qtun的可配置参数不断增多,因此有必要将参数写入到配置文件之中。又由于C语言并不擅长做字符串的处理,因此加入了轻量级的lua脚本语言,同时嵌入lua更有助于加入第三方插件的支持。
二、代码的修改
extern int init_path(char* cmd); extern int init_lua(); extern void show_logo(); extern void conf_init(library_conf_t* conf);
int script_global_init(lua_State* lua) { load_lib(lua, "_G", luaopen_base); load_lib(lua, LUA_TABLIBNAME, luaopen_table); load_lib(lua, LUA_STRLIBNAME, luaopen_string); load_lib(lua, LUA_IOLIBNAME, luaopen_io); lua_pushcfunction(lua, _syslog); lua_setglobal(lua, "_syslog"); init_qtun_state(lua); init_qtun_conf(lua); init_qtun_log(lua); return 1; }
static void init_qtun_state(lua_State* lua) { get_qtun_obj(lua); lua_pushstring(lua, "state"); lua_newtable(lua); lua_newtable(lua); lua_pushstring(lua, "__index"); lua_pushcfunction(lua, state_get); lua_settable(lua, -3); lua_setmetatable(lua, -2); lua_settable(lua, -3); lua_pop(lua, 1); } static void init_qtun_conf(lua_State* lua) { get_qtun_obj(lua); lua_pushstring(lua, "conf"); lua_newtable(lua); lua_newtable(lua); lua_pushstring(lua, "__index"); lua_pushcfunction(lua, conf_get); lua_settable(lua, -3); lua_pushstring(lua, "__newindex"); lua_pushcfunction(lua, conf_set); lua_settable(lua, -3); lua_setmetatable(lua, -2); lua_settable(lua, -3); lua_pop(lua, 1); } static void init_qtun_log(lua_State* lua) { int new_log = 0; get_qtun_obj(lua); lua_pushstring(lua, "log"); lua_gettable(lua, -2); if (lua_isnil(lua, -1)) { lua_pop(lua, 1); lua_pushstring(lua, "log"); lua_newtable(lua); new_log = 1; } push_log_level(lua, "LOG_EMERG" , 0); push_log_level(lua, "LOG_ALERT" , 1); push_log_level(lua, "LOG_CRIT" , 2); push_log_level(lua, "LOG_ERR" , 3); push_log_level(lua, "LOG_WARNING", 4); push_log_level(lua, "LOG_NOTICE" , 5); push_log_level(lua, "LOG_INFO" , 6); push_log_level(lua, "LOG_DEBUG" , 7); if (new_log) lua_settable(lua, -3); lua_pop(lua, 1); }
int script_load_config(lua_State* lua, library_conf_t* conf, const char* file_path) { char path[MAX_PATH]; lua_pushlightuserdata(lua, conf); lua_setglobal(lua, "__conf__"); strcpy(path, qtun->this_path); strcat(path, "scripts/load_config.lua"); if (luaL_dofile(lua, path) != 0) { fprintf(stderr, "%s/n", lua_tostring(qtun->lua, -1)); lua_close(qtun->lua); exit(1); } return 1; }
三、lua脚本
最后让我们来分别看一下这三个lua脚本长啥样
print('┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓') print('┃ ... ..... . . . . ┃') print('┃ . . . . . .. . ┃') print('┃ . . . . . . .. ┃') print('┃ ... . . ... . . ┃') print('┃ ┃') print('┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛')这个logo是不是很有爱^_^
qtun = { log = { syslog = function (level, fmt, ...) _syslog(level, string.format(fmt, ...)) end } } function trim(s) return s:gsub('^%s*(.-)%s*$', '%1') end function is_numeric(s) return tonumber(s) ~= nil end function is_string(s) return not is_numeric(s) end这里包装了一些公共函数
local function append_key_value(key, value) if value == 'true' then value = true elseif value == 'false' then value = false elseif is_numeric(value) then value = tonumber(value) elseif key == 'log_level' then if is_string(value) then value = qtun.log[value] end end qtun.conf[key] = value end local function set_true(key) qtun.conf[key] = true end local file = io.open(qtun.conf.conf_file, 'r') while true do ::start:: local line = file:read('*line') if line == nil then break end local len = #line local key = '' local first = '' local start = 0 local have_key = false local have_value = false local added = false local j = 0 for i=0, len do j = i local ch = line:sub(i + 1, i + 1) if first == '' and ch ~= ' ' then first = ch end if ch == '#' then if trim(line:sub(start, i)) == '' then goto start end have_value = true if have_key then append_key_value(key, trim(line:sub(start, i))) else set_true(trim(line:sub(start, i))) end added = true break elseif ch == '=' then key = trim(line:sub(start, i)) if key == '' then error('missing key') end have_key = true start = i + 2 end end if first == '#' then goto start end if not added then if not have_key then local key = trim(line:sub(start, j)) if key == '' then goto start end set_true(key) else append_key_value(key, trim(line:sub(start, j))) end end end file:close()解析配置文件的主要逻辑都在这里了
四、完整代码
完整代码可到 step14 中查看