Article From:https://www.cnblogs.com/lsgsanxiao/p/9122164.html

Original address: https://blog.csdn.net/niha1993825jian/article/details/41086403

#include <stdio.h>  
#include <errno.h>  
#include <ctype.h>  
#include <string.h>  
#include <stdlib.h>  
#include <stdbool.h>  
  
#define  MAX_VALUE  64 /* Define the maximum length of the section, key, value string * /// printf("File = %s\nLine = %d\nFunc=%s\nDate=%s\nTime=%s\n", __FILE__, __LINE__, __FUNCTION__, __DATE__, __TIME__);  
#define  PRINT_ERRMSG(STR) fprintf(stderr,"line:%d,msg:%s,eMsg:%s\n", __LINE__, STR, strerror(errno))  
  
typedef struct _option {  
  char    key[MAX_VALUE];   /* Corresponding key*/  
  char    value[MAX_VALUE]; /* Corresponding value*/  
  struct  _option *next;    /* Linked list connection identifier*/  
}Option;  
  
typedef struct _data {  
  char    section[MAX_VALUE]; /* Save the section value*/  
  Option  *option;            /* optionChain Headers*/  
  struct  _data *next;        /* Linked list connection identifier*/  
}Data;  
  
typedef struct {  
  char    comment;              /* A symbol for annotation*/  
  char    separator;            /* Representation of a delimiter*/  
  char    re_string[MAX_VALUE]; /* The value of the return value string*/  
  int     re_int;               /* Return the value of int*/  
  bool    re_bool;              /* Return the value of bool*/  
  double  re_double ;           /* Return to the double type*/  
  Data    *data;                /* Save the header of the data*/  
}Config;  
  
/** 
* Determine whether a string is empty* return to true for null, not return to false for empty**/  
bool str_empty(const char *string)  
{  
  return NULL == string || 0 == strlen(string);  
}  
  
/** 
* Add section, key, value to the linked list* if the addition does not exist when the section is added, one additional* if the corresponding section key does not exist, a new one is added.* if section has already existed, it will not be repeated*If the key corresponding to section already exists, it will only override the value of key.**/  
bool cnf_add_option(Config *cnf, const char *section, const char *key, const char *value)  
{  
  if (NULL == cnf || str_empty(section) || str_empty(key) || str_empty(value)) {  
    return false; /* Incorrect parameter, return to false*/  
  }  
    
  Data *p = cnf->data; /* Let the variable P loop traverse the data and find the corresponding section*/  
  while (NULL != p && 0 != strcmp(p->section, section)) {  
    p = p->next;  
  }  
    
  if (NULL == p) { /* It shows that section is not found, and one needs to be added*/  
    Data *ps = (Data*)malloc(sizeof(Data));  
    if (NULL == ps) {  
      exit(-1); /* Application memory error*/  
    }  
    strcpy(ps->section, section);  
    ps->option = NULL;    /* The initial option is empty*/  
    ps->next = cnf->data; /* cnf->dataMaybe NULL*/  
    cnf->data = p = ps;   /* Inserting the head insert into a chain table*/  
  }  
    
  Option *q = p->option;  
  while (NULL != q && 0 != strcmp(q->key, key)) {  
    q = q->next; /* Traverse the option to check whether the key has already existed*/  
  }  
    
  if (NULL == q) { /* There is no option, then a new one*/  
    q = (Option*)malloc(sizeof(Option));  
    if (NULL == q) {  
      exit(-1); /* Application memory error*/  
    }  
    strcpy(q->key, key);  
    q->next = p->option; /*Here p-> option may be NULL, but it doesn't matter.*/  
    p->option = q; /* Inserting the head insert into a chain table*/  
  }  
  strcpy(q->value, value); /* In any case, change the value.*/  
    
  return true;  
}  
  
/** 
* Remove all the blanks in the string* and ignore the annotated part* eventually get a string without a blank**/  
bool strip_comments(char *string, char comment)  
{  
  if (NULL == string || '\n' == *string || '\r' == *string) {  
    return false; /* The first character is a return or a line that represents a blank line*/  
  }  
    
  char *p, *q; /* Underneath all the blank characters in the string*/  
  for (p = q = string; *p != '\0' && *p != comment; p++) {  
    if (0 == isspace(*p)) {  
      *q++ = *p; /* Not a blank character rewrites a string*/  
    }  
  }  
  *q = '\0';  
    
  return 0 != strlen(string); /* The string length is not 0, indicating that the data is available.*/  
}  
  
/** 
* Pass the configuration file path* parameters have file paths, annotated characters, delimiters* return to the Config structure**/  
Config *cnf_read_config(const char *filename, char comment, char separator)  
{  
  Config *cnf     = (Config*)malloc(sizeof(Config));  
  cnf->comment    = comment; /* The character and later character of each line will be discarded*/  
  cnf->separator  = separator; /* Used to separate Section and data*/  
  cnf->data       = NULL; /* The initial data is empty*/  
    
  if (str_empty(filename)) {  
    return cnf; /* The empty string returns the object directly*/  
  }  
    
  char *p, sLine[MAX_VALUE];    /* Save a row of data to a string*/  
  char section[MAX_VALUE], key[MAX_VALUE], value[MAX_VALUE]; /* Caching section, key, value*/  
  FILE *fp = fopen(filename, "r");  
  if(NULL == fp) {  
    PRINT_ERRMSG("fopen");  
    exit(errno); /* Read file errors directly according to error code*/  
  }  
    
  while (NULL != fgets(sLine, MAX_VALUE, fp)) {  
    if (strip_comments(sLine, cnf->comment)) { /* Remove all the blanks from the string, and the annotations are ignored*/  
      if ('[' == sLine[0] && ']' == sLine[strlen(sLine)-1]) {  
        memset(section, '\0', MAX_VALUE); /* Empty section, because strncpy does not add'\0'*/  
        strncpy(section, sLine+1, strlen(sLine)-2);  
      } else if (NULL != (p = strchr(sLine, cnf->separator))) {  /* Existence separators*/  
        memset(key,   '\0', MAX_VALUE); /* Empty key, because strncpy does not add'\0'*/  
        strncpy(key,  sLine, p - sLine);  
        strcpy(value, p + 1); /* strcpyIt's going to add'\0', so it's right.*/  
        cnf_add_option(cnf, section, key, value); /* Add section, key, value*/  
      } /* If the row does not have a separator, the line is ignored*/  
    } /* end strip_comments */  
  } /* end while */  
    
  fclose(fp);  
  return cnf;  
}  
  
/** 
* Get the value of the specified type* assign a value to a corresponding value according to a different type* this method needs to be noted that the conversion of int and double is not satisfactory, that is, 0.* it is good to judge when you need to write your own code**/  
bool cnf_get_value(Config *cnf, const char *section, const char *key)  
{  
  Data *p = cnf->data; /* Let the variable P loop traverse the data and find the corresponding section*/  
  while (NULL != p && 0 != strcmp(p->section, section)) {  
    p = p->next;  
  }  
    
  if (NULL == p) {  
    PRINT_ERRMSG("section not find!");  
    return false;  
  }  
    
  Option *q = p->option;  
  while (NULL != q && 0 != strcmp(q->key, key)) {  
    q = q->next; /* Traverse the option to check whether the key has already existed*/  
  }  
    
  if (NULL == q) {  
    PRINT_ERRMSG("key not find!");  
    return false;  
  }  
    
  strcpy(cnf->re_string, q->value);       /* Assigning the result string*/  
  cnf->re_int    = atoi(cnf->re_string);  /* Conversion to plastic*/  
  cnf->re_bool   = 0 == strcmp ("true", cnf->re_string); /* Conversion to bool type*/  
  cnf->re_double = atof(cnf->re_string);  /* Conversion to double type*/  
    
  return true;  
}  
  
/** 
* Determine whether section exists* no return null pointer* exists to return the Data pointer that contains that section**/  
Data *cnf_has_section(Config *cnf, const char *section)  
{  
  Data *p = cnf->data; /* Let the variable P loop traverse the data and find the corresponding section*/  
  while (NULL != p && 0 != strcmp(p->section, section)) {  
    p = p->next;  
  }  
    
  if (NULL == p) { /* Not to find it does not exist*/  
    return NULL;  
  }  
    
  return p;  
}  
  
/** 
* Determine whether the specified option exists* no return null pointer* the existence returns the Option pointer that contains the key under that section.**/  
Option *cnf_has_option(Config *cnf, const char *section, const char *key)  
{  
  Data *p = cnf_has_section(cnf, section);  
  if (NULL == p) { /* Not to find it does not exist*/  
    return NULL;  
  }  
    
  Option *q = p->option;  
  while (NULL != q && 0 != strcmp(q->key, key)) {  
    q = q->next; /* Traverse the option to check whether the key has already existed*/  
  }  
  if (NULL == q) { /* Not to find it does not exist*/  
    return NULL;  
  }  
    
  return q;  
}  
  
/** 
* Write the Config object into the specified file* header indicates an annotation at the beginning of the file* write success returns true**/  
bool cnf_write_file(Config *cnf, const char *filename, const char *header)  
{  
  FILE *fp = fopen(filename, "w");  
  if(NULL == fp) {  
    PRINT_ERRMSG("fopen");  
    exit(errno); /* Read file errors directly according to error code*/  
  }  
    
  if (0 < strlen(header)) { /* File annotations are not empty, write annotations to files*/  
    fprintf(fp, "%c %s\n\n", cnf->comment, header);  
  }  
    
  Option *q;  
  Data   *p = cnf->data;  
  while (NULL != p) {  
    fprintf(fp, "[%s]\n", p->section);  
    q = p->option;  
    while (NULL != q) {  
      fprintf(fp, "%s %c %s\n", q->key, cnf->separator, q->value);  
      q = q->next;  
    }  
    p = p->next;  
  }  
    
  fclose(fp);  
  return true;  
}  
  
/** 
* Delete option**/  
bool cnf_remove_option(Config *cnf, const char *section, const char *key)  
{  
  Data *ps = cnf_has_section(cnf, section);  
  if (NULL == ps) { /* Not to find it does not exist*/  
    return NULL;  
  }  
    
  Option *p, *q;  
  q = p = ps->option;  
  while (NULL != p && 0 != strcmp(p->key, key)) {  
    if (p != q) { q = q->next; } /* Always let Q be in the last node of the p*/  
    p = p->next;  
  }  
    
  if (NULL == p) { /* Not to find it does not exist*/  
    return NULL;  
  }  
    
  if (p == q) { /* The first option matches*/  
    ps->option = p->next;  
  } else {  
    q->next = p->next;  
  }  
    
  free(p);  
  q = p = NULL; // Avoid wild pointers
    
  return true;  
}  
  
/** 
* Delete section**/  
bool cnf_remove_section(Config *cnf, const char *section)  
{  
  if (str_empty(section)) {  
    return false;  
  }  
    
  Data *p, *q;  
  q = p = cnf->data; /* Let the variable P loop traverse the data and find the corresponding section*/  
  while (NULL != p && 0 != strcmp(p->section, section)) {  
    if (p != q) { q = q->next; } /* Always let Q be in the last node of the p*/  
    p = p->next;  
  }  
    
  if (NULL == p) { /* No section was found*/  
    return false;  
  }  
    
  if (p == q) { /* This represents the first section, so the chain header position changes.*/  
    cnf->data = p->next;  
  } else { /* This is the middle or tail node at this point*/  
    q->next = p->next;  
  }  
    
  Option *o = p->option;  
  while (NULL != o) {  
    free(o); /* Loop release all option*/  
    o = o->next;  
  }  
  p->option = NULL; // Avoid wild pointers
  free(p); /* Release the deleted section*/  
  q = p = NULL;  // Avoid wild pointers
    
  return true;  
}  
  
/** 
* Print the current Config object**/  
void print_config(Config *cnf)  
{  
  Data *p = cnf->data; // Loop print results
  while (NULL != p) {  
    printf("[%s]\n",p->section);  
      
    Option *q = p->option;  
    while (NULL != q) {  
      printf("  %s %c %s\n", q->key, cnf->separator, q->value);  
      q = q->next;  
    }  
    p = p->next;  
  }  
}  
  
/** 
* Main program, put at the bottom* avoid repeated declarations of other functions**/  
int main(int argc, char *argv[])  
{  
  // Read the configuration file cnf.ini, the annotation character is the key, the separated key value is =
  Config *cnf = cnf_read_config("cnf.ini", '#', '=');  
  if (NULL == cnf) {  
    return -1; /* fail to create object*/  
  }  
    
  printf("-------------- After Read File --------------\n");  
  print_config(cnf); // Print CNF objects
  cnf_remove_section(cnf,"AAA"); // Delete the section of AAA
  cnf_remove_option(cnf, "CC","df");  // Delete the DF under CC
  printf("-------------- After remove --------------\n");  
  print_config(cnf); // Print CNF objects
  cnf_add_option(cnf, "NEW", "new_1", "true"); // The value of new_1 under the new NEW
  cnf_add_option(cnf, "NEW", "new_2", "asdas"); // The value of new_2 under the new NEW
  cnf_add_option(cnf, "NEW1", "new_2", "true");  
  printf("-------------- After add --------------\n");  
  print_config(cnf); // Print CNF objects
    
  cnf_get_value(cnf, "NEW1", "new_2"); // Get the new_2 value under NEW1
  printf("cnf_get_value:%s,%d,%d,%f\n",cnf->re_string,cnf->re_int,cnf->re_bool,cnf->re_double);  
    
  cnf->separator = ':'; // Separates Fu Gaicheng: a colon
  cnf_write_file(cnf, "cnf_new.ini", "write a new ini file!"); // Write the object to the cnf_new.ini file
  return 0;  
}  

 

Leave a Reply

Your email address will not be published. Required fields are marked *