该版本在builtin内建模块中添加了如下模块函数:bltInt:将参数转为整数,bltFloat:将参数转为浮点数,bltHtmlEscape:对参数进行html转义,当前版本使用v1.8.1版本的zengl语言库,该版本的语言库修复了一些bug...

    页面导航: 项目下载地址:

    zenglServer源代码的相关地址:https://github.com/zenglong/zenglServer  当前版本对应的tag标签为:v0.10.1

zenglServer v0.10.1:

    该版本在builtin内建模块中添加了如下模块函数:

    bltInt:将参数转为整数

    bltFloat:将参数转为浮点数

    bltHtmlEscape:对参数进行html转义

    同时对bltJsonEncode内建模块函数进行了调整,在数组转json时,如果是空数组则返回[],相关C源码位于module_builtin.c文件中:

/**
 * 将zengl脚本中的数组转为json格式,并追加到infoString动态字符串
 * 如果数组中还包含了数组,那么所包含的数组在转为json时,会递归调用当前函数
 * 如果数组成员有对应的哈希key(字符串作为key),那么生成的json会用大括号包起来
 * 例如:{"hello":"world","name":"zengl"}
 * 如果数组成员没有哈希key,那么生成的json会用中括号包起来
 * 例如:[1,2,3,3.14159,"zengl language"]
 */
static void builtin_write_array_to_string(ZL_EXP_VOID * VM_ARG, BUILTIN_INFO_STRING * infoString, ZENGL_EXPORT_MEMBLOCK memblock)
{
	...............................................................
	zenglApi_GetMemBlockInfo(VM_ARG,&memblock,&size,ZL_EXP_NULL);
	count = zenglApi_GetMemBlockNNCount(VM_ARG, &memblock);
	if(count > 0)
	{
		............................................................
	}
	else if(count == 0) { // 如果有效成员数为0,则返回[]也就是空数组
		builtin_make_info_string(VM_ARG, infoString, "[]");
	}
}

/**
 * 这是一个供其他模块函数调用的辅助函数,用于将str字符串进行html转义
 * html转义过程中,会将&替换为&amp; 将双引号替换为&quot; 将单引号替换为 &#39; 将左尖括号<替换为&lt; 将右尖括号>替换为&gt;
 */
static void builtin_html_escape_str(ZL_EXP_VOID * VM_ARG, BUILTIN_INFO_STRING * infoString, char * str)
{
	const char * html_escape_table[] = {"", "&amp;", "&quot;", "&#39;", "&lt;", "&gt;"}; // &, ", ', <, >
	char * start = str;
	int str_len = strlen(str);
	int escape_index = 0;
	int i;
	for(i = 0; i < str_len;i++) {
		switch(str[i]) {
		case '&':
			escape_index = 1;
			break;
		case '"':
			escape_index = 2;
			break;
		case '\'':
			escape_index = 3;
			break;
		case '<':
			escape_index = 4;
			break;
		case '>':
			escape_index = 5;
			break;
		default:
			continue;
		}
		if(escape_index > 0) {
			char tmp = str[i];
			str[i] = '\0';
			builtin_make_info_string(VM_ARG, infoString, "%s%s", start, html_escape_table[escape_index]);
			str[i] = tmp;
			start = str + (i + 1);
		}
	}
	if(infoString->str != NULL) {
		if((start - str) < i) {
			builtin_make_info_string(VM_ARG, infoString, "%s", start);
		}
	}
}

..............................................................

/**
 * bltInt模块函数,返回第一个参数的整数形式
 * 例如:
 * test = "12345abc";
 * print 'test: ' + test + '<br/>';
 * print 'bltInt(test): ' + bltInt(test) + '<br/>';
 * 执行结果如下:
 * test: 12345abc
 * bltInt(test): 12345
 * 如果将第二个参数设置为非0值,bltInt会同时将转化的结果赋值给第一个参数(需要将第一个参数的引用传递过来)
 * 例如:
 * def TRUE 1;
 * def FALSE 0;
 * test = "12345abc";
 * print 'test: ' + test + '<br/>';
 * print 'bltInt(&amp;test, TRUE): ' + bltInt(&test, TRUE) + '<br/>';
 * print 'test: ' + test + '<br/><br/>';
 * 执行结果如下:
 * test: 12345abc
 * bltInt(&test, TRUE): 12345
 * test: 12345
 * 在经过bltInt(&test, TRUE);转化后,test就被转为了整数
 */
ZL_EXP_VOID module_builtin_int(ZL_EXP_VOID * VM_ARG,ZL_EXP_INT argcount)
{
	ZENGL_EXPORT_MOD_FUN_ARG arg = {ZL_EXP_FAT_NONE,{0}};
	if(argcount < 1)
		zenglApi_Exit(VM_ARG,"usage: bltInt(data|&data[, isSetData=0])");
	zenglApi_GetFunArg(VM_ARG,1,&arg);
	int isSetData = ZL_EXP_FALSE;
	if(argcount >= 2) {
		ZENGL_EXPORT_MOD_FUN_ARG arg2 = {ZL_EXP_FAT_NONE,{0}};
		zenglApi_GetFunArg(VM_ARG,2,&arg2);
		if(arg2.type != ZL_EXP_FAT_INT)
			zenglApi_Exit(VM_ARG,"the second argument isSetData of bltInt must be integer");
		isSetData = arg2.val.integer;
	}
	ZL_EXP_LONG retval;
	switch(arg.type) {
	case ZL_EXP_FAT_STR:
		retval = atol((const char *)arg.val.str);
		break;
	case ZL_EXP_FAT_INT:
		retval = arg.val.integer;
		break;
	case ZL_EXP_FAT_FLOAT:
		retval = (ZL_EXP_LONG)arg.val.floatnum;
		break;
	default:
		retval = 0;
		break;
	}
	if(isSetData) {
		if(arg.type != ZL_EXP_FAT_INT) {
			arg.type = ZL_EXP_FAT_INT;
			arg.val.integer = retval;
			zenglApi_SetFunArg(VM_ARG,1,&arg);
		}
	}
	zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_INT, ZL_EXP_NULL, retval, 0);
}

/**
 * bltFloat模块函数,返回第一个参数的浮点数形式
 * 例如:
 * test2 = "3.14159mdbknf";
 * print 'test2: ' + test2 + '<br/>';
 * print 'bltFloat(test2): ' + bltFloat(test2) + '<br/>';
 * 执行结果如下:
 * test2: 3.14159mdbknf
 * bltFloat(test2): 3.14159
 * 如果将第二个参数设置为非0值,bltFloat会同时将转化的结果赋值给第一个参数(需要将第一个参数的引用传递过来)
 * def TRUE 1;
 * def FALSE 0;
 * test2 = "3.14159mdbknf";
 * print 'test2: ' + test2 + '<br/>';
 * print 'bltFloat(&amp;test2, TRUE): ' + bltFloat(&test2, TRUE) + '<br/>';
 * print 'test2: ' + test2 + '<br/><br/>';
 * 执行结果如下:
 * test2: 3.14159mdbknf
 * bltFloat(&test2, TRUE): 3.14159
 * test2: 3.14159
 * 在经过bltFloat(&test2, TRUE);转化后,test2就被转为了浮点数
 */
ZL_EXP_VOID module_builtin_float(ZL_EXP_VOID * VM_ARG,ZL_EXP_INT argcount)
{
	ZENGL_EXPORT_MOD_FUN_ARG arg = {ZL_EXP_FAT_NONE,{0}};
	if(argcount < 1)
		zenglApi_Exit(VM_ARG,"usage: bltFloat(data|&data[, isSetData=0])");
	zenglApi_GetFunArg(VM_ARG,1,&arg);
	int isSetData = ZL_EXP_FALSE;
	if(argcount >= 2) {
		ZENGL_EXPORT_MOD_FUN_ARG arg2 = {ZL_EXP_FAT_NONE,{0}};
		zenglApi_GetFunArg(VM_ARG,2,&arg2);
		if(arg2.type != ZL_EXP_FAT_INT)
			zenglApi_Exit(VM_ARG,"the second argument isSetData of bltFloat must be integer");
		isSetData = arg2.val.integer;
	}
	ZL_EXP_DOUBLE retfloat;
	switch(arg.type) {
	case ZL_EXP_FAT_STR:
		retfloat = atof((const char *)arg.val.str);
		break;
	case ZL_EXP_FAT_INT:
		retfloat = (ZL_EXP_DOUBLE)arg.val.integer;
		break;
	case ZL_EXP_FAT_FLOAT:
		retfloat = arg.val.floatnum;
		break;
	default:
		retfloat = 0;
		break;
	}
	if(isSetData) {
		if(arg.type != ZL_EXP_FAT_FLOAT) {
			arg.type = ZL_EXP_FAT_FLOAT;
			arg.val.floatnum = retfloat;
			zenglApi_SetFunArg(VM_ARG,1,&arg);
		}
	}
	zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_FLOAT, ZL_EXP_NULL, 0, retfloat);
}

..............................................................

/**
 * bltHtmlEscape模块函数,将字符串进行html转义,并将转义的结果返回
 * html转义过程中,会将&替换为&amp; 将双引号替换为&quot; 将单引号替换为 &#39; 将左尖括号<替换为&lt; 将右尖括号>替换为&gt;
 * 例如:
 * test3 = '大家好&"\'<html></html>&&&';
 * print 'bltHtmlEscape(test3): ' +bltHtmlEscape(test3) + '<br/>';
 * 执行结果如下:
 * bltHtmlEscape(test3): 大家好&amp;&quot;&#39;&lt;html&gt;&lt;/html&gt;&amp;&amp;&amp;<br/>
 * 如果将第二个参数设置为非0值,bltHtmlEscape会同时将转化的结果赋值给第一个参数(需要将第一个参数的引用传递过来)
 * 例如:
 * use builtin;
 * def TRUE 1;
 * def FALSE 0;
 * test3 = '大家好&"\'<html></html>&&&';
 * print 'bltHtmlEscape(&amp;test3, TRUE): ' + bltHtmlEscape(&test3, TRUE) + '<br/>';
 * print 'test3: ' + test3 + '<br/><br/>';
 * 执行结果如下:
 * bltHtmlEscape(&amp;test3, TRUE): 大家好&amp;&quot;&#39;&lt;html&gt;&lt;/html&gt;&amp;&amp;&amp;<br/>
 * test3: 大家好&amp;&quot;&#39;&lt;html&gt;&lt;/html&gt;&amp;&amp;&amp;<br/><br/>
 */
ZL_EXP_VOID module_builtin_html_escape(ZL_EXP_VOID * VM_ARG,ZL_EXP_INT argcount)
{
	ZENGL_EXPORT_MOD_FUN_ARG arg = {ZL_EXP_FAT_NONE,{0}};
	if(argcount < 1)
		zenglApi_Exit(VM_ARG,"usage: bltHtmlEscape(str|&str[, isSetData=0])");
	zenglApi_GetFunArg(VM_ARG,1,&arg);
	int isSetData = ZL_EXP_FALSE;
	if(argcount >= 2) {
		ZENGL_EXPORT_MOD_FUN_ARG arg2 = {ZL_EXP_FAT_NONE,{0}};
		zenglApi_GetFunArg(VM_ARG,2,&arg2);
		if(arg2.type != ZL_EXP_FAT_INT)
			zenglApi_Exit(VM_ARG,"the second argument isSetData of bltHtmlEscape must be integer");
		isSetData = arg2.val.integer;
	}
	BUILTIN_INFO_STRING infoString = { 0 };
	switch(arg.type) {
	case ZL_EXP_FAT_STR:
		builtin_html_escape_str(VM_ARG, &infoString, arg.val.str);
		break;
	case ZL_EXP_FAT_INT: // 整数直接返回原值
		zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_INT, ZL_EXP_NULL, arg.val.integer, 0);
		return;
	case ZL_EXP_FAT_FLOAT: // 浮点数直接返回原值
		zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_FLOAT, ZL_EXP_NULL, 0, arg.val.floatnum);
		return;
	case ZL_EXP_FAT_MEMBLOCK: // 数组之类的内存块也直接返回原内存块
		zenglApi_SetRetValAsMemBlock(VM_ARG,&arg.val.memblock);
		return;
	default: // 其他类型统一设置为空字符串
		builtin_make_info_string(VM_ARG, &infoString, "");
		break;
	}
	if(infoString.str != NULL) {
		zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_STR, infoString.str, 0, 0);
		if(isSetData) {
			arg.type = ZL_EXP_FAT_STR;
			arg.val.str = infoString.str;
			zenglApi_SetFunArg(VM_ARG,1,&arg);
		}
		zenglApi_FreeMem(VM_ARG, infoString.str);
	}
	else
		zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_STR, arg.val.str, 0, 0);
}

/**
 * builtin模块的初始化函数,里面设置了与该模块相关的各个模块函数及其相关的处理句柄
 */
ZL_EXP_VOID module_builtin_init(ZL_EXP_VOID * VM_ARG,ZL_EXP_INT moduleID)
{
	.............................................................
	zenglApi_SetModFunHandle(VM_ARG,moduleID,"bltInt",module_builtin_int);
	zenglApi_SetModFunHandle(VM_ARG,moduleID,"bltFloat",module_builtin_float);
	.............................................................
	zenglApi_SetModFunHandle(VM_ARG,moduleID,"bltHtmlEscape",module_builtin_html_escape);
}


    此外,当前版本使用v1.8.1版本的zengl语言库,该版本的语言库修复了一些bug。详情可以参考zengl编程语言栏目的“zengl v1.8.1 修复bug”对应的文章。

    当前版本还修复了r调试命令会多返回一层的问题,同时添加了e调试命令,e命令可以在调试的过程中直接终止脚本。相关C源码位于debug.c文件中:

/**
 * r命令:执行到返回
 ..............................................................
 */
static void debug_command_run_to_return(ZL_EXP_VOID * VM_ARG, DEBUG_INFO * debug_info, int * exit)
{
	..........................................................
	ret = zenglApi_DebugGetTrace(VM_ARG,&arg,&loc,&pc,&fileName,&line,ZL_EXP_NULL,ZL_EXP_NULL);
	if(ret == 1)
	{
		//zenglApi_DebugGetTrace(VM_ARG,&arg,&loc,&pc,&fileName,&line,ZL_EXP_NULL,ZL_EXP_NULL);
		pc++;
		.......................................................
	}
}

...............................................................

/**
 * h命令:显示帮助信息,帮助信息中可以看到各个命令的基本用法
 */
static void debug_command_help(ZL_EXP_VOID * VM_ARG, DEBUG_INFO * debug_info)
{
	builtin_make_info_string(VM_ARG, &debug_info->format_send_msg,
			................................................
			" r 执行到返回 usage:r\n"
			" c 继续执行 usage:c\n"
			" e 退出,停止执行 usage:e\n"
			" l 显示源码 usage:l filename [lineNumber[ offset]] | l [lineNumber[ offset]]\n"
			" u 执行到指定的行 usage:u filename lineNumber | u lineNumber\n"
			" h 显示帮助信息\n");
}

...............................................................

/**
 * 中断回调函数,如果zenglServer开启了调试功能,那么当触发断点时,就会调用此回调函数
 * 在该回调函数中,可以接收远程调试器发来的各种调试命令,并将调试结果通过连接套接字反馈给远程调试器
 */
ZL_EXP_INT debug_break(ZL_EXP_VOID * VM_ARG,ZL_EXP_CHAR * cur_filename,
		ZL_EXP_INT cur_line,ZL_EXP_INT breakIndex,ZL_EXP_CHAR * log)
{
	.............................................................
	switch(command[0])
	{
	...............................................................
	case 'e': // 退出,停止执行
		zenglApi_Stop(VM_ARG);
		exit = 1;
		builtin_make_info_string(VM_ARG, &debug_info->format_send_msg, "{\"exit\":%d}", exit);
		break;
	...............................................................
	}
	.............................................................
}


    上面r调试命令之前多调用了一次zenglApi_DebugGetTrace接口,所以之前的版本调试时有可能会多返回一层,当前版本将多调用的接口给注释掉了。还可以看到,e命令是通过调用zenglApi_Stop接口来终止脚本的。

    对pydebugger/TCPServer.py进行了调整,如果用户输入的是空命令(例如用户什么也没输,直接敲了回车),则直接使用上一次输入过的命令。如果之前没输入过命令,则使用默认的l命令。此外,单步中断时,会显示Single Break,之前显示的是breakIndex:-1,TCPServer.py中主要调整的代码如下:

# -*- coding: utf-8 -*-
# 请使用python3运行本脚本
........................................................

# MyTCPHandler类会在每次接收到连接时被实例化一次,并通过handle方法去处理连接
class MyTCPHandler(socketserver.BaseRequestHandler):
	.....................................................
	command = 'l' # 记录用户上一次输入过的命令,默认为l命令即显示源码

	.....................................................

	# 如果输入的是空命令(例如用户什么也没输,直接敲了回车),则将上一次输入的命令返回,如果上一次没输入过命令,则将默认的l命令返回
	def get_empty_command(self):
		if self.command == '':
			self.command = 'l'
		return self.command

	# 将用户输入的命令记录到self.command中,以便下一次用户输入空命令时使用
	def set_empty_command(self, command = ''):
		if command != '' and self.command != command:
			self.command = command

	# handle方法用于处理调试器接收到的zenglServer连接,该方法会将用户输入的调试命令,通过连接发送给zenglServer,并将zenglServer返回的结果显示出来
	def handle(self):
		........................................................
		# 将中断发生的脚本文件名(包括目录路径在内),行号,触发的断点索引,主执行脚本文件路径等打印出来
		if(cur_normal_path == main_normal_path):
			format_str = "file:{},line:{},{}" # 如果当前执行脚本就是主执行脚本的话,则不显示main_script和dir_path信息
		else:
			format_str = "file:{},line:{},{}  [main_script:{}, dir_path:{}]"
		breakIndex = recv_msg_decode['breakIndex']
		print(format_str.format(self.cur_filename, self.cur_line, 
			"breakIndex:{}".format(breakIndex) if breakIndex != -1 else "Single Break", # breakIndex为-1,表示单步执行时发生的中断
			self.main_script_filename, self.dir_path))
		........................................................
		while(True): # 循环接受用户输入的调试命令
			input_command = input('zl debug >>> ').strip()
			command_list = self.get_command_list(input_command)
			if(" ".join(command_list) == ''):
				# print('command is empty')
				input_command = self.get_empty_command()
				command_list = self.get_command_list(input_command)
			else:
				self.set_empty_command(input_command)
			........................................................


    添加测试脚本:my_webroot/v0_10_1/test.zl,测试脚本中包含了bltInt之类的模块函数的使用示例:

use builtin;
def TRUE 1;
def FALSE 0;

print '<!Doctype html>
<html>
<head><meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>测试bltInt,bltFloat,bltHtmlEscape等</title>
</head>
<body>';

fun test()
	a['test'] = bltArray();
	a['test', 'name'] = 'zengl';
	print 'test,name: '+a['test', 'name'] + '<br/>';
	return a['test']; // 测试返回数组成员
endfun

b = test();
b = b; // 测试是否会释放掉自己
print 'b,name: '+b['name'] + '<br/><br/>';

test = "12345abc";
print 'test: ' + test + '<br/>';
print 'bltInt(test): ' + bltInt(test) + '<br/>';
print 'test: ' + test + '<br/>';
print 'bltInt(&test, TRUE): ' + bltInt(&test, TRUE) + '<br/>';
print 'test: ' + test + '<br/><br/>';

test2 = "3.14159mdbknf";
print 'test2: ' + test2 + '<br/>';
print 'bltFloat(test2): ' + bltFloat(test2) + '<br/>';
print 'test2: ' + test2 + '<br/>';
print 'bltFloat(&test2, TRUE): ' + bltFloat(&test2, TRUE) + '<br/>';
print 'test2: ' + test2 + '<br/><br/>';

test3 = '大家好&"\'<html></html>&&&';
print 'bltHtmlEscape(test3): ' +bltHtmlEscape(test3) + '<br/>';
print 'bltHtmlEscape(&test3, TRUE): ' + bltHtmlEscape(&test3, TRUE) + '<br/>';
print 'test3: ' + test3 + '<br/><br/>';

print 'empty array to json: ' + bltJsonEncode(bltArray()) + '<br/><br/>';

zls_version = bltGetZenglServerVersion();
print 'zenglServer版本号:' + zls_version[0] + '.' + zls_version[1] + '.' + zls_version[2] + '<br/>';
zl_version = bltGetZenglVersion();
print 'zengl语言版本号:' + zl_version[0] + '.' + zl_version[1] + '.' + zl_version[2];

print '</body></html>';


    在浏览器中的执行结果如下:


图1:my_webroot/v0_10_1/test.zl执行结果

    test3经过html转义后,就可以在浏览器中正常显示了。

    以上就是当前版本的相关内容。OK,就到这里,休息,休息一下 o(∩_∩)o~~

结束语:

    有人说:常人选择看到希望才坚持  但疯子相信只有坚持了才会看到希望

——  《导火新闻线》
 
上下篇

下一篇: zenglServer v0.11.0 共享内存,crustache转义,magick模块,新增bltDate等内建模块函数

上一篇: zenglServer v0.10.0 使用zengl脚本的编译缓存,跳过编译过程

相关文章

zenglServer v0.8.0-v0.8.1

zenglServer v0.13.0 目录入口文件以及模板路径调整

zenglServer v0.23.0 使用v1.8.3版本的zengl语言,增加bltTrim等模块函数,支持中文url路径等

zenglServer v0.16.0 增加curlSetPostByHashArray,curlSetHeaderByArray模块函数,调整进程名称等

zenglServer v0.21.0 增加base64编解码相关的内建模块函数

zenglServer v0.11.0 共享内存,crustache转义,magick模块,新增bltDate等内建模块函数