diff --git a/src/conf.c b/src/conf.c index b0ff9d5..5aa6921 100644 --- a/src/conf.c +++ b/src/conf.c @@ -1,17 +1,71 @@ #include "hash/hash.h" #include "stack/stack.h" +#include + +//解析过程的各状态 +enum conf_stat +{ + conf_stat_start, + conf_stat_normal, + conf_stat_note, + conf_stat_key, + conf_stat_more_key, + conf_stat_quote, + conf_stat_done +}; + +#define POP (*data) +#define ADVANCE (++data) +#define BACK (--data) +#define LEN (data-str) + +#define CONF_GET_VALUE(value,stack) \ +{\ + if(conf_stack_get_data(stack) == NULL)\ + {\ + retcode=CONF_KEY_ERR;\ + printf("行:%d ",line);\ + goto end;\ + }\ + value=realloc(value,sizeof(char*)*(value_len+2));\ + if(value == NULL)\ + {\ + retcode=CONF_NO_MEM;\ + goto end;\ + }\ + value[value_len]=strdup(conf_stack_get_data(stack));\ + if(value[value_len] == NULL)\ + {\ + retcode=CONF_NO_MEM;\ + free(value);\ + goto end;\ + }\ + value[value_len+1]=NULL;\ + ++value_len;\ +} + +int line=1; //行 //解析对参数 //data为配置文件内容 //正确时返回0并置res为参数列表conf->len为参数个数 //错误时返回错误代码 -int parse_value(CONF *conf,char *data,CONF_VALUE **res); +//int parse_value(CONF *conf,char *data,CONF_VALUE **res); +int parse_value(CONF *conf,char *data); //得到一行的偏移量 int next_line(char *data); //释放内存 void free_data(CONF_ARG *data); //得到键 void get_key(char **key,int *index,CONF_ARG *arg); +//读取键值 +int _conf_read_key(char *data,int len,STACK *stack); +//获取值状态 +enum conf_stat _conf_value_status(char c); +//读取值 +int _conf_read_value(char *data,int len,STACK *stack); +//读取带有引号的值 +int _conf_read_value_with_quote(char *data,int len,STACK *stack,char quote); //打开配置文件并初始化值 //path为配置文件路径 @@ -36,6 +90,7 @@ CONF *conf_open(const char *path) //初始化键值对 conf->len=0; + conf->size=HASH_DEFAULT; conf->hash_data=NULL; return conf; @@ -46,11 +101,9 @@ CONF *conf_open(const char *path) //解析成功返回错误代码 int conf_parse(CONF *conf) { - CONF_VALUE *value=NULL; //参数对列表 char *data; //配置文件内容 long file_len; //配置文件长度 int retcode; - int i; //加载配置文件内容到内存 if(fseek(conf->fp,0L,SEEK_END) != 0) @@ -66,36 +119,15 @@ int conf_parse(CONF *conf) //关闭文件 fclose(conf->fp); - //解析 - retcode=parse_value(conf,data,&value); - - //开辟内存空间 - conf->hash_data=malloc(sizeof(CONF_ARG)*conf->len); - //开辟内存空间出错 - if(conf->hash_data == NULL) - { - //如果已经解析了则进行释放 - if(value) - free(value); - - //返回错误 - retcode=CONF_NO_MEM; - } - - //初始化数组 - for(i=0;i != conf->len;++i) - { - conf->hash_data[i].len=0; - conf->hash_data[i].next=NULL; - conf->hash_data[i].value=NULL; - } - //插入数据 - for(i=0;i != conf->len;++i) - conf_value_insert(conf->hash_data,&value[i],conf->len); - + //创建表 + conf->hash_data=malloc(sizeof(CONF_ARG)*conf->size); + if(conf->hash_data == NULL) return CONF_NO_MEM; + //初始化键值对 + conf_hash_zero(conf->hash_data,conf->size); + //解析 + retcode=parse_value(conf,data); free(data); - //free(value); - + return retcode; } @@ -173,7 +205,6 @@ int conf_insert(CONF_CREATER *creater,char *key,char *value,char *note) int conf_save(CONF_CREATER *creater) { CONF_CREATER *head=creater; -// int i; if(creater->len == 0) return CONF_NO_DATA; @@ -186,14 +217,6 @@ int conf_save(CONF_CREATER *creater) if(creater->key != NULL && creater->value != NULL) fprintf(head->fp,"%s = %s\n",creater->key,creater->value); creater=creater->next; - //如果该键有多个参数则用,分开 - /*if(creater->value->value[1] != NULL) - { - for(i=1;creater->value->value[i] != NULL;++i) - fprintf(creater->fp,",%s",creater->value->value[i]); - } - - fwrite("\n",1,1,creater->fp);*/ } fclose(head->fp); @@ -207,7 +230,7 @@ void conf_free(CONF *conf) int i; int j; - for(i=0;i != conf->len;++i) + for(i=0;i != conf->size;++i) { if(conf->hash_data[i].len != 0) free_data(&conf->hash_data[i]); @@ -255,157 +278,230 @@ void conf_error(int errcode) case CONF_VALUE_ERR: printf("错误:错误的值!\n"); break; - case STACK_MAX: - printf("参数字符过多!\n"); - break; default: printf("未知错误!\n"); } } //解析参数 -int parse_value(CONF *conf,char *data,CONF_VALUE **res) +int parse_value(CONF *conf,char *data) { - int i=0; //字符偏移量 - int flags=0; //'与"的标记 - int key=0; //键标记 - int arg=0; //,标记 - int len=0; //键值对个数 - int count=0; //参数个数 - CONF_VALUE *value=NULL; //存放键值参数 - STACK stack; //存放参数的栈 + //保存解析字符串的首地址 + char *str=data; + //状态 + int status; + int save_status; + int end_status; + //引号 + char quote; + //存储字符串的栈 + STACK stack; + CONF_VALUE *value=NULL; + int retcode=CONF_OK; + //多参数个数 + int value_len=0; + //初始化栈和状态 conf_stack_init(&stack); + status=conf_stat_start; + save_status=conf_stat_normal; + end_status=conf_stat_done; - while(data[i]) +redo: + while(POP) { - switch(data[i]) + switch(POP) { - case '=': //读取键,如果第一次读到=则表示键已读完 - if(!key) + //注释 + case '#': + if(save_status == conf_stat_normal) + status=conf_stat_note; + else if(save_status == conf_stat_key) { - value=realloc(value,sizeof(CONF_VALUE)*(len+1)); - if(value == NULL) - return CONF_NO_MEM; - value[len].key=malloc(sizeof(char)*conf_stack_length(&stack)+1); - if(value[len].key == NULL) - return CONF_NO_MEM; - snprintf(value[len].key,sizeof(char)*conf_stack_length(&stack)+1,"%s",stack.data); - key=1; - value[len].value=NULL; - conf_stack_cleanup(&stack); + retcode=CONF_VALUE_ERR; + printf("行:%d ",line); + conf_free(conf); + goto end; } + break; + //读取值 + case '=': + if(save_status == conf_stat_key) + status=conf_stat_key; else { - if(conf_stack_push(&stack,data[i]) != 0) //否则则是值压入栈 - return STACK_MAX; - } - break; -/* 如果第一次读到"则设置"标记 - * 如果不是第一次读入"则如果flags为1则表示读取完成 - * 如果为2则表示'标记则将"压入栈中 - */ - case '"': - if(!flags) - flags=1; - else if(flags == 1) - flags=0; - else if(flags == 2) - { - if(conf_stack_push(&stack,data[i]) != 0) - return STACK_MAX; - } - break; - case '\'': //上同 - if(!flags) - flags=2; - else if(flags == 2) - flags=0; - else if(flags == 1) - { - if(conf_stack_push(&stack,data[i]) != 0) - return STACK_MAX; - } - break; -/* 多参数标记 - * 如果已设置'/"标记则直接压入 - * 如果没有设置'/"标记且arg未设置则设置arg - * 否则arg设置为0 - */ - case ',': - if(flags) - conf_stack_push(&stack,data[i]); - if(!flags && !arg) - arg=1; - if(arg) //存入多参数 - { - value[len].value=realloc(value[len].value,sizeof(char *)*(count+1)); - if(value[len].value == NULL) - return CONF_NO_MEM; - value[len].value[count]=malloc(sizeof(char)*conf_stack_length(&stack)+1); - if(value[len].value[count] == NULL) - return CONF_NO_MEM; - snprintf(value[len].value[count],sizeof(char)*conf_stack_length(&stack)+1,"%s",stack.data); - ++count; - conf_stack_cleanup(&stack); - arg=0; - } - break; - case '#': //如果没有设置flags则是注释直接跳到下一行 - if(!flags) - i+=next_line(data+i); - else - { - if(conf_stack_push(&stack,data[i]) != 0) - return STACK_MAX; + retcode=CONF_KEY_ERR; + printf("行:%d ",line); + if(value) + { + if(value->key) + free(value->key); + free(value); + } + conf_free(conf); + goto end; } break; + //过滤空白符 case ' ': case '\t': - if(flags) + if(end_status == conf_stat_done) + while(isspace(POP)) + ADVANCE; + goto redo; + case '\n': + if(save_status == conf_stat_normal) + ADVANCE; + else { - if(conf_stack_push(&stack,data[i]) != 0) - return STACK_MAX; + retcode=CONF_KEY_ERR; + printf("行:%d ",line); + conf_free(conf); + goto end; } + ++line; + goto redo; + case '\0': + if(status == conf_stat_normal) + { + retcode=CONF_KEY_ERR; + printf("行:%d ",line); + conf_free(conf); + goto end; + } + status=conf_stat_done; break; - case '\n': //一行数据读完 - if(conf_stack_empty(&stack)) - break; - value[len].value=realloc(value[len].value,sizeof(char *)*(count+2)); - if(value[len].value == NULL) - return CONF_NO_MEM; - value[len].value[count]=malloc(sizeof(char)*conf_stack_length(&stack)+1); - if(value[len].value[count] == NULL) - return CONF_NO_MEM; - snprintf(value[len].value[count],sizeof(char)*conf_stack_length(&stack)+1,"%s",stack.data); - value[len].value[count+1]=NULL; - count=0; - ++len; - key=0; - conf_stack_cleanup(&stack); - break; - default: //插入字符 - if(conf_stack_push(&stack,data[i]) != 0) - return STACK_MAX; + default: + if(save_status == conf_stat_key) + { + retcode=CONF_VALUE_ERR; + printf("行:%d ",line); + conf_free(conf); + goto end; + } + save_status=conf_stat_normal; + status=conf_stat_start; } - ++i; + switch(status) + { + //过滤注释 + case conf_stat_note: + data+=next_line(data); + status=conf_stat_start; + save_status=conf_stat_normal; + ++line; + goto redo; + //读取键 + case conf_stat_start: + data+=_conf_read_key(data,LEN,&stack); + value=malloc(sizeof(CONF_VALUE)); + if(value == NULL) + { + retcode=CONF_NO_MEM; + conf_free(conf); + goto end; + } + if(conf_stack_get_data(&stack) == NULL) + { + retcode=CONF_KEY_ERR; + printf("行:%d ",line); + free(value); + conf_free(conf); + goto end; + } + value->key=strdup(conf_stack_get_data(&stack)); + if(value->key == NULL) + { + retcode=CONF_NO_MEM; + free(value); + conf_free(conf); + goto end; + } + conf_stack_cleanup(&stack); + save_status=conf_stat_key; + end_status=conf_stat_done; + value->value=NULL; + goto redo; + //设置值状态 + case conf_stat_key: + ADVANCE; + while((POP == ' ') || (POP == '\t')) + ADVANCE; + save_status=conf_stat_key; + end_status=_conf_value_status(POP); + break; + case conf_stat_done: + retcode=CONF_OK; + goto end; + } + +value_redo: + switch(end_status) + { + //读取完成,保存数据到表中 + case conf_stat_done: + if((save_status != conf_stat_key) || + (status == conf_stat_key)) + { + retcode=CONF_VALUE_ERR; + printf("行:%d ",line); + conf_free(conf); + goto end; + } + //重置状态 + status=conf_stat_start; + save_status=conf_stat_normal; + value_len=0; + if(conf->len/conf->size >= HASH_SP) + conf_hash_update(conf); + if(conf_value_insert(conf->hash_data,value,conf->size)) + ++conf->len; + BACK; + value=NULL; + conf_stack_cleanup(&stack); + break; + //读取值 + case conf_stat_normal: + data+=_conf_read_value(data,LEN,&stack); + CONF_GET_VALUE(value->value,&stack); + while(isspace(POP) && (POP != '\n')) + ADVANCE; + end_status=_conf_value_status(POP); + status=conf_stat_start; + goto value_redo; + //读取带有引号的值 + case conf_stat_quote: + quote=POP; + ADVANCE; + data+=_conf_read_value_with_quote(data,LEN,&stack,quote); + CONF_GET_VALUE(value->value,&stack); + ADVANCE; + end_status=_conf_value_status(POP); + goto value_redo; + //多参数值读取 + case conf_stat_more_key: + conf_stack_cleanup(&stack); + ADVANCE; + end_status=_conf_value_status(POP); + goto value_redo; + } + + ADVANCE; } - - *res=value; - conf->len=len; - - return 0; +end: + conf_stack_destroy(&stack); + return retcode; } int next_line(char *data) { int i=0; - while(data[i] != '\n') + while((data[i] != '\n') && (data[i] != '\0')) ++i; - return i-1; + return i+1; } void free_data(CONF_ARG *data) @@ -438,7 +534,7 @@ char **conf_key_list(CONF *conf) key[conf->len]=NULL; //读取出所有键 - for(i=0;i < conf->len;++i) + for(i=0;i < conf->size;++i) if(conf->hash_data[i].len > 0) get_key(key,&index,&conf->hash_data[i]); @@ -464,12 +560,12 @@ CONF_VALUE *conf_value_get(CONF *conf,const char *key) /* 首先使用第一个哈希函数计算出哈希值,如果找到匹配的key则返回 * 否则使用第二个哈希函数计算值并比对key * 如果都未能匹配,则返回NULL */ - hash=conf_hash_func1(key)%conf->len; + hash=conf_hash_func1(key)%conf->size; if(conf_hash_search(&conf->hash_data[hash],key,&value)) return value; else { - hash=conf_hash_func2(key)%conf->len; + hash=conf_hash_func2(key)%conf->size; if(conf_hash_search(&conf->hash_data[hash],key,&value)) return value; } @@ -488,7 +584,7 @@ CONF_VALUE **conf_value_get_all(CONF *conf) return NULL; //第一次扫描数组中所有存在数据的地方并计算长度 - for(i=0;i != conf->len;++i) + for(i=0;i != conf->size;++i) if(conf->hash_data[i].len > 0) ++len; @@ -498,7 +594,7 @@ CONF_VALUE **conf_value_get_all(CONF *conf) return NULL; value[len]=NULL; //第二次扫描,返回数组中所有有数据的值 - for(i=0;i != conf->len;++i) + for(i=0;i != conf->size;++i) { if(conf->hash_data[i].len > 0) { @@ -509,3 +605,112 @@ CONF_VALUE **conf_value_get_all(CONF *conf) return value; } + +int _conf_read_key(char *data,int len,STACK *stack) +{ + int i=0; + char c; + + while(isspace(POP) && (POP != '\n')) + { + ADVANCE; + ++i; + } + if(POP == '\n') + { + printf("行:%d 列:%d 解析出错\n",line,i-len); + return 0; + } + + do + { + c=POP; + if(isspace(c) || c == '=' || c == '#') + break; + conf_stack_push(stack,c); + ++i; + ADVANCE; + }while(c); + + return i; +} + +enum conf_stat _conf_value_status(char c) +{ + switch(c) + { + case ',': + return conf_stat_more_key; + case '\'': + case '"': + return conf_stat_quote; + case '#': + case '\n': + return conf_stat_done; + default: + return conf_stat_normal; + } +} + +int _conf_read_value(char *data,int len,STACK *stack) +{ + char c; + int i=0; + + while(isspace(POP) && (POP != '\n')) + { + ADVANCE; + ++i; + } + if(POP == '\n') + { + printf("行:%d 列:%d 解析出错!\n",line,i-len); + return 0; + } + + do + { + c=POP; + if(isspace(c) || c == ',' || c == '#') + break; + + conf_stack_push(stack,c); + ++i; + ADVANCE; + }while(c); + + return i; +} + +int _conf_read_value_with_quote(char *data,int len,STACK *stack,char quote) +{ + char c; + int i=0; + + while(isspace(POP) && (POP != '\n')) + { + ADVANCE; + ++i; + } + if(POP == '\n') + { + printf("行:%d 列:%d 解析出错!\n",line,i-len); + return 0; + } + + do + { + c=POP; + if(c == quote) + break; + + conf_stack_push(stack,c); + ++i; + ADVANCE; + }while(c); + + if(c == '\0') + return 0; + + return i; +}