C/C++程序使用lu对象作为配置文件
欢迎访问 Lu程序设计
C/C++程序使用lu对象作为配置文件
1 说明
要演示本文的例子,你必须下载Lu32脚本系统。本文的例子需要lu32.dll、lu32.lib、C格式的头文件lu32.h,相信你会找到并正确使用这几个文件。
用C/C++编译器创建一个控制台应用程序,复制本文的例子代码直接编译运行即可。
2 使用lu对象作为配置文件的格式
通常应用程序会有一些可调控的参数,简单的控制可以通过命令行参数来实现,然而复杂一些的则一般会使用配置文件的形式。本文讨论使用lu对象作为配置文件的格式及实现。关于lu对象,参考Lu用户指南;lu对象的数据结构参考Lu编程指南。
lu对象中的基本数据格式采取“键 : 值”的方式,键是以#开头的字符串,而值可为任意数据(本文代码支持的数据类型有lu对象、编译符#、逻辑值、nil、字符串、整数、实数)。例如:
????(:static)= global(true), static= lu{ ... ... , #name : "王刚", #age : 21, ... ... }
这是个无名函数,可以避免函数重名问题;函数 global(true)
使得lu对象成为全局对象,故通常要使用该函数;static是一个静态变量,将全局的lu对象保存在静态变量中可以避免被垃圾收集器回收。
lu对象可以嵌套,故可存储类似“键1 : 键2 : 键3 : 值”的数据,第1个键在第1层lu对象中,第2个键在第2层lu对象中,依此类推。例如:
??(:static)= global(true), static= lu{ "--- 使用字符串进行注释 ---" , ... ... , #生产部 : lu{ #staff : lu{ #王刚 : lu{ #age : 21, #性别 : "男", #工作量 : lu{11, 15}, #e_mail : "[email protected]" }, #李军 : lu{ #age : 25, #性别 : "男", #工作量 : lu{17, 1.2, 1.8}, #website : "http://www.lijun.net/" } } }, ... ... }
本例中李军的年龄可表示为“#生产部 : #staff : #李军 : #age : 25”,而李军的工作量是一个lu对象“#生产部 : #staff : #李军 : #工作量
: lu{17, 1.2, 1.8}”。
另外,Lu核心库支持的表达式中不能有注释,不过可以使用字符串作为注释,如上例。使用字符串作为注释的好处是:当我们重建配置文件时,注释仍然存在。
程序对配置文件的操作有三种:读配置文件,修改配置文件,写配置文件。在本文的例子中,读配置文件即编译一个返回lu对象(包含配置信息)的字符串表达式;修改配置文件即对该lu对象的成员进行存取;写配置文件即根据该lu对象生成相应的字符串表达式。
本文的代码中提供了3个实用的函数lu2str、getlumember、setlumember以更方便地操作lu对象,包含了完整的错误检查,故代码较长。
3 代码
#include <stdio.h> #include <string.h> #include <locale.h> #include "lu32.h" #pragma comment( lib, "lu32.lib" ) //输出lu对象到一个字符串,支持lu对象、编译符#、逻辑值、nil、字符串、整数、实数 int lu2str(LuData *pVal,wchar_t *luStr,int luStrMax,int *luStrNow) { luLu *plu; //lu对象指针 static luLu *pmainlu=NULL; //记住最初的lu对象,避免该函数无穷递归调用 static int kkk; int j; luVOID i,StrMax; luINT k; wchar_t *pStr; char str32[32]; int bBlank = 1, bKeyLu = 0; if(pVal->BType!=luDynData_lu) return 1; //无效的lu对象 //验证lu对象是否有效 plu=(luLu *)SearchKey((char *)&(pVal->x), sizeof(luVOID), luDynData_lu); if(NULL==plu) return 1; //无效的lu对象指针 if(plu==pmainlu) return 2; //递归嵌套的lu对象 if(pmainlu==NULL) { pmainlu=plu; //记住最初的lu对象 if(luStrMax<40) return 3; //缓冲区太小 wcscpy_s(luStr,luStrMax,L"(:static)= global(true), static=\r\nlu{\r\n"); *luStrNow=39; } kkk++; for(i=0;i<plu->Len;i++) { if(plu->Lu[i].BType==luStaData_struniint || plu->Lu[i].BType==luDynData_lu) bKeyLu=1; } if(bKeyLu==0) { if(luStr[*luStrNow-1]==‘\n‘) (*luStrNow)--; if(luStr[*luStrNow-1]==‘\r‘) (*luStrNow)--; if(luStr[*luStrNow]) luStr[*luStrNow]=‘\0‘; } for(i=0;i<plu->Len;i++) { if(bKeyLu==0) { bBlank = 0; if(luStr[*luStrNow-1]==‘\n‘) (*luStrNow)--; if(luStr[*luStrNow-1]==‘\r‘) (*luStrNow)--; if(luStr[*luStrNow]) luStr[*luStrNow]=‘\0‘; } if(bBlank) { if(luStrMax-(*luStrNow)<kkk*4) { kkk--; return 3; //缓冲区太小 } for(j=0;j<kkk*4;j++) luStr[(*luStrNow)++]=‘ ‘; luStr[*luStrNow]=‘\0‘; } else { bBlank = 1; } switch(plu->Lu[i].BType) { case luStaData_nil : //nil if(luStrMax-(*luStrNow)<5) { kkk--; return 3; //缓冲区太小 } wcscat_s(luStr,luStrMax,L"nil"); *luStrNow=*luStrNow+3; break; case luStaData_int64 : //整数 j=sprintf_s(str32,32,"%I64d",plu->Lu[i].x); if(j<0) { kkk--; return 4; //数据转换错误 } if(luStrMax-(*luStrNow)<j) { kkk--; return 3; //缓冲区太小 } for(j=0;str32[j];j++) luStr[(*luStrNow)++]=str32[j]; luStr[*luStrNow]=‘\0‘; break; case luStaData_double : //实数 j=sprintf_s(str32,32,"%f",*(double *)&(plu->Lu[i].x)); if(j<0) { kkk--; return 4; //数据转换错误 } if(luStrMax-(*luStrNow)<j) { kkk--; return 3; //缓冲区太小 } for(j=0;str32[j];j++) luStr[(*luStrNow)++]=str32[j]; luStr[*luStrNow]=‘\0‘; break; case luStaData_logical : //逻辑值 if(luStrMax-(*luStrNow)<8) { kkk--; return 3; //缓冲区太小 } if(plu->Lu[i].x) { wcscat_s(luStr,luStrMax,L"true"); *luStrNow=*luStrNow+4; } else { wcscat_s(luStr,luStrMax,L"false"); *luStrNow=*luStrNow+5; } break; case luStaData_struniint : //由字符串决定的唯一整数 pStr=(wchar_t *)UniIntToStr((luVOID)plu->Lu[i].x,&k); if(!pStr) { kkk--; return 4; //数据转换错误 } k=k/2; if(luStrMax-(*luStrNow)<=k) { kkk--; return 3; //缓冲区太小 } luStr[(*luStrNow)++]=‘#‘; for(j=0;j<(int)k;j++) luStr[(*luStrNow)++]=pStr[j]; luStr[*luStrNow]=‘\0‘; break; case luStaData_string : //静态字符串 case luDynData_string : //动态字符串 pStr=GetStr(plu->Lu+i,NULL,&StrMax); if(!pStr) { kkk--; return 4; //数据转换错误 } if(luStrMax-(*luStrNow)<2) { kkk--; return 3; //缓冲区太小 } luStr[(*luStrNow)++]=‘\"‘; for(j=0;j<pStr[j];j++) { if(luStrMax-(*luStrNow)<=3) { kkk--; return 3; //缓冲区太小 } switch(pStr[j]) { case ‘\\‘ : case ‘\"‘ : luStr[(*luStrNow)++]=‘\\‘; luStr[(*luStrNow)++]=pStr[j]; break; case ‘\a‘ : luStr[(*luStrNow)++]=‘\\‘; luStr[(*luStrNow)++]=‘a‘; break; case ‘\b‘ : luStr[(*luStrNow)++]=‘\\‘; luStr[(*luStrNow)++]=‘b‘; break; case ‘\f‘ : luStr[(*luStrNow)++]=‘\\‘; luStr[(*luStrNow)++]=‘f‘; break; case ‘\n‘ : luStr[(*luStrNow)++]=‘\\‘; luStr[(*luStrNow)++]=‘n‘; break; case ‘\r‘ : luStr[(*luStrNow)++]=‘\\‘; luStr[(*luStrNow)++]=‘r‘; break; case ‘\t‘ : luStr[(*luStrNow)++]=‘\\‘; luStr[(*luStrNow)++]=‘t‘; break; case ‘\v‘ : luStr[(*luStrNow)++]=‘\\‘; luStr[(*luStrNow)++]=‘v‘; break; default: luStr[(*luStrNow)++]=pStr[j]; } } luStr[(*luStrNow)++]=‘\"‘; luStr[*luStrNow]=‘\0‘; break; case luDynData_lu : //lu对象 if(luStrMax-(*luStrNow)<5) { kkk--; return 3; //缓冲区太小 } wcscat_s(luStr,luStrMax,L"lu{\r\n"); *luStrNow=*luStrNow+5; j=lu2str(plu->Lu+i,luStr,luStrMax,luStrNow); //递归调用 if(j) { kkk--; return j; //错误 } if(luStr[*luStrNow-1]==‘\n‘) { if(luStrMax-(*luStrNow)<kkk*4+3) { kkk--; return 3; //缓冲区太小 } for(j=0;j<kkk*4;j++) luStr[(*luStrNow)++]=‘ ‘; } luStr[(*luStrNow)++]=‘}‘; luStr[*luStrNow]=‘\0‘; break; default : j=sprintf_s(str32,32,"%I64d",plu->Lu[i].x); if(j<0) { kkk--; return 4; //数据转换错误 } if(luStrMax-(*luStrNow)<j+20) { kkk--; return 3; //缓冲区太小 } wcscat_s(luStr,luStrMax,L"\"不可识别对象 "); *luStrNow=*luStrNow+8; for(j=0;str32[j];j++) luStr[(*luStrNow)++]=str32[j]; luStr[(*luStrNow)++]=‘\"‘; luStr[*luStrNow]=‘\0‘; } if(luStrMax-(*luStrNow)<10) { kkk--; return 3; //缓冲区太小 } if(i+1!=plu->Len) { if(plu->Lu[i].BType==luStaData_struniint) bBlank = 0; if(i) { if(plu->Lu[i-1].BType==luStaData_struniint) bBlank = 1; } if(bBlank) { wcscat_s(luStr,luStrMax,L", \r\n"); *luStrNow=*luStrNow+4; } else { wcscat_s(luStr,luStrMax,L" : "); *luStrNow=*luStrNow+3; } } else { if(bKeyLu==1) { wcscat_s(luStr,luStrMax,L"\r\n"); *luStrNow=*luStrNow+2; } } } kkk--; if(kkk==0) { pmainlu=NULL; wcscat_s(luStr,luStrMax,L"}\r\n"); *luStrNow=*luStrNow+3; } return 0; } //获得lu对象成员的值,通过pme返回 //luMember存放以#开头的成员列表,0表示结束 int getlumember(LuData *pVal,luVOID *luMember,LuData **pme) { luLu *plu; //lu对象指针 luVOID i,j,k; for(i=0;luMember[i];i++) { if(pVal->BType!=luDynData_lu) return 1; //无效的lu对象 //验证lu对象是否有效 plu=(luLu *)SearchKey((char *)&(pVal->x), sizeof(luVOID), luDynData_lu); if(NULL==plu) return 1; //无效的lu对象指针 for(j=0;j<plu->Len;j++) { if(plu->Lu[j].BType==luStaData_struniint) { if((luVOID)plu->Lu[j].x==luMember[i]) { k=j+1; if(k<plu->Len) { pVal=plu->Lu+k; break; } } } } if(j==plu->Len) return 2; //没有找到对象成员 } *pme=pVal; return 0; } //设置lu对象成员的值 //luMember存放以#开头的成员列表,0表示结束;如果从luMember找到的成员是一个lu对象,一般index表示该lu对象成员的序号;index的意义取决于mode。 //mode表示工作模式。 //mode=0表示删除对象成员(键 : 值)。index、key_me和me被忽略。 //mode=1时,index=0表示用新的键值(键key_me : 值me)更新对象成员键值;index<0表示在对象成员前插入键值;index>0表示在对象成员后插入键值。 //mode=2表示直接用me更新对象成员的值。index和key_me被忽略。 //mode=3,从luMember找到的成员应是一个lu对象,更新该lu对象第index个成员。key_me被忽略。 //mode=4,从luMember找到的成员应是一个lu对象,从该lu对象第index个成员前插入me,若index<0或者大于原lu对象长度,从末尾插入me。key_me被忽略。 int setlumember(LuData *pVal,luVOID *luMember,int index,luVOID key_me,LuData *me,int mode) { luLu *plu,*plup; //lu对象指针 LuData *old; int kk; luVOID i,j,k; if(mode==0 || mode==1) //删除、更新、插入键值(键 : 值) { old=NULL; for(i=0;luMember[i];i++) { if(pVal->BType!=luDynData_lu) return 1; //无效的lu对象 //验证lu对象是否有效 plu=(luLu *)SearchKey((char *)&(pVal->x), sizeof(luVOID), luDynData_lu); if(NULL==plu) return 1; //无效的lu对象指针 for(j=0;j<plu->Len;j++) { if(plu->Lu[j].BType==luStaData_struniint) { if((luVOID)plu->Lu[j].x==luMember[i]) { k=j+1; if(k<plu->Len) { old=pVal; pVal=plu->Lu+k; break; } } } } if(j==plu->Len) return 2; //没有找到对象成员 } if(!old) return 2; //没有找到对象成员 if(mode==0) { plup=(luLu *)NewSysObj(luDynData_lu,plu->Len-2,0); if(!plup) return 3; //内存错误 for(i=0;i<j;i++) plup->Lu[i]=plu->Lu[i]; for(j=i+2;i<plup->Len;i++,j++) plup->Lu[i]=plu->Lu[j]; *(luVOID *)&(old->x)=(luVOID)plup; //更新lu对象 DeleteKey((char *)&plu,sizeof(luVOID),luDynData_lu,NULL,1); //销毁以前的lu对象 return 0; } if(index==0) { plu->Lu[j].x=key_me; *pVal=*me; return 0; } plup=(luLu *)NewSysObj(luDynData_lu,plu->Len+2,0); if(!plup) return 3; //内存错误 index = (index<0) ? j : k+1; for(i=0;i<index;i++) plup->Lu[i]=plu->Lu[i]; j=i; plup->Lu[i].BType=luStaData_struniint; plup->Lu[i].VType=luStaData_struniint; plup->Lu[i++].x=key_me; plup->Lu[i++]=*me; for(;i<plup->Len;i++,j++) plup->Lu[i]=plu->Lu[j]; *(luVOID *)&(old->x)=(luVOID)plup; //更新lu对象 DeleteKey((char *)&plu,sizeof(luVOID),luDynData_lu,NULL,1); //销毁以前的lu对象 return 0; } kk=getlumember(pVal,luMember,&old); if(kk) return kk; if(mode==2) //直接更新键值 { *old=*me; return 0; } if(old->BType!=luDynData_lu) return 1; //无效的lu对象 //验证lu对象是否有效 plu=(luLu *)SearchKey((char *)&(old->x), sizeof(luVOID), luDynData_lu); if(NULL==plu) return 1; //无效的lu对象指针 if(mode==3) //更新键值的成员 { if(index<0 || index>=plu->Len) return 2; //没有找到对象成员 plu->Lu[index]=*me; return 0; } else if(mode==4) //插入键值的成员 { plup=(luLu *)NewSysObj(luDynData_lu,plu->Len+1,0); if(!plup) return 3; //内存错误 if(index<0 || index>plu->Len) index=plu->Len; for(i=0;i<index;i++) plup->Lu[i]=plu->Lu[i]; j=i; plup->Lu[i++]=*me; for(;i<plup->Len;i++,j++) plup->Lu[i]=plu->Lu[j]; *(luVOID *)&(old->x)=(luVOID)plup; //更新lu对象 DeleteKey((char *)&plu,sizeof(luVOID),luDynData_lu,NULL,1); //销毁以前的lu对象 return 0; } else { return 4; //不正确的工作模式 } } void main(void) { void *hFor; //表达式句柄 luINT nPara; //存放表达式的自变量个数 LuData *pPara; //存放输入自变量的数组指针 luINT ErrBegin,ErrEnd; //表达式编译出错的初始位置和结束位置 int ErrCode; //错误代码 LuData Val; //Lu基本数据类型 wchar_t luStr[1000]; //保存由lu对象转换来的字符串表达式 int luStrNow; //接收luStr中的字符个数 luString *pString; //Lu动态字符串指针 wchar_t ForStr[]=L"(:static)= global(true), static=lu{\"--- 使用字符串进行注释 ---\" , #生产部 : lu{ #staff : lu{ #王刚 : lu{ #age : 21, #性别 : \"男\", #工作量 : lu{ 11, 15}, #e_mail : \"[email protected]\"}, #李军 : lu{ #age : 25, #性别 : \"男\", #工作量 : lu{ 17,1.2,1.8}, #website : \"http://www.lijun.net/\"}}}}"; //由字符串获得一个唯一的整数 luVOID ui_PD; //#生产部 luVOID ui_staff; //#staff luVOID ui_wanggang; //#王刚 luVOID ui_lijun; //#李军 luVOID ui_age; //#age luVOID ui_gender; //#性别 luVOID ui_workload; //#工作量 luVOID ui_e_mail; //#e_mail luVOID ui_website; //#website luVOID ui_addr; //#家庭地址 luVOID luMember[10]; //用以查找替换lu对象成员 LuData *pme; //Lu基本数据类型指针,用来返回lu对象 LuData me; //Lu基本数据类型,用来更新lu对象键值 setlocale(LC_ALL, "chs"); //设置可以输出中文 if(!InitLu()) return; //初始化Lu ui_PD = StrToUniInt((char *)L"生产部",6); //由字符串获得一个唯一的整数,下同 ui_staff = StrToUniInt((char *)L"staff",10); ui_wanggang = StrToUniInt((char *)L"王刚",4); ui_lijun = StrToUniInt((char *)L"李军",4); ui_age = StrToUniInt((char *)L"age",6); ui_gender = StrToUniInt((char *)L"性别",4); ui_workload = StrToUniInt((char *)L"工作量",6); ui_e_mail = StrToUniInt((char *)L"e_mail",12); ui_website = StrToUniInt((char *)L"website",14); ui_addr = StrToUniInt((char *)L"家庭地址",8); ErrCode=LuCom(ForStr,0,0,0,&hFor,&nPara,&pPara,&ErrBegin,&ErrEnd); //编译表达式 if(ErrCode) { printf("表达式有错误!错误代码: %d \n",ErrCode); } else { Val=LuCal(hFor,pPara); //计算表达式的值 if(Val.BType==luDynData_lu) { if(0==lu2str(&Val,luStr,1000,&luStrNow)) //输出lu对象的值 { wprintf(L"%s",luStr); } //luMember中存放键的位置“#生产部 : #staff : #王刚 : #age” luMember[0]=ui_PD; luMember[1]=ui_staff; luMember[2]=ui_wanggang; luMember[3]=ui_age; luMember[4]=0; if(0==getlumember(&Val,luMember,&pme)) { wprintf(L"\r\n查找到 #生产部 : #staff : #王刚 : #age : %I64d\r\n\r\n",pme->x); } //luMember中存放键的位置“#生产部 : #staff : #李军 : #工作量” luMember[0]=ui_PD; luMember[1]=ui_staff; luMember[2]=ui_lijun; luMember[3]=ui_workload; luMember[4]=0; pString=(luString *)NewSysObj(luDynData_string,80,0); if(pString) wcscpy_s(pString->Str,80,L"XX省XX市XX区XX路100号大院60#7楼 邮政编码:123456"); me.BType=luDynData_string; me.VType=luDynData_string; me.x=0; *(luVOID *)&(me.x)=(luVOID)pString; setlumember(&Val,luMember,-1,ui_addr,&me,1); //在李军工作量前面增加家庭地址 //luMember中存放键的位置“#生产部 : #staff : #李军 : #工作量” luMember[0]=ui_PD; luMember[1]=ui_staff; luMember[2]=ui_lijun; luMember[3]=ui_workload; luMember[4]=0; me.BType=luStaData_double; me.VType=luStaData_double; *(double *)&(me.x)=12.3; setlumember(&Val,luMember,-1,0,&me,4); //李军的工作量增加12.3,添加到末尾 if(0==lu2str(&Val,luStr,1000,&luStrNow)) //输出lu对象的值 { wprintf(L"%s",luStr); } } } FreeLu(); //释放Lu }
运行结果:
(:static)= global(true), static= lu{ "--- 使用字符串进行注释 ---", #生产部 : lu{ #staff : lu{ #王刚 : lu{ #age : 21, #性别 : "男", #工作量 : lu{11, 15}, #e_mail : "[email protected]" }, #李军 : lu{ #age : 25, #性别 : "男", #工作量 : lu{17, 1.200000, 1.800000}, #website : "http://www.lijun.net/" } } } } 查找到 #生产部 : #staff : #王刚 : #age : 21 (:static)= global(true), static= lu{ "--- 使用字符串进行注释 ---", #生产部 : lu{ #staff : lu{ #王刚 : lu{ #age : 21, #性别 : "男", #工作量 : lu{11, 15}, #e_mail : "[email protected]" }, #李军 : lu{ #age : 25, #性别 : "男", #家庭地址 : "XX省XX市XX区XX路100号大院60#7楼 邮政编码:123456", #工作量 : lu{17, 1.200000, 1.800000, 12.300000}, #website : "http://www.lijun.net/" } } } }
4 函数说明
本例用到了Lu的10个输出函数:初始化Lu的函数InitLu,释放Lu的函数FreeLu,编译表达式的函数LuCom、计算表达式的函数LuCal、申请系统内置动态对象函数NewSysObj、查找键值函数SearchKey、 删除键值函数DeleteKey、由字符串获得一个唯一的整数StrToUniInt、由一个唯一的整数获得字符串UniIntToStr、获得字符串函数GetStr、。从这里查看这些函数的说明:Lu编程指南。
5 难点分析
代码中提供了3个实用的函数lu2str、getlumember、setlumember以更方便地操作lu对象。
lu2str:输出lu对象到一个字符串,该字符串用LuCom编译后运行,可重新得到该lu对象。
getlumember:获得lu对象成员的值。输入参数是类似“键1 : 键2 : 键3 : 0”的整数数组,每一个键是由字符串(Lu脚本中,键以#开头)获得的一个唯一的整数(用StrToUniInt转换)。
setlumember: 设置lu对象成员的值。可对lu对象的键值进行重置、插入、删除等操作。
程序主要操作步骤如下:
(1)对返回lu对象(包含了配置信息)的字符串表达式ForStr进行编译运行;
(2)用函数lu2str将lu对象转换为字符串表达式并输出;
(3)从lu对象中查询键“#生产部 : #staff : #王刚 : #age”并输出结果;
(4)在lu对象中“#生产部 : #staff : #李军 : #工作量”位置前插入键(#家庭地址 : "XX省XX市XX区XX路100号大院60#7楼 邮政编码:123456");
(5)在lu对象中“#生产部 : #staff : #李军 : #工作量”位置添加键成员(即将lu{17, 1.2, 1.8}修改为lu{17, 1.2, 1.8, 12.3});
(6)用函数lu2str将lu对象转换为字符串表达式并输出。
6 其他
你可能注意到了,我的联系方式就在下面,如有不明之处或有什么建议,可随时与我进行联系。
版权所有? Lu程序设计 2002-2013,保留所有权利
E-mail: [email protected] QQ:630715621
最近更新: 2014年01月12日
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。