C++編程之配置文件解析:在實際項目中,經常會把軟件的某些選項寫入配置文件。 Windows 平台上的 INI 文件格式簡單易用,設計了一個“類” ini_parser 來讀寫 INI 格式的配置文件。
struct ini_parser 可以解析 INI 格式的字符串、文件,也可以將內存中的符合 INI 格式的數據寫入文件,能夠支持 Windows 、Linux、Android等多平台。目前暫不支持選項分組功能。
功能相對簡單,直接看源碼吧。
下面是頭文件:
structsingle_list; structini_parser{ structsingle_list*keyvalues; int(*parse_file)(structini_parser*,constchar*file); int(*parse_string)(structini_parser*,constchar*text); char*(*value)(structini_parser*,constchar*key); void(*set_value)(structini_parser*,constchar*key,constchar*value); void(*remove)(structini_parser*,constchar*key); int(*save_to_file)(structini_parser*,constchar*file); void(*deletor)(structini_parser*ini); }; structini_parser*new_ini_parser(); struct init_parser 的聲明符合我們在本系列文章中提到的面向對象框架,需要說明的是,一旦 deletor 方法被調用, ini_parser 的實例將不再允許訪問。 下面是源文件: #include"ini_parser.h" #includ e #include structtag_value_pair{ structslist_nodenode; char*szTag; char*szValue; }; typedefstructtag_value_pairtag_value; staticvoid_tag_value_free(structslist_node*node) { if(node)delete_tag_value_pair(node); } staticint_tag_value_hittest(structslist_node*node,void*key) { returnstrcmp((char*)tag,((structtag_value_pair*)node)->szTag); } staticstructsingle_list*new_tag_value_list() { returnnew_single_list(_tag_value_free,_tag_value_hittest); } staticstructtag_value_pair*new_tag_value_pair() { structtag_value_pair*pair=(structtag_value_pair*)malloc(sizeof(structtag_value_pair)); pair->node.next=0; pair->szTag=0; pair->szValue=0; returnpair; } staticstructtag_value_pair*make_tag_value_pair(char*tag,char*value) { structtag_value_pair*pair=0; if(!tag||!value)return0; pair=(structtag_value_pair*)malloc(sizeof(structtag_value_pair)); pair->szTag=strdup(tag); pair->szValue=strdup(value); pair->node.next=0; returnpair; } staticstructtag_value_pair*parse_line(char*line,intlen) { structtag_value_pair*pair=0; intcount=0; char*p=line; char*end=0;m char*start=line; if(!p)return0; while(*p=='')++p; /*blankline*/ if(p-line==len|| *p=='\r'|| *p=='\n'|| *p=='\0')return0; /*donotsupportgroup*/ if(*p=='[')return0; /*comments*/ if(*p=='#')return0; /*extractkey*/ start=p; end=line+len; while(*p!='='&&p!=end)++p; if(p==end) { /*none'=',invalidline*/ return0; } end=p-1; while(*end=='')--end;/*skipblankattheend*/ count=end-start+1; pair=new_tag_value_pair(); pair->szTag=malloc(count+1); strncpy(pair->szTag,start,count); pair->szTag[count]=0; /*extractvalue*/ ++p; end=line+len;/*nextposofthelastchar*/ while(*p==''&&p!=end)++p; if(p==end) { delete_tag_value_pair(pair); return0; } start=p; --end;/*tothelastchar*/ if(*end=='\n'){*end=0;--end;} if(*end=='\r'){*end=0;--end;} count=end-start+1; if(count>0) { pair->szValue=malloc(count+1); strncpy(pair->szValue,start,count); pair->szValue[count]=0; } /*releaseemptykey-valuepair*/ if(!pair->szValue) { delete_tag_value_pair(pair); return0; } returnpair; } staticint_parse_file(structini_parser*ini,constchar*file){ FILE*fp=fopen(file,"r"); if(fp) { structtag_value_pair*pair=0; charbuf[1024]={0}; while(fgets(buf,1024,fp)) { pair=parse_line(buf,strlen(buf)); if(pair) { ini->keyvalues->add(ini->keyvalues,pair); } } fclose(fp); returnini->keyvalues->size; } return-1; } staticint_parse_text(structini_parser*ini,constchar*text){ char*p=text; char*start=0; structtag_value_pair*pair=0; if(!text)return-1; while(1) { start=p; while(*p!='\n'&&*p!='\0')++p; if(*p=='\0')break; pair=parse_line(start,p-start); if(pair)ini->keyvalues->add(ini->keyvalues,pair); ++p; } returnini->keyvalues->size; } staticchar*_value(structini_parser*ini,constchar*key){ structtag_value_pair*pair=NODE_T(ini->keyvalues->find_by_key(ini->keyvalues,key),structtag_value_pair); if(pair)returnpair->szValue; return0; } staticvoid_set_value(structini_parser*ini,constchar*key,constchar*value){ structtag_value_pair*pair=NODE_T(ini->keyvalues->find_by_key(ini->keyvalues,key),structtag_value_pair); if(pair) { if(pair->szValue)free(pair->szValue); pair->szValue=strdup(value); } else { ini->keyvalues->add(ini->keyvalues,make_tag_value_pair(key,value)); } } staticvoid_remove(structini_parser*ini,constchar*key){ structtag_value_pair*pair=NODE_T(ini->keyvalues->find_by_key(ini->keyvalues,key),structtag_value_pair); if(pair)ini->keyvalues->remove(ini->keyvalues,pair); } staticvoidwrite_keyvalue(structtag_value_pair*pair,FILE*fp) { fputs(pair->szTag,fp); fputc('=',fp); fputs(pair->szValue,fp); fputc('\n',fp); } staticint_save_to_file(structini_parser*ini,constchar*file){ if(ini->keyvalues->size>0) { FILE*fp=fopen(file,"w"); if(fp) { structtag_value_pair*pair=NODE_T(ini->keyvalues->head,structtag_value_pair); while(pair!=0) { write_keyvalue(pair,fp); pair=NODE_T(pair->node.next,structtag_value_pair); } fclose(fp); return0; } } return-1; } staticvoid_delete_ini_parser(structini_parser*ini){ if(ini) { ini->keyvalues->deletor(ini->keyvalues); free(ini); } } structini_parser*new_ini_parser(){ structini_parser*ini=(structini_parser*)malloc(sizeof(structini_parser)); ini->keyvalues=new_tag_value_list(); ini->parse_file=_parse_file; ini->parse_string=_parse_text; ini->value=_value; ini->set_value=_set_value; ini->remove=_remove; ini->save_to_file=_save_to_file; ini->deletor=_delete_ini_parser; returnini; } 下面是簡單的測試代碼: view plaincopy 在CODE上查看代碼片派生到我的代碼片 staticchar*g_szIniString="#abc\nfirst=2\nsecond\nname=charlizhang\n"; staticvoidini_parser_test_string() { structini_parser*ini=new_ini_parser(); intsize=ini->parse_string(ini,g_szIniString); assert(size>0); assert(ini->value(ini,"second")==0); assert(ini->value(ini,"abc")==0); assert(ini->value(ini,"name")!=NULL); assert(ini->value(ini,"first")!=NULL); printf("inistring:%s\n",g_szIniString); printf("key-valuepairscount=%d\n",size); printf("key\'name\'',value=%s\n",ini->value(ini,"name")); printf("key\'first\'',value=%s\n",ini->value(ini,"first")); ini->set_value(ini,"baidu","hahaha"); ini->save_to_file(ini,"write.conf"); ini->remove(ini,"first"); ini->save_to_file(ini,"write2.conf"); ini->deletor(ini); } staticvoidini_parser_test_file() { structini_parser*ini=new_ini_parser(); intsize=ini->parse_file(ini,"test.conf"); assert(size>0); assert(ini->value(ini,"second")==0); assert(ini->value(ini,"abc")==0); assert(ini->value(ini,"name")!=NULL); assert(ini->value(ini,"first")!=NULL); printf("inistring:%s\n",g_szIniString); printf("key-valuepairscount=%d\n",size); printf("key\'name\'',value=%s\n",ini->value(ini,"name")); printf("key\'first\'',value=%s\n",ini->value(ini,"first")); printf("key\'baidu\'',value=%s\n",ini->value(ini,"baidu")); ini->deletor(ini); } voidini_parser_test() { ini_parser_test_string(); ini_parser_test_file(); }
struct ini_parser 已經運用在實際的項目中,目前為止沒發現什麼問題。