• parseConf(配置文件解析器)


      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 //用''填充字符串
    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.删除一行中前面的' ','	';
    123  *      2.忽略掉那些以'
    ','#','='开头的行;
    124  *      3.如果一行中有'#'注释,将'#'所在的位置设置'',代表字符串末尾;
    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
    ");
    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
    ");
    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] != '	')){
    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++] = '';  
    183                 break;
    184             }else if(dealWithBuffer[i] == '=' ){
    185                 equalIndex = i;
    186             }
    187         }
    188         /**
    189          * 删除以换行符,#,=等字符开始的行,同时清空dealWithBuffer缓冲区
    190          */
    191         if((equalIndex == 0) || (lineBuffer[ 0 ] == '
    ') || (lineBuffer[ 0 ] == '#')) {
    192             /**
    193              * 一定要记得清理这个缓存
    194              */
    195             cleanString(dealWithBuffer);
    196             continue;
    197         }
    198         /**
    199          * 如果一行数据末尾是'
    ',则换成'',相当于移除'
    '
    200          */
    201         length = strlen(dealWithBuffer);
    202         if(dealWithBuffer[length-1] == '
    '){
    203             dealWithBuffer[length-1] = '';
    204         }
    205         /**
    206          * 通过将'='换成'',这样就key,value字符串
    207          */
    208         dealWithBuffer[equalIndex] = '';
    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的值,也就是去掉字符串左右两边的' ','	'
    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清理,因为字符中间有''
    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] = '';
    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
    ");
    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
    ");
    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
    ");
    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
    ");
    322         return;
    323     }
    324 
    325     int index = 1;
    326     kvpair* currentkvpair = kvpairs;
    327     printf("33[32m--------------------------------------33[0m
    ");
    328     while(currentkvpair){
    329         printf("33[32m   %03d: %s=%s33[0m
    ", index, currentkvpair->key, currentkvpair->value);
    330         currentkvpair = currentkvpair->next;
    331         index++;
    332     }
    333     printf("33[32m--------------------------------------33[0m
    ");
    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) || ('	' == *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]) || ('	' == str[i]) || ('' == str[i]))
    372             str[i] = '';
    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:
    
            ./parseConf <configure file> 
    
    ");
    387         return ;
    388     }
    389 
    390     /**
    391      * 获取键值对,键值对头节点保存在keyValues中
    392      */
    393     kvpair* keyValues;
    394     getkvpairs(argv[1], &keyValues);
    395     printf("
    33[32m\\\\\\\\\\\\\\\\\33[36mDemo33[32m/////////////////33[0m
    ");
    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
    ", buffer);
    408 
    409     close(fd);
    410 
    411     /**
    412      * 将当前的所有的键值对打印出来
    413      */
    414     printkvpairs(keyValues);
    415     /**
    416      * 通过key获取value值
    417      */
    418     char* key = "rows";
    419     printf("33[32mgetValueBykey:key = %s; value = %s33[0m
    ", key, key2val(key, keyValues));
    420     /**
    421      * 通过value获取key值
    422      */
    423     char* value = "24";
    424     printf("33[32mgetKeyByValue:value = %s; key = %s33[0m
    ", value, val2key(value, keyValues));
    425     printf("33[32m--------------------------------------33[0m
    ");
    426     /**
    427      * 释放keyValues链表
    428      */
    429     if(freekvpairs(keyValues) == 0){
    430         printf("33[32m Memory of keyValues linked has freed33[0m
    ");
    431         printf("33[32m--------------------------------------33[0m
    ");
    432     }
    433 }
  • 相关阅读:
    基于Form组件实现的增删改和基于ModelForm实现的增删改
    Git和Github的基本操作
    如果获取的数据不是直接可以展示的结构---三种操作方式
    可迭代对象和迭代器生成器
    django之整体复习
    权限管理之大致流程
    kindedit编辑器和xxs攻击防护(BeautifulSoup)的简单使用
    博客系统之评论树与评论楼相关操作
    中介模型以及优化查询以及CBV模式
    angularjs中ajax请求时传递参数的方法
  • 原文地址:https://www.cnblogs.com/zengjfgit/p/4373987.html
Copyright © 2020-2023  润新知