在一个跨平台( Android 、Windows、Linux )项目中配置文件用 INI 格式,自己写了个解析库,纯C语言的,简单好用。
可以解析 INI 格式的字符串、解析文件、保存到文件。
下面是头文件:
#ifndef INI_PARSER_H #define INI_PARSER_H #ifdef __cplusplus extern "C" { #endif struct tag_value_list; struct ini_parser { struct tag_value_list * keyvalues; int (*parse_file)(struct ini_parser *, const char * file); int (*parse_string)(struct ini_parser *, const char *text); char * (*value)(struct ini_parser *, const char * key); void (*set_value)(struct ini_parser *, const char * key, const char * value); void (*remove)(struct ini_parser *, const char *key); int (*save_to_file)(struct ini_parser *, const char * file); }; struct ini_parser * new_ini_parser(); void delete_ini_parser(struct ini_parser *); #ifdef __cplusplus } #endif #endif // INI_PARSER_H
下面是源文件:
#include "ini_parser.h" #include <stdio.h> #include <string.h> #include "tag_value.h" static struct tag_value_pair * parse_line(char *line, int len) { struct tag_value_pair * pair = 0; int count = 0; char * p = line; char * end = 0; char * start = line; if(!p) return 0; while(*p == ' ') p++; /*blank line*/ if(p - line == len || *p == '\r' || *p == '\n' || *p == '\0') return 0; /*do not support group*/ if(*p == '[') return 0; /*comments*/ if(*p == '#') return 0; /* extract key */ start = p; end = line + len; while(*p != '=' && p!= end) p++; if(p == end) { /* none '=' , invalid line */ return 0; } end = p - 1; while(*end == ' ') end--; /* skip blank at the end */ count = end - start + 1; pair = new_tag_value_pair(); pair->szTag = malloc(count + 1); strncpy(pair->szTag, start, count); pair->szTag[count] = 0; /* extract value */ p++; end = line + len; /* next pos of the last char */ while( *p == ' ' && p != end) p++; if(p == end) { delete_tag_value_pair(pair); return 0; } start = p; end--; /* to the last char */ 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; } /* release empty key-value pair */ if(!pair->szValue) { delete_tag_value_pair(pair); return 0; } return pair; } static int _parse_file(struct ini_parser * ini, const char *file){ FILE * fp = fopen(file, "r"); if(fp) { struct tag_value_pair * pair = 0; char buf[1024] = {0}; while(fgets(buf, 1024, fp)) { pair = parse_line(buf, strlen(buf)); if(pair) { ini->keyvalues->add(ini->keyvalues, pair); } } fclose(fp); return ini->keyvalues->size; } return -1; } static int _parse_text(struct ini_parser * ini, const char * text){ char *p = text; char * start = 0; struct tag_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++; } return ini->keyvalues->size; } static char * _value(struct ini_parser * ini, const char * key){ struct tag_value_pair * pair = ini->keyvalues->find_by_tag(ini->keyvalues, key); if(pair) return pair->szValue; return 0; } static void _set_value(struct ini_parser * ini, const char * key, const char *value){ struct tag_value_pair * pair = ini->keyvalues->find_by_tag(ini->keyvalues, key); if(pair) { if(pair->szValue) free(pair->szValue); pair->szValue = strdup(value); } else { ini->keyvalues->add(ini->keyvalues, make_tag_value_pair(key, value)); } } static void _remove(struct ini_parser * ini, const char * key){ struct tag_value_pair * pair = ini->keyvalues->find_by_tag(ini->keyvalues, key); if(pair)ini->keyvalues->remove(ini->keyvalues, pair); } static void write_keyvalue(struct tag_value_pair * pair, FILE *fp) { fputs(pair->szTag, fp); fputc('=', fp); fputs(pair->szValue, fp); fputc('\n', fp); } static int _save_to_file(struct ini_parser * ini, const char * file){ if(ini->keyvalues->size > 0) { FILE * fp = fopen(file, "w"); if(fp) { struct tag_value_pair * pair = ini->keyvalues->head; while(pair != ini->keyvalues->tail) { write_keyvalue(pair, fp); pair = pair->next; } if(pair)write_keyvalue(pair, fp); fclose(fp); return 0; } } return -1; } struct ini_parser * new_ini_parser(){ struct ini_parser * ini = (struct ini_parser*)malloc(sizeof(struct ini_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; return ini; } void delete_ini_parser(struct ini_parser *ini){ if(ini) { delete_tag_value_list(ini->keyvalues); free(ini); } }
#include "util/ini_parser.h" #include "ini_test.h" #include <stdio.h> #include <assert.h> static char * g_szIniString = "#abc\nfirst=2\nsecond\nname=charli zhang \n"; static void ini_parser_test_string() { struct ini_parser * ini = new_ini_parser(); int size = 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("ini string: %s\n", g_szIniString); printf("key-value pairs count = %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"); delete_ini_parser(ini); } static void ini_parser_test_file() { struct ini_parser * ini = new_ini_parser(); int size = 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("ini string: %s\n", g_szIniString); printf("key-value pairs count = %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")); delete_ini_parser(ini); } void ini_parser_test() { ini_parser_test_string(); ini_parser_test_file(); }