當(dāng)前位置:首頁(yè) > 芯聞號(hào) > 充電吧
[導(dǎo)讀]中午在做HTTP服務(wù)器,內(nèi)嵌了LUA引擎作為業(yè)務(wù)邏輯部分. 但考慮到LUA輸出HTML的性能不高,況且 MVC 模式開發(fā)網(wǎng)頁(yè)已經(jīng)習(xí)慣了,何不用C給lua寫個(gè)最簡(jiǎn)單的模板引擎呢?說(shuō)做就做, 項(xiàng)目時(shí)間很緊

中午在做HTTP服務(wù)器,內(nèi)嵌了LUA引擎作為業(yè)務(wù)邏輯部分. 但考慮到LUA輸出HTML的性能不高,況且 MVC 模式開發(fā)網(wǎng)頁(yè)已經(jīng)習(xí)慣了,何不用C給lua寫個(gè)最簡(jiǎn)單的模板引擎呢?說(shuō)做就做, 項(xiàng)目時(shí)間很緊張,所以必須確定目標(biāo),想了會(huì)兒。定了幾個(gè)目標(biāo):


我要的是編譯型的模板,要支持緩存。
不需要強(qiáng)大的模板邏輯方面的指令。將HTML模板文件編譯成LUA源代碼即可。LUA 還是比較容易擴(kuò)展的,除了那棧用起來(lái)比較變態(tài)之外,經(jīng)過(guò)了幾個(gè)小時(shí)的奮斗,C+LUA代碼。算是大功告成了。

#include#include#include#include#include#include#include#include?"lib/automem.h"

#include?"lua.h"
#include?"lauxlib.h"

#include?"lua-tpl.h"

/*
	LUA?最簡(jiǎn)單的模板引擎.
*/

const?char?LUAFMT_TPL_META[]="LUAFMT_TPL";

void?lua_cfmt_createmetatable?(lua_State?*L);
void?lua_register_class(lua_State?*?L,const?luaL_Reg?*?methods,const?char?*?name,lua_CFunction?has_index);

#if?defined(_WIN32)?||?defined(_WIN64)
	#define?open	_open
	#define?close	_close
	#define?read	_read
	#define?stat(?x?,?y?)	_stat(?x?,?y?)
#endif

static?char?*?file_get_contents(const?char?*?file,int?*?sz){
	char?*?ret?=?NULL;
	struct?stat?st;
	int?fd;
	*sz?=?0;
	if?((fd?=?open(file,?O_RDONLY|O_BINARY))?!=?-1)
	{
		if?(fstat(fd,?&st)?!=?-1)
		{
			ret?=?(char?*)malloc(st.st_size);
			if(NULL?!=?ret){
				while(?*sz?<?st.st_size){
					*sz?+=?read(fd,?ret?+?*sz,?st.st_size?-?(*sz));
					_lseek(fd,?*sz,?SEEK_SET);
				}
			}
			close(fd);
		}
	}
	return?ret;
}

int?file_put_contents(const?char*?file_name,?automem_t*?mem)
{
	FILE?*?fp?=?fopen(file_name,"wb+");
	if(NULL?!=?fp)
	{
		fwrite(mem->pdata,?mem->size,?1,?fp);
		fclose(fp);
		return?1;
	}
	return?0;
}

enum{
	tpl_state_normal,
	tpl_state_scode_1,
	tpl_state_code,
	tpl_state_ecode_1,
	tpl_state_escape,
};

#define?append_end_stringfield(a,b,c)?
	automem_append_voidp(?(a)?,?cmd,?lcmd);?
	automem_append_voidp(?(a),?(b)?,?(c));?
	automem_append_voidp(?(a)?,?ecmd,?lecmd);?
	automem_append_voidp(?(a),?")n",?2);

static?void?lua_tpl_compile_local(lua_State?*?L,?automem_t?*?mem,?const?char?*?buf,int?lbuf){
	int?state?=?tpl_state_normal,?i?=?0;
	const?char?*?sbuf;?char?c;
	size_t?lcmd?=?sizeof("request.print([[")?-1,
		lecmd?=?sizeof("]])")?-1,
		lpre?=?0;
	const?char?*?cmd?=?"request.print([[",
		*?ecmd?=?"]])",
		*pre?=?NULL;

	if(lua_isstring(L,?3))
		cmd?=luaL_checklstring(L,?3,?&lcmd);

	if(lua_isstring(L,?4))
		ecmd?=luaL_checklstring(L,?4,?&lecmd);

	if(lua_isstring(L,?5))
		pre?=luaL_checklstring(L,?5,?&lpre);

	if(NULL?!=?pre){
		automem_append_voidp(mem,?pre,?lpre);
		automem_append_byte(mem,'n');
	}
	sbuf?=?buf;
	while(i?<?lbuf){
		c?=?buf[i];
		switch?(state)
		{
		case?tpl_state_normal:
			switch(c){
			case?'{':
				state?=?tpl_state_scode_1;
				break;
			}
			break;
		case?tpl_state_scode_1:
			switch(c){
			case?'#':
				state?=tpl_state_code;
				append_end_stringfield(mem,sbuf,?&buf[i]?-?sbuf-1);
				sbuf?=?&buf[i+1];
				break;
			default:
				state?=?tpl_state_normal;
				break;
			}
			break;
		case?tpl_state_code:
			switch(c){
			case?'#':
				state?=?tpl_state_ecode_1;
				break;
			}
		case?tpl_state_ecode_1:
			switch(c){
			case?'}':
				automem_append_voidp(mem,sbuf,?&buf[i]?-?sbuf-1);
				automem_append_byte(mem,'n');
				sbuf?=?&buf[i+1];
				state?=?tpl_state_normal;
				break;
			default:
				state=tpl_state_code;
			}
		default:
			break;
		}
		i++;
	}
	if(tpl_state_normal?==?state){
		append_end_stringfield(mem,sbuf,?&buf[i]?-?sbuf);
	}
}
/*?對(duì)模板文件進(jìn)行編譯.*/
static?int?lua_tpl_compile(lua_State?*?L)
{
	int?cache?=?0,i?=?0,?lbuf?=?0;
	size_t?lfile;
	const?char?*cfile?=?NULL,?*?file=?luaL_checklstring(L,?1,&lfile),*?buf;
	automem_t?mem;

	if(lua_isboolean(L,?2))
		cache?=lua_toboolean(L,?2);

	if(0?!=?cache){
		struct?stat?st1,st2;
		cfile=(char?*)malloc(lfile+5);
		memcpy((char?*)cfile,file,lfile);
		strcpy((char?*)cfile+lfile,".tpl");

		if((0?==?stat(file,&st1))?&&?(0?==?stat(cfile,?&st2)))
		{
			if(st1.st_mtime?<=?st2.st_mtime)
			{
				if(NULL?!=?(buf?=?file_get_contents(cfile,?&lbuf)))
				{
					free((void?*)cfile);
					lua_pushlstring(L,buf,?lbuf);
					goto?lua_tpl_compile_final;
				}
			}
		}
	}

	if(NULL?!=?(buf?=?file_get_contents(file,?&lbuf)))
	{
		automem_init(&mem,lbuf?+?1024);
		lua_tpl_compile_local(L,?&mem,?buf,?lbuf);
		free((void*)buf);
		lua_pushlstring(L,(char?*)mem.pdata,mem.size);
		if(0?!=?cache?&&?NULL?!=cfile)
			file_put_contents(cfile,&mem);

		automem_uninit(&mem);
	}

	if(NULL?!=?cfile)
		free((void?*)cfile);
lua_tpl_compile_final:
	return?1;
}

static?luaL_Reg?fmt_tpl_reg[]?=?{
	{"compile",lua_tpl_compile},
	{NULL,NULL}
};

int?luaopen_cfmt_tpl(lua_State?*?L)
{
	luaL_newlib(L,?fmt_tpl_reg);
	lua_cfmt_createmetatable(L);
	return?1;
}



整個(gè)LUA模塊擴(kuò)展就1個(gè)函數(shù) compile()。在LUA中的原型如下:


string??compile(filePath,cached,?write,?prefix,suffix,init)


功能: 將html模板編譯為lua代碼.

參數(shù):


filePath: html源文件的路徑.cached: 是否需要緩存.writer: 內(nèi)容輸出函數(shù)名.prefix: 文件分界符前綴.init:初始代碼,用于做參數(shù)展開之類的工作.


當(dāng)然,光有C的接口還不夠,為了使它變得簡(jiǎn)單易用,還需要用LUA對(duì)其包裝一下^_^, 包裝代碼如下:


function?util.tpl(writer)
	local?t?=??require?"cfmt.tpl"
	local?tpl?=?{}
	local?args?=?{}
	local?_prefix='[=['
	local?_suffix=']=]'
	--?創(chuàng)建的時(shí)候指定?writer
	if?nil?~=?writer?then?args['_']=writer?end
	
	function?tpl:assign(name,value)
		args[name]=value
	end
	
	function?tpl:boundary(prefix,?suffix)?--修改字符串邊界符
		if?nil?~=?prefix?then?_prefix=prefix?end
		if?nil?~=?suffix?then?_suffix=suffix?end
	end
	
	function?tpl:display(tpl,cache,writer)?--?tpl?模板文件位置,?cache?是否需要緩存?writer?可選,如果創(chuàng)建對(duì)象的時(shí)候指定了的話.
		local?i=1

		if?nil~=writer?then?args['_']=writer?end
		local?init?=?{'local?args?=?...'}
		for?key,val?in?pairs(args)?do
			init[#init+1]='local?'..key..'=args["'..key..'"]'
			i=i+1
		end

		init?=?table.concat(init,'n')
		local?code?=t.compile(tpl,cache,'_('.._prefix,?_suffix,init)
		load(code)(args)
	end
	return?tpl;
end




接下來(lái)用起來(lái)就簡(jiǎn)單多了,上測(cè)試代碼.


---外部進(jìn)來(lái)的數(shù)據(jù)在這里做檢測(cè)
function?login:request(r)

	local?tpl?=?(require?"util").tpl(r.print)
	
	local?users?={
		{['ID']=1,['username']='bywayboy',['age']=31},
		{['ID']=1,['username']='liigo',['age']=31},
		{['ID']=1,['username']='sunwei',['age']=8},

	}
	local?b={['a']=12}
	
	tpl:assign('users',users);
	tpl:assign('title',"測(cè)試模板變量.")
	tpl:assign('name',"某某童鞋")
	
	tpl:display("D:\VC\CmdChannel\win32\Debug\test.html",true)
end


再來(lái)一個(gè)模板文件示例:



{#_(title)#}--方121212法ID姓名年齡{#?for?key,val?in?pairs(users)?do#}{#_(val['ID'])?#}{#_(val['username'])#}{#_(val['age'])#}{#end#}{#_(name)#}


該文件最終生成的緩存文件為:



local?args?=?...
local?_=args["_"]
local?name=args["name"]
local?users=args["users"]
local?title=args["title"]
_([=[]=])
_(title)
_([=[--方121212法ID姓名年齡]=])
?for?key,val?in?pairs(users)?do
_([=[]=])
_(val['ID'])?
_([=[]=])
_(val['username'])
_([=[]=])
_(val['age'])
_([=[]=])
end
_([=[]=])
_(name)
_([=[]=])


輸出結(jié)果如圖:


最終生成的HTML代碼如下:

測(cè)試模板變量.--方121212法ID姓名年齡1bywayboy311liigo311sunwei8某某童鞋





本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉