C. Construct a simple configuration file reading library and a configuration file reading library.
Preface
I recently saw this article,
Json engine performance comparison report http://www.oschina.net/news/61942/cpp-json-compare? Utm_source = tuicool
I feel that there are a lot of technical difficulties and a lot of mountains are revealed.
Json standard definition http://www.json.org/json-zh.html
I have written a general json parser. The comparison between lines 1000 and the above is really weak. Later I saw a few of the source code blowing out of it. I feel deeply touched upon it.
I am not enough. I have been researching some downloads and found that using and designing and developing are two different things.
The main foundation of json design is in the structure design and Syntax Parsing. The encapsulation of a framework lies in the routines. If the routines are clear, the design can be combined.
Together. No matter what you do, it will always be optimized as long as you learn it. Below we will share a relatively simple article, but we will also configure the C framework in terms of structure design and Syntax Parsing.
Read capability.
Body
1. parsing file description
The following figure shows the configuration file: test. php
<? php
// Here is a simple test php variable resolution
$ abc = "123456";
$ str = "1231212121212121212
21222222222
2121212 \ "
";
We only need to parse the above data, save it in the global area and call it next time. For example
The running result is as above. For the above configuration, there are the following rules
a. $ followed by the variable name
b. Use in the middle = split
c. Variable contents are wrapped with "", need to use "Use \"
The above is the configuration grammar rules. Below we gradually explain the content of grammar analysis
2. Simple core code, grammar analysis test
The specific scanning algorithm is as follows
a. Skip the leading blank character and find the $ character
b. If $ is followed by a blank character, then read this line directly
c. Scan to = character, otherwise read this line
d Scan to "character
e Scan to the last "character, the previous character must not be \, otherwise the reading of this line is completed.
The above is the algorithm idea for processing, which is easier to understand. The specific test code is as follows
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define _STR_PATH "test.php"
/ *
* Process the file content here and output the parsed file content
* /
int main (int argc, char * argv [])
{
int c, n;
char str [1024];
int idx;
FILE * txt = fopen (_STR_PATH, "rb");
if (NULL == txt) {
puts ("fopen is error!");
exit (EXIT_FAILURE);
}
// Handle the reading problem here
while ((c = fgetc (txt))! = EOF) {
//1.0 Skip white space characters first
while (c! = EOF && isspace (c))
c = fgetc (txt);
//2.0 if the first character encountered is not '$'
if (c! = '$') {// Read this line
while (c! = EOF && c! = '\ n')
c = fgetc (txt);
continue;
}
//2.1 The first character is a $ legal character, the beginning cannot be a space, otherwise it is also read
if ((c = fgetc (txt))! = EOF && isspace (c)) {
while (c! = EOF && c! = '\ n')
c = fgetc (txt);
continue;
}
// Start recording
idx = 0;
//3.0 find the first equal sign
while (c! = EOF && c! = '=')
str [idx ++] = c, c = fgetc (txt);
if (c! = '=') // Invalid analysis ends directly
break;
//4.0 find the first "
while (c! = EOF && c! = '\ "')
str [idx ++] = c, c = fgetc (txt);
if (c! = '\ "') // Invalid analysis ends directly
break;
//4.1 Find the second equal sign
do {
n = str [idx ++] = c;
c = fgetc (txt);
} while (c! = EOF && c! = '\ "' && n! = '\\');
if (c! = '\ "') // Invalid analysis ends directly
break;
str [idx] = '\ 0';
puts (str);
// Last read to the end of the line
while (c! = EOF && c! = '\ n')
c = fgetc (txt);
if (c! = '\ n')
break;
}
fclose (txt);
system ("pause");
return 0;
}
The output of the above code is the above. The algorithm is straightforward and easy to understand. Writing a small function here is still very fulfilling. Especially looking at those famous open source code libraries, it is particularly cool.
The above code can be practiced by yourself, it is very interesting, there is no difficulty here. The code will be optimized from the previous framework.
3. The finalized interface description
Here we will apply the above ideas to actual combat, first look at the contents of the scconf.h interface as follows
#ifndef _H_SCCONF
#define _H_SCCONF
/ **
* Here is the configuration file reading interface,
* Write configuration, read configuration, need to point to the start of the configuration path _STR_SCPATH
* /
#define _STR_SCCONF_PATH "module / schead / config / config.ini"
/ *
* Start the configuration reading function, or restart
* /
extern void sc_start (void);
/ *
* Get the value of the corresponding key configuration, through the key
* key: name in configuration
*: Return the corresponding key value, if not return NULL, and print the log
* /
extern const char * sc_get (const char * key);
#endif //! _H_SCCONF
There are only two interfaces. Enable this configuration to read the library and get the content of the specified key. The file directory structure is as follows
The above interface is also very simple to use
sc_start ();
puts (sc_get ("heoo"));
The config.ini configuration content is as follows
/ *
* This is equivalent to the form of php definition variable, definition
* The configuration file can be read later. Sc_get ("heoo") => "Hello!"
* /
$ heoo = "Hello World \ n";
$ yexu = "\" How are you \ ",
I am fine, thanks!";
$ end = "coding future 123 runing,";
The specific implementation content is directly introduced later.
4. Specific implementation in the current development library
First look at the code implemented by scconf.c
#include <scconf.h>
#include <scatom.h>
#include <tree.h>
#include <tstring.h>
#include <sclog.h>
// Simple binary tree structure
struct dict {
_TREE_HEAD;
char * key;
char * value;
};
// Function creation function, kv is a structure like [abc \ 012345]
static void * __dict_new (tstring tstr)
{
char * ptr; // Temporary variables
struct dict * nd = malloc (sizeof (struct dict) + sizeof (char) * (tstr-> len + 1));
if (NULL == nd) {
SL_NOTICE ("malloc struct dict is error!");
exit (EXIT_FAILURE);
}
nd-> __ tn.lc = NULL;
nd-> __ tn.rc = NULL;
// Read more books, the rest is sad, 1%, not me,
nd-> key = ptr = (char *) nd + sizeof (struct dict);
memcpy (ptr, tstr-> str, tstr-> len + 1);
while (* ptr ++)
;
nd-> value = ptr;
return nd;
}
// Start adding
static inline int __dict_acmp (tstring tstr, struct dict * rnode)
{
return strcmp (tstr-> str, rnode-> key);
}
// Find and delete
static inline int __dict_gdcmp (const char * lstr, struct dict * rnode)
{
return strcmp (lstr, rnode-> key);
}
// Delete method
static inline void __dict_del (void * arg)
{
free (arg);
}
// The foreplay is too long, it's not over yet.
static tree_t __tds; // Save dictionary The default value is NULL
// The default __tds destruction function
static inline void __tds_destroy (void)
{
tree_destroy (& __ tds);
}
static int __lock; // For locking, the default value is 0
static void __analysis_start (FILE * txt, tree_t * proot)
{
char c, n;
TSTRING_CREATE (tstr);
// Handle the reading problem here
while ((c = fgetc (txt))! = EOF) {
//1.0 Skip white space characters first
while (c! = EOF && isspace (c))
c = fgetc (txt);
//2.0 if the first character encountered is not '$'
if (c! = '$') {// Read this line
while (c! = EOF && c! = '\ n')
c = fgetc (txt);
continue;
}
//2.1 The first character is a $ legal character, the beginning cannot be a space, otherwise it is also read
if ((c = fgetc (txt))! = EOF && isspace (c)) {
while (c! = EOF && c! = '\ n')
c = fgetc (txt);
continue;
}
// Start recording
tstr.len = 0;
//3.0 find the first equal sign
while (c! = EOF && c! = '=') {
if (! isspace (c))
tstring_append (& tstr, c);
c = fgetc (txt);
}
if (c! = '=') // Invalid analysis ends directly break;
c = '\ 0';
//4.0 find the first "
while (c! = EOF && c! = '\ "') {
if (! isspace (c))
tstring_append (& tstr, c);
c = fgetc (txt);
}
if (c! = '\ "') // Invalid analysis ends directly
break;
//4.1 Find the second equal sign
for (n = c; (c = fgetc (txt))! = EOF; n = c) {
if (c == '\ "' && n! = '\\')
break;
tstring_append (& tstr, c);
}
if (c! = '\ "') // Invalid analysis ends directly
break;
// This is the legal character, and the detection is started,
tree_add (proot, & tstr);
// Last read to the end of the line
while (c! = EOF && c! = '\ n')
c = fgetc (txt);
if (c! = '\ n')
break;
}
TSTRING_DESTROY (tstr);
}
/ *
* Start the configuration reading function, or restart
* /
void
sc_start (void)
{
FILE * txt = fopen (_STR_SCCONF_PATH, "r");
if (NULL == txt) {
SL_NOTICE ("fopen" _STR_SCCONF_PATH "r is error!");
return;
}
ATOM_LOCK (__ lock);
// First release this __tds, this __tds memory is the same as the program cycle
__tds_destroy ();
// This underlying library, the lack of memory is directly exited
__tds = tree_create (__ dict_new, __dict_acmp, __dict_gdcmp, __dict_del);
// The following is the analysis and reading content
__analysis_start (txt, & __ tds);
ATOM_UNLOCK (__ lock);
fclose (txt);
}
/ *
* Get the value of the corresponding key configuration, through the key
* key: name in configuration
*: Return the corresponding key value, if not return NULL, and print the log
* /
inline const char *
sc_get (const char * key)
{
struct dict * kv;
if ((! key) || (! * key) ||! (kv = tree_get (__ tds, key, NULL)))
return NULL;
return kv-> value;
}
The data structure uses the general tree.h binary search tree structure. The lock uses the scatom.h atomic lock, and the storage content uses tstring.h string memory management
Grammatical analysis is to parse characters according to the above reading ideas
static void __analysis_start (FILE * txt, tree_t * proot);
The data structure is
// Simple binary tree structure
struct dict {
_TREE_HEAD;
char * key;
char * value;
};
Simple binary tree structure with key.
5. Use display
Let's test the above library, first test the code as follows test_scconf.c
#include <schead.h>
#include <scconf.h>
// After writing, what can I do, alone
int main (int argc, char * argv [])
{
const char * value;
sc_start ();
// Simple test configuration read content
value = sc_get ("heoo");
puts (value);
value = sc_get ("heoo2");
if (value)
puts (value);
else
puts ("heoo2 does not exist");
value = sc_get ("yexu");
puts (value);
value = sc_get ("end");
puts (value);
system ("pause");
return 0;
}
The results are as follows
For the configuration, see the config.ini above. Here we have completed the simple configuration file function. I want to rip a bit. I have used more languages or libraries. I still feel that the advanced VS + .Net library development is the best.
Building blocks is the most enjoyable, all functions are used, and the code design is also very beautiful. The only pity is that the speed is a bit slow and a little bloated. Personally feel that the development of C # library is the top bluff of the window C ++, C # is not promoted
Going out and dying of the C ++ programmers on the window, all moved to the ranks of Linux C / C ++ development. What is more interesting is that C # is not red because of Microsoft's dad, but because of the father of Unity 3D.
C # + VS is really beautiful to write, but if you do n’t need VS, let me say it another way. The test of a window programmer is to let him leave vs. whether it starts to be so ecstatic.
It is recommended to learn more as a programmer, because they are all languages, and it is convenient to communicate after learning more. What do you think?
Afterword
Mistakes are inevitable, corrections are welcome, as I grow older, I feel that I am still very watery. I need to learn a lot of things, and I also need to abandon many things. For the unknown,
It's a record of all the chaos. Looking at the source code of the open source project is still very cool. Next time I have the opportunity to share the handwriting and an efficient cjson engine.