C语言面向对象编程(六):配置文件解析

 在实际项目中,经常会把软件的某些选项写入配置文件。 Windows 平台上的 INI 文件格式简单易用,本篇文章利用《C语言面向对象编程(五):单链表实现》中实现的单链表,设计了一个“类” ini_parser 来读写 INI 格式的配置文件。

    struct ini_parser 可以解析 INI 格式的字符串、文件,也可以将内存中的符合 INI 格式的数据写入文件,能够支持 Windows 、 Linux 、 Android 等多平台。目前暂不支持选项分组功能。

    功能相对简单,直接看源码吧。

    下面是头文件:

 
  1. struct single_list;

  2.  
  3. struct ini_parser {

  4. struct single_list * keyvalues;

  5. int (*parse_file)(struct ini_parser *, const char * file);

  6. int (*parse_string)(struct ini_parser *, const char *text);

  7. char * (*value)(struct ini_parser *, const char * key);

    扫描二维码关注公众号,回复: 3488579 查看本文章
  8. void (*set_value)(struct ini_parser *, const char * key, const char * value);

  9. void (*remove)(struct ini_parser *, const char *key);

  10. int (*save_to_file)(struct ini_parser *, const char * file);

  11. void (*deletor)(struct ini_parser *ini);

  12. };

  13.  
  14. struct ini_parser * new_ini_parser();

    struct init_parser 的声明符合我们在本系列文章中提到的面向对象框架,需要说明的是,一旦 deletor 方法被调用, ini_parser 的实例将不再允许访问。

    下面是源文件:

 
  1. #include "ini_parser.h"

  2. #include <stdio.h>

  3. #include <string.h>

  4.  
  5. struct tag_value_pair{

  6. struct slist_node node;

  7. char * szTag;

  8. char * szValue;

  9. };

  10. typedef struct tag_value_pair tag_value;

  11.  
  12. static void _tag_value_free(struct slist_node *node)

  13. {

  14. if(node) delete_tag_value_pair(node);

  15. }

  16.  
  17. static int _tag_value_hittest(struct slist_node * node, void *key)

  18. {

  19. return strcmp((char*)tag, ((struct tag_value_pair*)node)->szTag);

  20. }

  21.  
  22. static struct single_list * new_tag_value_list()

  23. {

  24. return new_single_list(_tag_value_free, _tag_value_hittest);

  25. }

  26.  
  27. static struct tag_value_pair *new_tag_value_pair()

  28. {

  29. struct tag_value_pair * pair = (struct tag_value_pair *)malloc(sizeof(struct tag_value_pair));

  30. pair->node.next = 0;

  31. pair->szTag = 0;

  32. pair->szValue = 0;

  33. return pair;

  34. }

  35.  
  36. static struct tag_value_pair * make_tag_value_pair(char * tag, char * value)

  37. {

  38. struct tag_value_pair *pair = 0;

  39. if(!tag || !value)return 0;

  40.  
  41. pair = (struct tag_value_pair*)malloc(sizeof(struct tag_value_pair));

  42. pair->szTag = strdup(tag);

  43. pair->szValue = strdup(value);

  44. pair->node.next = 0;

  45. return pair;

  46. }

  47.  
  48.  
  49. static struct tag_value_pair * parse_line(char *line, int len)

  50. {

  51. struct tag_value_pair * pair = 0;

  52. int count = 0;

  53. char * p = line;

  54. char * end = 0;m

  55. char * start = line;

  56. if(!p) return 0;

  57. while(*p == ' ') ++p;

  58.  
  59.  
  60. /*blank line*/

  61. if(p - line == len ||

  62. *p == '\r' ||

  63. *p == '\n' ||

  64. *p == '\0') return 0;

  65.  
  66. /*do not support group*/

  67. if(*p == '[') return 0;

  68. /*comments*/

  69. if(*p == '#') return 0;

  70.  
  71. /* extract key */

  72. start = p;

  73. end = line + len;

  74. while(*p != '=' && p!= end) ++p;

  75. if(p == end)

  76. {

  77. /* none '=' , invalid line */

  78. return 0;

  79. }

  80. end = p - 1;

  81. while(*end == ' ') --end; /* skip blank at the end */

  82. count = end - start + 1;

  83.  
  84. pair = new_tag_value_pair();

  85. pair->szTag = malloc(count + 1);

  86. strncpy(pair->szTag, start, count);

  87. pair->szTag[count] = 0;

  88.  
  89. /* extract value */

  90. ++p;

  91. end = line + len; /* next pos of the last char */

  92. while( *p == ' ' && p != end) ++p;

  93. if(p == end)

  94. {

  95. delete_tag_value_pair(pair);

  96. return 0;

  97. }

  98. start = p;

  99. --end; /* to the last char */

  100. if(*end == '\n') { *end = 0; --end; }

  101. if(*end == '\r') { *end = 0; --end; }

  102. count = end - start + 1;

  103. if(count > 0)

  104. {

  105. pair->szValue = malloc(count + 1);

  106. strncpy(pair->szValue, start, count);

  107. pair->szValue[count] = 0;

  108. }

  109.  
  110. /* release empty key-value pair */

  111. if(!pair->szValue)

  112. {

  113. delete_tag_value_pair(pair);

  114. return 0;

  115. }

  116.  
  117. return pair;

  118. }

  119.  
  120. static int _parse_file(struct ini_parser * ini, const char *file){

  121. FILE * fp = fopen(file, "r");

  122. if(fp)

  123. {

  124. struct tag_value_pair * pair = 0;

  125. char buf[1024] = {0};

  126. while(fgets(buf, 1024, fp))

  127. {

  128. pair = parse_line(buf, strlen(buf));

  129. if(pair)

  130. {

  131. ini->keyvalues->add(ini->keyvalues, pair);

  132. }

  133. }

  134. fclose(fp);

  135. return ini->keyvalues->size;

  136. }

  137. return -1;

  138. }

  139.  
  140. static int _parse_text(struct ini_parser * ini, const char * text){

  141. char *p = text;

  142. char * start = 0;

  143. struct tag_value_pair * pair = 0;

  144. if(!text) return -1;

  145.  
  146. while(1)

  147. {

  148. start = p;

  149. while(*p != '\n' && *p != '\0' )++p;

  150. if(*p == '\0') break;

  151.  
  152. pair = parse_line(start, p - start);

  153. if(pair) ini->keyvalues->add(ini->keyvalues, pair);

  154.  
  155. ++p;

  156. }

  157.  
  158. return ini->keyvalues->size;

  159. }

  160.  
  161. static char * _value(struct ini_parser * ini, const char * key){

  162. struct tag_value_pair * pair = NODE_T(ini->keyvalues->find_by_key(ini->keyvalues, key), struct tag_value_pair);

  163. if(pair) return pair->szValue;

  164. return 0;

  165. }

  166.  
  167. static void _set_value(struct ini_parser * ini, const char * key, const char *value){

  168. struct tag_value_pair * pair = NODE_T(ini->keyvalues->find_by_key(ini->keyvalues, key), struct tag_value_pair);

  169. if(pair)

  170. {

  171. if(pair->szValue) free(pair->szValue);

  172. pair->szValue = strdup(value);

  173. }

  174. else

  175. {

  176. ini->keyvalues->add(ini->keyvalues, make_tag_value_pair(key, value));

  177. }

  178. }

  179.  
  180. static void _remove(struct ini_parser * ini, const char * key){

  181. struct tag_value_pair * pair = NODE_T(ini->keyvalues->find_by_key(ini->keyvalues, key), struct tag_value_pair);

  182. if(pair)ini->keyvalues->remove(ini->keyvalues, pair);

  183. }

  184.  
  185. static void write_keyvalue(struct tag_value_pair * pair, FILE *fp)

  186. {

  187. fputs(pair->szTag, fp);

  188. fputc('=', fp);

  189. fputs(pair->szValue, fp);

  190. fputc('\n', fp);

  191. }

  192.  
  193. static int _save_to_file(struct ini_parser * ini, const char * file){

  194. if(ini->keyvalues->size > 0)

  195. {

  196. FILE * fp = fopen(file, "w");

  197. if(fp)

  198. {

  199. struct tag_value_pair * pair = NODE_T(ini->keyvalues->head,struct tag_value_pair);

  200. while(pair != 0)

  201. {

  202. write_keyvalue(pair, fp);

  203. pair = NODE_T(pair->node.next, struct tag_value_pair);

  204. }

  205.  
  206. fclose(fp);

  207. return 0;

  208. }

  209. }

  210. return -1;

  211. }

  212.  
  213. static void _delete_ini_parser(struct ini_parser *ini){

  214. if(ini)

  215. {

  216. ini->keyvalues->deletor(ini->keyvalues);

  217. free(ini);

  218. }

  219. }

  220.  
  221. struct ini_parser * new_ini_parser(){

  222. struct ini_parser * ini = (struct ini_parser*)malloc(sizeof(struct ini_parser));

  223. ini->keyvalues = new_tag_value_list();

  224. ini->parse_file = _parse_file;

  225. ini->parse_string = _parse_text;

  226. ini->value = _value;

  227. ini->set_value = _set_value;

  228. ini->remove = _remove;

  229. ini->save_to_file = _save_to_file;

  230. ini->deletor = _delete_ini_parser;

  231. return ini;

  232. }

    下面是简单的测试代码:

 
  1. static char * g_szIniString = "#abc\nfirst=2\nsecond\nname=charli zhang \n";

  2.  
  3. static void ini_parser_test_string()

  4. {

  5. struct ini_parser * ini = new_ini_parser();

  6. int size = ini->parse_string(ini, g_szIniString);

  7.  
  8. assert( size > 0);

  9. assert( ini->value(ini, "second") == 0 );

  10. assert( ini->value(ini, "abc") == 0);

  11. assert( ini->value(ini, "name") != NULL );

  12. assert( ini->value(ini, "first") != NULL);

  13.  
  14. printf("ini string: %s\n", g_szIniString);

  15. printf("key-value pairs count = %d\n", size);

  16. printf("key \'name\'', value = %s\n", ini->value(ini, "name"));

  17. printf("key \'first\'', value = %s\n", ini->value(ini, "first"));

  18.  
  19. ini->set_value(ini, "baidu", "hahaha");

  20. ini->save_to_file(ini, "write.conf");

  21.  
  22. ini->remove(ini, "first");

  23. ini->save_to_file(ini, "write2.conf");

  24.  
  25. ini->deletor(ini);

  26. }

  27.  
  28. static void ini_parser_test_file()

  29. {

  30. struct ini_parser * ini = new_ini_parser();

  31. int size = ini->parse_file(ini, "test.conf");

  32.  
  33. assert( size > 0);

  34. assert( ini->value(ini, "second") == 0 );

  35. assert( ini->value(ini, "abc") == 0);

  36. assert( ini->value(ini, "name") != NULL );

  37. assert( ini->value(ini, "first") != NULL);

  38.  
  39. printf("ini string: %s\n", g_szIniString);

  40. printf("key-value pairs count = %d\n", size);

  41. printf("key \'name\'', value = %s\n", ini->value(ini, "name"));

  42. printf("key \'first\'', value = %s\n", ini->value(ini, "first"));

  43. printf("key \'baidu\'', value = %s\n", ini->value(ini, "baidu"));

  44.  
  45. ini->deletor(ini);

  46. }

  47.  
  48. void ini_parser_test()

  49. {

  50. ini_parser_test_string();

  51. ini_parser_test_file();

  52. }

    struct ini_parser 已经运用在实际的项目中,目前为止没发现什么问题。

猜你喜欢

转载自blog.csdn.net/csshuke/article/details/82666210