1 /******************************************************************************
  2  *
  3  *                          parseConf(配置文件解析器)
  4  *
  5  *    1. 很多时候,我们安装一些软件,都可以通过改一些软件的配置文件来修改程序的
  6  *        运行性能,如Tomcat修改端口号,访问数据库时一些固定的参数等等;
  7  *    2. 本Demo就是干着这么一件事,从properties.conf文件中取出键值对(keyvalue),
  8  *        实现更大程度提高代码的可利用性,通用性;
  9  *    3. 以下是我们要解析的properties.conf文件中的内容:
 10  *        #title = charMaps
 11  *              t    itle = c   harMaps
 12  *            #jfdalj    lasdfjl jflds
 13  *        jfdsljf
 14  *        =fjldsfsjd
 15  *        up     = looking
 16  *                rows = 24    #jals    djfaldjfals
 17  *                r ows = 25    #jals    djfaldjfals
 18  *        c    ols =       8    0
 19  *
 20  *            =    fsdfa
 21  *
 22  *        c    ols =       88   0
 23  *        jsflsjfd
 24  *        jfsldjaf
 25  *        tadjfsldjf=
 26  *
 27  *        cols=88   0
 28  *        cols=888  0
 29  *        interval    = 1   0000
 30  *        version = 11.0
 31  *           lkjk  ng     =    i  an   f  n  ig
 32  *           test = 100000000
 33  *    4. 这是我们使用本parseConf程序解析出来的结果:
 34  *        001: t    itle=c   harMaps
 35  *        002: up=looking
 36  *        003: rows=24
 37  *        004: r ows=25
 38  *        005: c    ols=88   0
 39  *        006: cols=888  0
 40  *        007: interval=1   0000
 41  *        008: version=11.0
 42  *        009: lkjk  ng=i  an   f  n  ig
 43  *        010: test=100000000
 44  *    5. 配置文件的书写规范:
 45  *        1. 键值对(keyvalue)以key=value的形式存在,等号两边可以出现空格;
 46  *        2. 对于不能构成键值对(keyvalue)的key或value都会被忽略;
 47  *        3. '#'为行注释符,目前只支持单行注释,不提供多行注释;  :)
 48  *        4. 如果解析中发现键值对中key相同,那么取最后那次的键值对为最终键值对;
 49  *    6. 使用valgrind对程序进行内存释放检查结果,不会造成内存泄露:
 50  *        [user@localhost parseConf]$ valgrind ./parseConf properties.conf
 51  *        ==6325== Memcheck, a memory error detector
 52  *        ==6325== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
 53  *        ==6325== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
 54  *        ==6325== Command: ./parseConf properties.conf
 55  *        ==6325==
 56  *          ...  //省略程序运行时的输出内容
 57  *        ==6325==
 58  *        ==6325== HEAP SUMMARY:
 59  *        ==6325==     in use at exit: 0 bytes in 0 blocks
 60  *        ==6325==   total heap usage: 39 allocs, 39 frees, 9,092 bytes allocated
 61  *        ==6325==
 62  *        ==6325== All heap blocks were freed -- no leaks are possible
 63  *        ==6325==
 64  *        ==6325== For counts of detected and suppressed errors, rerun with: -v
 65  *        ==6325== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 12 from 8)
 66  *
 67  *                                           2015-3-28 晴 深圳 曾剑锋
 68  *****************************************************************************/
 69
 70 #include <stdlib.h>
 71 #include <stdio.h>
 72 #include <string.h>
 73 #include <fcntl.h>
 74
 75 //默认一行数据的缓冲区大小
 76 #define BUFFER_SIZE 1024
 77
 78 //键值对结构体,本Demo采用单链表来实现
 79 typedef struct KVPAIR {
 80     char key[128];
 81     char value[512];
 82     struct KVPAIR * next;
 83 } kvpair;
 84 /**
 85  *  获取键值对的起始指针,参数是传入需要保存keyvalus首地址的指针,
 86  *  函数返回值为0时表示获取成功
 87  */
 88 int getkvpairs(char *conffile, kvpair** kvpairs);
 89 /**
 90  *  通过key值获取kvpairs中的value,如果链表中没有key对应的数据,或者给的参数错误
 91  *  将返回NULL
 92  */
 93 char* key2val(char* key, kvpair* kvpairs);
 94 /**
 95  *  通过value值获取kvpairs中的key,如果链表中没有value对应的数据,或者给的参数错误
 96  *  将返回NULL
 97  */
 98 char* val2key(char* value, kvpair* kvpairs);
 99 //打印输出kvpairs中所有的键值对
100 void printkvpairs(kvpair* kvpairs);
101 //用'\0'填充字符串
102 void cleanString(char* string);
103 /**
104  *  查看链表中有没有当前key对应的键值对,如果有,返回该key对应的键值对
105  *  如果没有,将返回NULL
106  */
107 kvpair* checkKey(char* key, kvpair* kvpairs);
108 //释放链表
109 int freekvpairs(kvpair* kvpairs);
110 //去除字符串左侧不可见字符
111 char *ltrim(char* str);
112 //去除字符串右侧不可见字符
113 char *rtrim(char* str);
114 //去除字符串左右不可见字符
115 char *trim(char* str);
116
117 /**
118  * on success, return 0, otherwise return -1
119  *
120  *  配置文件预处理过程是以一行一行来处理的,大致思路如下:
121  *  while(直到文件末尾){
122  *      1.删除一行中前面的' ','\t';
123  *      2.忽略掉那些以'\n','#','='开头的行;
124  *      3.如果一行中有'#'注释,将'#'所在的位置设置'\0',代表字符串末尾;
125  *          也就是'#'以及后面注释都不管,因为那是注释  :)
126  *      4.删除一行中末尾的换行符;
127  *      5.修剪获取到的key,value字符串;
128  *      6.剩下的也就是是键值对了,保存在链表中.
129  *  }
130  */
131 int getkvpairs(char* conffile, kvpair** kvpairs){
132     /**
133      * 如果传入的参数conffile不是NULL,并且配置文件能打开,则使用该文件中的配置参数
134      * 如果conffile指定的文件失效,则使用当前文件夹下的./properties.conf文件作为配置
135      * 文件,如果前面两者都失效,则会报错,并返回-1,文件后缀conf是properties的缩写
136      */
137     if(kvpairs == NULL){
138         perror("function( getkvpairs ) parameter ( kvpairs ) was NULL\n");
139         return -1;
140     }
141
142     if (conffile == NULL)
143         conffile = "./properties.conf";
144
145     FILE* conf = NULL;
146     conf = fopen(conffile, "r");
147     if(conf == NULL){
148         perror("function( getconfpairs ) can't found the properties file\n");
149         return -1;
150     }
151
152     int     i = 0;                      //用于循环计数
153     int     index = 0;                  //dealWithBuffer数组中作为保存缓存数据的指针
154     int     length = 0;                 //保存字符串的长度
155     int     equalIndex = 0;             //保存等号的下标
156     kvpair* keyValueHead = NULL;        //用于保存键值对的头节点
157     kvpair* currentkvpair = NULL;       //用于保存键值对的当前节点
158     kvpair* previewkvpair = NULL;       //用于保存键值对的前一个节点
159     char*   lineBuffer = calloc(BUFFER_SIZE, sizeof(char));
160     char*   dealWithBuffer = calloc(BUFFER_SIZE, sizeof(char));
161
162     while(fgets(lineBuffer, BUFFER_SIZE, conf)){
163         index = 0;
164         equalIndex = 0;
165         length = strlen(lineBuffer);
166         /**
167          * 删除行首的空格,制表符
168          */
169         for(i = 0; i < length; i++){
170             if((lineBuffer[i] != ' ') && (lineBuffer[i] != '\t')){
171                 strcpy(dealWithBuffer, &(lineBuffer[i]));
172                 break;
173             }
174         }
175         /**
176          *  清除一行中有#来注释的部分,保留键值对
177          *  且找出一行中=所在的位置,位置信息保存在equalIndex中
178          */
179         length = strlen(dealWithBuffer);
180         for(i = 0; i < length; i++){
181             if(dealWithBuffer[i] == '#' ){
182                 dealWithBuffer[i++] = '\0';
183                 break;
184             }else if(dealWithBuffer[i] == '=' ){
185                 equalIndex = i;
186             }
187         }
188         /**
189          * 删除以换行符,#,=等字符开始的行,同时清空dealWithBuffer缓冲区
190          */
191         if((equalIndex == 0) || (lineBuffer[ 0 ] == '\n') || (lineBuffer[ 0 ] == '#')) {
192             /**
193              * 一定要记得清理这个缓存
194              */
195             cleanString(dealWithBuffer);
196             continue;
197         }
198         /**
199          * 如果一行数据末尾是'\n',则换成'\0',相当于移除'\n'
200          */
201         length = strlen(dealWithBuffer);
202         if(dealWithBuffer[length-1] == '\n'){
203             dealWithBuffer[length-1] = '\0';
204         }
205         /**
206          * 通过将'='换成'\0',这样就key,value字符串
207          */
208         dealWithBuffer[equalIndex] = '\0';
209         /**
210          * 一定要的得加1, 因为字符串长度不包括尾零
211          */
212         char* key = calloc(strlen(dealWithBuffer)+1, sizeof(char));
213         char* value = calloc(strlen(&(dealWithBuffer[equalIndex+1]))+1, sizeof(char));
214         strcpy(key, dealWithBuffer);
215         strcpy(value, &(dealWithBuffer[equalIndex+1]));
216
217         /**
218          * 修剪key,value的值,也就是去掉字符串左右两边的' ','\t'
219          */
220         trim(key);
221         trim(value);
222         /**
223          * 接下来检查key是否存在,如果存在,直接修改其value,而不创建数据结构体
224          * 如果key不存在,则创建结构体,保存key,value,加入链表
225          * 当然,先要保证key,value有效
226          */
227         if((strlen(key) != 0) && (strlen(value) != 0)){
228             if((currentkvpair = checkKey(key, keyValueHead)) != NULL){
229                 bzero(currentkvpair->value, strlen(currentkvpair->value));
230                 strcpy(currentkvpair->value, value);
231             }else{
232                 currentkvpair = malloc(sizeof(kvpair));
233                 strcpy(currentkvpair->key, key);
234                 strcpy(currentkvpair->value, value);
235                 currentkvpair->next = NULL;
236                 if(keyValueHead == NULL){
237                     keyValueHead = currentkvpair;
238                     previewkvpair = currentkvpair;
239                 }else {
240                     previewkvpair->next =  currentkvpair;
241                     previewkvpair =  currentkvpair;
242                     currentkvpair = NULL;
243                 }
244             }
245         }
246
247         bzero(dealWithBuffer, BUFFER_SIZE);//不能使用cleanString清理,因为字符中间有'\0'
248         cleanString(lineBuffer);
249         free(key);
250         free(value);
251     }
252     free(lineBuffer);
253     free(dealWithBuffer);
254     *kvpairs = keyValueHead;
255     fclose(conf);
256     return 0;
257 }
258
259 void cleanString(char* string){
260     int i;
261     int length = strlen(string);
262     for(i = 0; i < length; i++){
263         string[i] = '\0';
264     }
265 }
266
267 char* key2val(char* key, kvpair* kvpairs){
268     if((key == NULL) || (strlen(key) == 0)){
269         perror("function( key2val) parameter ( key ) was NULL\n");
270         return NULL;
271     }
272
273     kvpair* currentkvpair = kvpairs;
274     while(currentkvpair){
275         /**
276           * 本来打算直接用strcmp,但是貌似strcmp会自动比较字符串所占数组的大小
277           * 所以改成使用strncmp
278           */
279         if(strncmp(currentkvpair->key, key, strlen(key)) == 0){
280             return currentkvpair->value;
281         }
282         currentkvpair = currentkvpair->next;
283     }
284     return NULL;
285 }
286
287 char* val2key(char* value, kvpair* kvpairs){
288     if((value == NULL) || (strlen(value) == 0)){
289         perror("function( val2key) parameter ( value ) was NULL\n");
290         return NULL;
291     }
292
293     kvpair* currentkvpair = kvpairs;
294     while(currentkvpair){
295         if(strncmp(currentkvpair->value, value, strlen(value)) == 0){
296             return currentkvpair->key;
297         }
298         currentkvpair = currentkvpair->next;
299     }
300     return NULL;
301 }
302
303 kvpair* checkKey(char* key, kvpair* kvpairs){
304     if((key == NULL) || (strlen(key) == 0)){
305         perror("function( checkKey ) parameter ( key ) was NULL\n");
306         return NULL;
307     }
308
309     kvpair* currentkvpair = kvpairs;
310     while(currentkvpair){
311         if(strncmp(currentkvpair->key, key, strlen(key)) == 0){
312             return currentkvpair;
313         }
314         currentkvpair = currentkvpair->next;
315     }
316     return NULL;
317 }
318
319 void printkvpairs(kvpair* kvpairs){
320     if(kvpairs == NULL){
321         perror("function( printkvpairs ) parameter( kvpairs ) was NULL\n");
322         return;
323     }
324
325     int index = 1;
326     kvpair* currentkvpair = kvpairs;
327     printf("\033[32m--------------------------------------\033[0m\n");
328     while(currentkvpair){
329         printf("\033[32m   %03d: %s=%s\033[0m\n", index, currentkvpair->key, currentkvpair->value);
330         currentkvpair = currentkvpair->next;
331         index++;
332     }
333     printf("\033[32m--------------------------------------\033[0m\n");
334 }
335
336 int freekvpairs(kvpair* kvpairs){
337     if(kvpairs == NULL){
338         return 0;
339     }
340
341     kvpair* previewkvpair = kvpairs;
342     kvpair* currentkvpair = kvpairs;
343     while(currentkvpair->next){
344         previewkvpair = currentkvpair;
345         currentkvpair = currentkvpair->next;
346         free(previewkvpair);
347     }
348     free(currentkvpair);
349     return 0;
350 }
351
352 char *ltrim(char* str) {
353     char str_tmp[BUFFER_SIZE] = {0};
354     char *current = str_tmp;
355     int count = 0;
356
357     strncpy(str_tmp, str, strlen(str));
358     bzero(str, strlen(str));
359
360     while(' ' == (*current) || ('\t' == *current ))
361         current++;
362
363     strncpy(str, current, strlen(current));
364     return str;
365 }
366
367 char *rtrim(char* str) {
368     int count = 0;
369     int i = strlen(str)-1;
370     for(; i >= 0; i--){
371         if((' ' == str[i]) || ('\t' == str[i]) || ('\0' == str[i]))
372             str[i] = '\0';
373         else
374             break;
375     }
376     return str;
377 }
378
379 char *trim(char* str) {
380     return rtrim(ltrim(str));
381 }
382
383 int main(int argc, char* argv[]){
384     //传入需要被解析的文件
385     if(argc < 2){
386         printf("    Usage:\n\r        ./parseConf <configure file> \n\n");
387         return ;
388     }
389
390     /**
391      * 获取键值对,键值对头节点保存在keyValues中
392      */
393     kvpair* keyValues;
394     getkvpairs(argv[1], &keyValues);
395     printf("\n\033[32m\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\033[36mDemo\033[32m/\033[0m\n");
396
397     /**
398      * 将配置文件中的内容打印出来
399      */
400     int fd = open(argv[1], O_RDONLY);
401     if(-1 == fd){
402         perror("open file error");
403     }
404
405     char buffer[1024] = {0};
406     read(fd, buffer, 1024);
407     printf("%s\n", buffer);
408
409     close(fd);
410
411     /**
412      * 将当前的所有的键值对打印出来
413      */
414     printkvpairs(keyValues);
415     /**
416      * 通过key获取value值
417      */
418     char* key = "rows";
419     printf("\033[32mgetValueBykey:key = %s; value = %s\033[0m\n", key, key2val(key, keyValues));
420     /**
421      * 通过value获取key值
422      */
423     char* value = "24";
424     printf("\033[32mgetKeyByValue:value = %s; key = %s\033[0m\n", value, val2key(value, keyValues));
425     printf("\033[32m--------------------------------------\033[0m\n");
426     /**
427      * 释放keyValues链表
428      */
429     if(freekvpairs(keyValues) == 0){
430         printf("\033[32m Memory of keyValues linked has freed\033[0m\n");
431         printf("\033[32m--------------------------------------\033[0m\n");
432     }
433 }

parseConf(配置文件解析器)相关推荐

  1. python 接口测试 如何写配置文件_python接口自动化测试 - configparser配置文件解析器详细使用...

    configparser简介 ConfigParser模块已在Python 3中重命名为configparser 该模块定义了ConfigParser类. ConfigParser类实现一种基本的配置 ...

  2. python 配置文件解析代码_python3从零学习-5.5.2、configparser — 配置文件解析器

    源代码: Lib/configparser.py 此模块提供了它实现一种基本配置语言 ConfigParser 类,这种语言所提供的结构与 Microsoft Windows INI 文件的类似. 你 ...

  3. 使用springMVC提供的CommonsMultipartResolver文件解析器,实现文件轻松上传

    springMVC提供的前端控制器,可以拦截所有请求,指挥调度所有后台逻辑资源. 使用传统方式进行文件上传,需要我们手动解析request对象,获取文件上传项,再进行文件的上传. springMVC框 ...

  4. MyBatis 源码分析 - 配置文件解析过程

    文章目录 * 本文速览 1.简介 2.配置文件解析过程分析 2.1 配置文件解析入口 2.2 解析 properties 配置 2.3 解析 settings 配置 2.3.1 settings 节点 ...

  5. mybatis配置文件解析

    mybatis配置文件解析 mybatis核心配置文件`mybatis-config.xml文件. mybatis的配置文件包含了会深深影响mybatis行为的设置和属性信息. 能配置的内容: con ...

  6. rest-framework之解析器

    rest-framework之解析器 本文目录 一 解析器的作用 二 全局使用解析器 三 局部使用解析器 四 源码分析 回到目录 一 解析器的作用 根据请求头 content-type 选择对应的解析 ...

  7. 【c语言】C语言配置文件解析库——iniparser

    转载自:http://blog.csdn.net/u011192270/article/details/49339071 C语言配置文件解析库--iniparser 前言:在对项目的优化时,发现Lin ...

  8. C语言配置文件解析库——iniparser

    C语言配置文件解析库--iniparser 1. 1.1前言:在对项目的优化时,发现Linux下没有专门的供给C语言使用的配置文件函数,于是搜索到了iniparser库,可以像那些面向对象语言一样,使 ...

  9. 详解Spring MVC 4之ViewResolver视图解析器

    所有的We MVC框架都有一套它自己的解析视图的机制,Spring MVC也不例外,它使用ViewResolver进行视图解析,让用户在浏览器中渲染模型.ViewResolver是一种开箱即用的技术, ...

最新文章

  1. 安卓中事件绑定的写法
  2. 一个程序员的时间管理
  3. 大学计算机一级word,大学计算机基础一级考试复习资料
  4. 20个linux命令行工具监视性能(上)
  5. unique-substrings-in-wraparound-string(好)
  6. Spring学习总结(14)——Spring10种常见异常解决方法
  7. 项目交换成功——PM(李忠)
  8. 学习 Perl(一) —— 安装及 hello world
  9. Android - Android Studio 自动(auto)添加import 语句
  10. 人工智能资源下载2024G
  11. 5G网络切片技术解析,一文让你读懂5G切片
  12. 【风马一族_SQL Server】
  13. node-sass报错
  14. 互联网日报 | 新浪同意被私有化;吉利汽车科创板首发过会;滴滴货运日单量持续破10万...
  15. 关于坐标系和投影的相关知识探讨
  16. Python中使用正则表达式以及正则表达式匹配规则
  17. 《算法设计编程实验:大学程序设计课程与竞赛训练教材》——2.4 相关题库...
  18. 国内各大互联网公司Java工程师笔经面经
  19. stdafx.cpp编译引起的C2859、C1083、LNK2001错误
  20. Numpy和Pandas的简单使用

热门文章

  1. AVR系列之TWI功能测试
  2. 安装ISA2004后,加入域时提示:远程过程调用失败且未运行的解决办法
  3. 解析HttpURLConnection与代理服务器
  4. 欧姆龙修复PLC编程软件中的多个高危漏洞
  5. Pwn2Own 2021奥斯汀黑客大赛公布类别、目标及奖金
  6. FireEye 红队失窃工具大揭秘之:分析复现 Zoho 任意文件上传漏洞(CVE-2020-8394)
  7. 只需一条信息即可远程利用严重的思科 Jabber RCE缺陷
  8. PHP如何获取txt中的文字
  9. 你不知道的Event
  10. js中this的问题