依赖的类
1 /*1 utils.h
2 *# A variety of utility functions.
3 *#
4 *# Some of the functions are duplicates of well known C functions that are not
5 *# standard.
6 *2 License
7 *[
8 *# Author: Werner Stoop
9 *# This software is provided under the terms of the unlicense.
10 *# See http://unlicense.org/ for more details.
11 *]
12 *2 API
13 */
14 #include "stdafx.h"
15 /*@ MY_MIN(a,b)
16 *# Macro that returns the smallest of its parameters.\n
17 *# As with all macros, {{a}} and {{b}} should not have side effects.
18 */
19 #define MY_MIN(a,b) (((a)<(b))?(a):(b))
20
21 /*@ MY_MAX(a,b)
22 *# Macro that returns the largest of its parameters.\n
23 *# As with all macros, {{a}} and {{b}} should not have side effects.
24 */
25 #define MY_MAX(a,b) (((a)>(b))?(a):(b))
26
27 /*@ int my_stricmp(const char *p, const char *q)
28 *# Compares two strings {{p}} and {{q}} case insensitively.
29 *#
30 *# It returns 0 if the strings are the same, a positive number if {{p}} comes after {{q}},
31 *# and negative if {{p}} comes before {{q}}.
32 */
33 int my_stricmp(const char *p, const char *q);
34
35 /*@ char *my_strdup(const char *s)
36 *# Creates a duplicate of a string {{s}} in a dynamic memory buffer.\n
37 *# The returned buffer needs to be {{free()}}d after use. It may return
38 *# {{NULL}} if the memory allocation fails.
39 */
40 char *my_strdup(const char *s);
41
42 /*@ char *my_strlower (char *p)
43 *# Converts a string {{p}} to lowercase in place.
44 *# It returns {{p}}.
45 */
46 char *my_strlower (char *p);
47
48 /*@ char *my_strupper (char *p)
49 *# Converts a string {{p}} to uppercase in place.
50 *# It returns {{p}}.
51 */
52 char *my_strupper (char *p);
53
54 /*@ char *my_strtok_r(char *str, const char *delim, char **saveptr)
55 *# Works the same as {{strtok_r(3)}} for platforms which lack it.
56 */
57 char *my_strtok_r(char *str, const char *delim, char **saveptr);
58
59 /*@ char *my_readfile (const char *fn)
60 *# Reads an entire file identified by {{fn}} into a dynamically allocated memory buffer.\n
61 *# The returned buffer needs to be {{free()}}d afterwards.\n
62 *# It returns {{NULL}} if the file could not be read.
63 */
64 char *my_readfile (const char *fn);
1 /*
2 * A variety of utility functions.
3 *
4 * See utils.h for more info
5 *
6 * This is free and unencumbered software released into the public domain.
7 * http://unlicense.org/
8 */
9 #include "stdafx.h"
10 #include <stdlib.h>
11 #include <string.h>
12 #include <stdio.h>
13 #include <ctype.h>
14
15 /* Case insensitive strcmp()
16 */
17 int my_stricmp(const char *p, const char *q) {
18 for(;*p && tolower(*p) == tolower(*q); p++, q++);
19 return tolower(*p) - tolower(*q);
20 }
21
22 /* strdup() is not ANSI C */
23 char *my_strdup(const char *s) {
24 char *a;
25 size_t len = strlen(s);
26 a = (char*)malloc(len + 1);
27 if(!a) return NULL;
28 memcpy(a, s, len + 1);
29 return a;
30 }
31
32 /* converts a string to lowercase */
33 char *my_strlower (char *p) {
34 char *s;
35 for (s = p; s[0]; s++)
36 s[0] = tolower (s[0]);
37
38 return p;
39 }
40
41 /* converts a string to lowercase */
42 char *my_strupper (char *p)
43 {
44 char *s;
45 for (s = p; s[0]; s++)
46 s[0] = toupper (s[0]);
47
48 return p;
49 }
50
51 char *my_strtok_r(char *str, const char *delim, char **saveptr) {
52 if(!str)
53 str = *saveptr;
54 if(!str[0]) {
55 *saveptr = str;
56 return NULL;
57 }
58 char *s = strpbrk(str, delim);
59 if(s) {
60 s[0] = '\0';
61 *saveptr = s + 1;
62 } else
63 for(*saveptr = str; (*saveptr)[0]; (*saveptr)++);
64 return str;
65 }
66
67 /* Reads an entire file into a dynamically allocated memory buffer.
68 * The returned buffer needs to be free()d afterwards
69 */
70 char *my_readfile(const char *fname) {
71 FILE *f;
72 long len,r;
73 char *str;
74
75 if(!(f = fopen(fname, "rb")))
76 return NULL;
77
78 fseek(f, 0, SEEK_END);
79 len = ftell(f);
80 rewind(f);
81
82 if(!(str = (char*)malloc(len+2)))
83 return NULL;
84 r = fread(str, 1, len, f);
85
86 if(r != len) {
87 free(str);
88 return NULL;
89 }
90
91 fclose(f);
92 str[len] = '\0';
93 return str;
94 }
ini格式配置文件的读写
1 /*1 ini.h
2 *# Header file for the {*INI*} parser.\n
3 *#
4 *# This is a simple parser for {*.INI*} files.
5 *# It is based around the syntax described in the Wikipedia entry at
6 *# {_http://en.wikipedia.org/wiki/INI_file_}\n
7 *#
8 *# The API has these features:
9 *{
10 ** Use {{~~ini_read()}} to read an INI file from the disc into an {{~~ini_file}}
11 *# structure or create an empty {{~~ini_file}} structure.
12 ** Use {{~~ini_get()}} to retrieve values from the {{~~ini_file}} structure.
13 ** Use {{~~ini_put()}} and {{~~ini_putf()}} to set values in the {{~~ini_file}} structure.
14 ** Use {{~~ini_write()}} to write the contents of the {{~~ini_file}} structure back to disc.
15 ** Use {{~~ini_free()}} to deallocate the {{~~ini_file}} structure.
16 ** {{~~ini_errstr()}} is used for reporting errors.
17 *}
18 *2 License
19 *[
20 *# Author: Werner Stoop
21 *# This software is provided under the terms of the unlicense.
22 *# See http://unlicense.org/ for more details.
23 *]
24 *2 API
25 */
26 #ifndef INI_H
27 #define INI_H
28
29 #if defined(__cplusplus)
30 extern "C" {
31 #endif
32
33 /*
34 * Encapsulates a parameter-value pair in an INI section.
35 * Parameters are stored in a binary search tree, which attempts (but does not
36 * guarantee) O(log(n)) behaviour.
37 */
38 typedef struct INI_PAIR
39 {
40 char *param; /* The parameter */
41 char *value; /* Its value */
42
43 /* Nodes in the tree */
44 struct INI_PAIR *left, *right;
45 } ini_pair;
46
47 /*
48 * Encapsulates a section within a INI file.
49 * Sections are stored in a binary search tree, which attempts (but does not
50 * guarantee) O(log(n)) behaviour.
51 */
52 typedef struct INI_SECTION
53 {
54 char *name; /* Name of the section */
55 ini_pair *fields; /* Fields in the section */
56
57 /* Nodes in the tree */
58 struct INI_SECTION *left, *right;
59 } ini_section;
60
61 /*@ struct ##ini_file;
62 *# Structure to encapsulate an INI file.
63 */
64 struct ini_file
65 {
66 ini_pair *globals;
67 ini_section *sections;
68 };
69
70 /*@ ini_file *##ini_read(const char *filename, int *err, int *line);
71 *# Reads an INI file named by {{filename}} and returns it as a {{~~ini_file}} object.
72 *# If {{filename}} is {{NULL}}, an empty {{ini_file}} object is created and returned.
73 *# Comments are discarded, so a later call to {{~~ini_write()}} will be
74 *# commentless.\n
75 *# It returns {{NULL}} if the INI file couldn't be read, in which case {{err}} will contain the error code
76 *# (see {{~~ini_errstr()}}) and {{line}} will contain the line in the file where the error occured.
77 *# ({{err}} and {{line}} may be {{NULL}}).
78 */
79 struct ini_file *ini_read(const char *filename, int *err, int *line);
80
81 /*@ ini_file *##ini_parse(const char *text, int *err, int *line);
82 *# Parses a null-terminated string {{text}} as an INI file.\n
83 *# It returns {{NULL}} if the INI file couldn't be read, in which case {{err}} will contain the error code
84 *# (see {{~~ini_errstr()}}) and {{line}} will contain the line in the file where the error occured.
85 *# ({{err}} and {{line}} may be {{NULL}}).
86 */
87 struct ini_file *ini_parse(const char *text, int *err, int *line);
88
89 /*@ int ##ini_write(ini_file *ini, const char *fname);
90 *# Saves all the sections and parameters in an {{ini_file}} to a file.\n
91 *# {{fname}} is the file to which to save. If {{fname}} is {{NULL}}, it is written to
92 *# {{stdout}}.
93 *# It returns 1 on success, an error code otherwise (see {{~~ini_errstr()}}).
94 */
95 int ini_write(struct ini_file *ini, const char *fname);
96
97 /*@ void ##ini_free(ini_file *ini);
98 *# Free's all the memory allocated to a {{ini_file}} object created in {{~~ini_read()}}.\n
99 *# {{ini}} is the {{ini_file}} to free
100 */
101 void ini_free(struct ini_file *ini);
102
103 /*@ int ini_has_section(struct ini_file *ini, const char *sec)
104 *# Returns true if the ini file has a specific section.
105 */
106 int ini_has_section(struct ini_file *ini, const char *sec);
107
108 /*@ const char *##ini_get(struct ini_file *ini, const char *sec, const char *par, const char *def);
109 *# Retrieves a parameter {{par}} from a section {{sec}} within the struct ini_file {{ini}}
110 *# and returns its value.\n
111 *# If {{sec}} is {{NULL}}, the global parameters in {{ini}} are searched.\n
112 *# If the value is not found, the default {{def}}, which may be {{NULL}}, is
113 *# returned.
114 */
115 const char *ini_get(struct ini_file *ini,
116 const char *sec,
117 const char *par,
118 const char *def);
119
120 /*@ int ##ini_put(struct ini_file *ini, const char *sec, const char *par, const char *val);
121 *# Sets a parameter {{par}} in section {{sec}}'s value to {{val}}, replacing the
122 *# current value if it already exists, or creates the section if it does not
123 *# exist.\n
124 *# If {{sec}} is {{NULL}}, the parameter is added to {{ini}}'s global parameters.\n
125 *# It returns 1 on success, 0 on failure (which only happens if {{malloc()}} fails).
126 */
127 int ini_put(struct ini_file *ini, const char *sec, const char *par, const char *val);
128
129 /*@ int ##ini_putf(struct ini_file *ini, const char *sec, const char *par, const char *fmt, ...);
130 *# {{~~ini_putf()}} takes a {{printf()}} style format string and uses vsnprintf() to
131 *# pass a value to {{~~ini_put()}}. This function is intended for placing
132 *# data types that are not strings into the {{ini_file}}
133 *#
134 *# The other parameters are the same as those of {{ini_put()}}.
135 */
136 int ini_putf(struct ini_file *ini,
137 const char *sec,
138 const char *par,
139 const char *fmt,
140 ...);
141
142 /*@ const char *##ini_errstr(int err)
143 *# Returns a textual description of an error code
144 */
145 const char *ini_errstr(int err);
146
147 #if defined(__cplusplus)
148 } /* extern "C" */
149 #endif
150
151 #endif /* INI_H */
1 /*
2 * This is a simple parser for .INI files.
3 * It is based around the syntax described in the Wikipedia entry at
4 * "http://en.wikipedia.org/wiki/INI_file"
5 *
6 * See ini.h for more info
7 *
8 * This is free and unencumbered software released into the public domain.
9 * http://unlicense.org/
10 */
11 #include "stdafx.h"
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <stdarg.h>
16 #include <ctype.h>
17 #include <setjmp.h>
18
19 #include <assert.h> /* Remember to define NDEBUG for release */
20
21 #include "ini.h"
22 #include "utils.h"
23 #include <crtdbg.h>
24
25 /* Maximum number of characters expected on a line.
26 It is only used by the ini_putf() function.
27 */
28 #define MAX_LINE 1024
29
30 /* Various error codes */
31 #define SUCCESS 1
32 #define FILE_CREATED 0
33 #define NO_SUCH_FILE -1
34 #define OUT_OF_MEMORY -2
35 #define MISSING_END_BRACE -3
36 #define EMPTY_SECTION -4
37 #define EXPECTED_EQUALS -5
38 #define EXPECTED_END_OF_STRING -6
39 #define ER_FOPEN -7
40 #define BAD_SYMBOL -8
41 #define EXPECTED_PARAMETER -9
42 #define EXPECTED_VALUE -10
43
44 const char *ini_errstr(int err)
45 {
46 switch(err)
47 {
48 case SUCCESS : return "Success";
49 case FILE_CREATED: return "New INI object created";
50 case NO_SUCH_FILE: return "Unable to open file";
51 case OUT_OF_MEMORY: return "Out of memory";
52 case MISSING_END_BRACE: return "Missing ']' at end of section";
53 case EMPTY_SECTION: return "Empty [] for section";
54 case EXPECTED_EQUALS : return "Expected an '='/':'";
55 case EXPECTED_END_OF_STRING : return "Expected an end of string";
56 case ER_FOPEN : return "Unable to open file";
57 case BAD_SYMBOL : return "Bad symbol";
58 case EXPECTED_PARAMETER : return "Expected a parameter (or section)";
59 case EXPECTED_VALUE : return "Expected a value";
60 }
61 return "Unknown";
62 }
63
64 /** Configurable parameters *************************************************/
65
66 /*
67 * Recursively adds sections to the tree of sections
68 */
69 static void insert_section(ini_section *r, ini_section *n) {
70 assert(r);
71 assert(n);
72
73 if(my_stricmp(r->name, n->name) < 0) {
74 if(!r->left)
75 r->left = n;
76 else
77 insert_section(r->left, n);
78 } else {
79 if(!r->right)
80 r->right = n;
81 else
82 insert_section(r->right, n);
83 }
84 }
85
86 /*
87 * Searches a tree of pairs for a specific parameter
88 */
89 static ini_pair *find_pair(ini_pair *root, const char *name) {
90 int c;
91
92 if(!root) return NULL;
93
94 c = my_stricmp(root->param, name);
95 if(c == 0)
96 return root;
97 else if(c < 0)
98 return find_pair(root->left, name);
99 else
100 return find_pair(root->right, name);
101 }
102
103 /*
104 * Searches for a specific section
105 */
106 static ini_section *find_section(ini_section *root, const char *name) {
107 int c;
108
109 if(!root) return NULL;
110
111 c = my_stricmp(root->name, name);
112 if(c == 0)
113 return root;
114 else if(c < 0)
115 return find_section(root->left, name);
116 else
117 return find_section(root->right, name);
118 }
119
120 /*
121 * Creates a new section, and adds it to a tree of sections
122 */
123 static ini_section *add_section(ini_section **root, char *name) {
124 ini_section *n;
125
126 assert(root);
127 assert(name);
128
129 n = find_section(*root, name);
130 if(n) {
131 free(name);
132 return n;
133 }
134
135 n = (ini_section*)malloc(sizeof *n);
136 if(!n) return NULL;
137
138 n->name = name;
139
140 n->fields = NULL;
141 n->left = n->right = NULL;
142
143 if(*root)
144 insert_section(*root, n);
145 else
146 *root = n;
147
148 return n;
149 }
150
151 /*
152 * Inserts a new pair n into a pair tree p
153 */
154 static void insert_pair(ini_pair *p, ini_pair *n) {
155 if(my_stricmp(p->param, n->param) < 0) {
156 if(!p->left)
157 p->left = n;
158 else
159 insert_pair(p->left, n);
160 } else {
161 if(!p->right)
162 p->right = n;
163 else
164 insert_pair(p->right, n);
165 }
166 }
167
168 /*
169 * Adds a parameter-value pair to section s
170 */
171 static ini_pair *add_pair(ini_section *s, char *p, char *v) {
172 ini_pair *n;
173
174 assert(s);
175
176 n = (ini_pair*)malloc(sizeof *n);
177 if(!n) return NULL;
178
179 n->param = p;
180 n->value = v;
181
182 n->left = n->right = NULL;
183
184 if(!s->fields)
185 s->fields = n;
186 else
187 insert_pair(s->fields, n);
188
189 return n;
190 }
191
192 /** Functions for memory deallocation ***************************************/
193
194 /*
195 * Free's a tree of parameter-value pairs
196 */
197 static void free_pair(ini_pair *p) {
198 if(!p) return;
199
200 free_pair(p->left);
201 free_pair(p->right);
202
203 free(p->param);
204 free(p->value);
205 free(p);
206 }
207
208 /*
209 * Free's all the memory allocated to a ini_section s
210 */
211 static void free_section(ini_section *s) {
212 if(!s) return;
213
214 free_section(s->left);
215 free_section(s->right);
216
217 free(s->name);
218 free_pair(s->fields);
219 free(s);
220 }
221
222 /*
223 * Free's all the memory allocated to a ini_file object in ini_read()
224 */
225 void ini_free(struct ini_file *ini) {
226 if(!ini) return;
227 free_pair(ini->globals);
228 free_section(ini->sections);
229 free(ini);
230 }
231
232 /** Parsing functions *******************************************************/
233
234 static struct ini_file *make_ini()
235 {
236 struct ini_file *ini = (ini_file*)malloc(sizeof *ini);
237 if(!ini) return NULL;
238 ini->globals = NULL;
239 ini->sections = NULL;
240 return ini;
241 }
242
243 /*
244 * Reads an INI file and returns it as a ini_file object.
245 * If filename is NULL, an empty ini_file object is created and returned.
246 */
247 struct ini_file *ini_read(const char *filename, int *err, int *line) {
248 if(line) *line = 0;
249 if(!filename)
250 {
251 if(err) *err = FILE_CREATED;
252 return make_ini();
253 }
254 else
255 {
256 char *text = my_readfile(filename);
257 if(!text) {
258 if(err) *err = NO_SUCH_FILE;
259 return NULL;
260 }
261 struct ini_file * ini = ini_parse(text, err, line);
262 free(text);
263 return ini;
264 }
265 }
266
267 #define T_END 0
268 #define T_VALUE 1
269
270 static int get_token(const char **tp, const char **tstart, const char **tend, int *line, jmp_buf err) {
271 /* *tstart points to the start of the token, while *tend points one char past the end */
272
273 const char *t = *tp;
274 int tok = T_END;
275
276 assert(tp && tstart && tend);
277
278 whitespace:
279 while(isspace(t[0])) {
280 if(t[0] == '\n' && line)
281 (*line)++;
282 t++;
283 }
284 if(t[0] == ';' || t[0] == '#') {
285 while(t[0] != '\n' && t[0] != '\0')
286 t++;
287 goto whitespace;
288 }
289
290 *tstart = t;
291 *tend = t;
292 if(t[0]) {
293 if(strchr("[]:=", t[0])) {
294 tok = *t++;
295 } else if(isgraph(t[0]) && !strchr("\"'[];#", t[0])) {
296 while(isgraph(t[0]) && !strchr("\"'[];#", t[0])) {
297 t++;
298 }
299 *tend = t;
300 tok = T_VALUE;
301 } else if(t[0] == '\"' || t[0] == '\'') {
302 char delim = t[0];
303 if(t[1] == delim && t[2] == delim) {
304 /* """Python style long strings""" */
305 t += 3;
306 *tstart = t;
307 while(!(t[0] == delim && t[1] == delim && t[2] == delim)) {
308 if(t[0] == '\0') {
309 longjmp(err, EXPECTED_END_OF_STRING);
310 } else if(t[0] == '\\')
311 t++;
312 t++;
313 }
314 *tend = t;
315 t+=3;
316 } else {
317 *tstart = ++t;
318 while(t[0] != delim) {
319 if(t[0] == '\0' || t[0] == '\n') {
320 longjmp(err, EXPECTED_END_OF_STRING);
321 } else if(t[0] == '\\')
322 t++;
323 t++;
324 }
325 *tend = t++;
326 }
327 tok = T_VALUE;
328 } else {
329 /* Unrecognized token */
330 longjmp(err, BAD_SYMBOL);
331 }
332 }
333
334 *tp = t;
335 return tok;
336 }
337
338 static char *get_string(const char *tstart, const char *tend, jmp_buf err)
339 {
340 char *string, *s;
341 const char *i;
342
343 assert(tend > tstart);
344 string = (char*)malloc(tend - tstart + 1);
345 if(!string)
346 longjmp(err, OUT_OF_MEMORY);
347
348 for(i = tstart, s = string; i < tend; i++) {
349 if(i[0] == '\\') {
350 switch(*++i) {
351 case '\\':
352 case '\'':
353 case '\"': *s++ = i[0]; break;
354 case 'r': *s++ = '\r'; break;
355 case 'n': *s++ = '\n'; break;
356 case 't': *s++ = '\t'; break;
357 case '0': *s++ = '\0'; break;
358 default: break;
359 }
360 } else {
361 *s++ = i[0];
362 }
363 }
364 assert(s - string <= tend - tstart);
365 s[0] = '\0';
366 return string;
367 }
368
369 struct ini_file *ini_parse(const char *text, int *err, int *line) {
370 jmp_buf on_error;
371 int e_code;
372
373 struct ini_file *ini = NULL;
374 ini_section *cur_sec = NULL;
375
376 const char *tstart, *tend;
377
378 int t;
379
380 if(err) *err = SUCCESS;
381 if(line) *line = 1;
382
383 ini = make_ini();
384
385 if((e_code = setjmp(on_error)) != 0) {
386 if(err) *err = e_code;
387 ini_free(ini);
388 return NULL;
389 }
390
391 while((t = get_token(&text, &tstart, &tend, line, on_error)) != T_END) {
392 if(t == '[') {
393 char *section_name;
394 if(get_token(&text, &tstart, &tend, line, on_error) != T_VALUE) {
395 longjmp(on_error, EMPTY_SECTION);
396 }
397
398 section_name = get_string(tstart, tend, on_error);
399
400 cur_sec = add_section(&ini->sections, section_name);
401 if(!cur_sec)
402 longjmp(on_error, OUT_OF_MEMORY);
403
404 if(get_token(&text, &tstart, &tend, line, on_error) != ']') {
405 longjmp(on_error, MISSING_END_BRACE);
406 }
407
408 } else if (t == T_VALUE ) {
409 char *par, *val;
410 par = get_string(tstart, tend, on_error);
411 t = get_token(&text, &tstart, &tend, line, on_error);
412 if(t != '=' && t != ':') {
413 longjmp(on_error, EXPECTED_EQUALS);
414 }
415 if(get_token(&text, &tstart, &tend, line, on_error) != T_VALUE) {
416 longjmp(on_error, EXPECTED_VALUE);
417 }
418 val = get_string(tstart, tend, on_error);
419
420 if(cur_sec)
421 add_pair(cur_sec, par, val);
422 else {
423 /* Add the parameter and value to the INI file's globals */
424 ini_pair *pair;
425 if(!(pair = (ini_pair*)malloc(sizeof *pair)))
426 longjmp(on_error, OUT_OF_MEMORY);
427
428 pair->param = par;
429 pair->value = val;
430
431 pair->left = pair->right = NULL;
432
433 if(!ini->globals)
434 ini->globals = pair;
435 else
436 insert_pair(ini->globals, pair);
437 }
438
439
440 } else
441 longjmp(on_error, EXPECTED_PARAMETER);
442 }
443
444 return ini;
445 }
446
447 /** Printing functions ******************************************************/
448
449 static void string_to_file(FILE *f, const char *s) {
450 fputc('\"', f);
451 for(; s[0]; s++) {
452 switch(s[0]) {
453 case '\n': fputs("\\n",f); break;
454 case '\r': fputs("\\r",f); break;
455 case '\t': fputs("\\t",f); break;
456 case '\"': fputs("\\\"",f); break;
457 case '\'': fputs("\\\'",f); break;
458 case '\\': fputs("\\\\",f); break;
459 default : fputc(s[0], f); break;
460 }
461 }
462 fputc('\"', f);
463 }
464
465 /*
466 * Recursively prints a tree of ini_pairs
467 */
468 static void write_pair(ini_pair *p, FILE *f) {
469 if(!p) return;
470
471 string_to_file(f, p->param);
472 fputs(" = ", f);
473 string_to_file(f, p->value);
474 fputc('\n', f);
475
476 write_pair(p->left, f);
477 write_pair(p->right, f);
478 }
479
480 /*
481 * Recursively prints a tree of INI sections
482 */
483 static void write_section(ini_section *s, FILE *f) {
484 if(!s) return;
485
486 fputs("\n[", f);
487 string_to_file(f, s->name);
488 fputs("]\n", f);
489
490 write_pair(s->fields, f);
491
492 /* The akward sequence is to ensure that values are not written sorted */
493
494 write_section(s->left, f);
495 write_section(s->right, f);
496 }
497
498 /*
499 * Saves all the sections and parameters in an ini_file to a file.
500 * If fname is NULL, it is written to stdout.
501 */
502 int ini_write(struct ini_file *ini, const char *fname) {
503 FILE *f;
504
505 if(fname) {
506 f = fopen(fname, "w");
507 if(!f)
508 return ER_FOPEN;
509 } else
510 f = stdout;
511
512 write_pair(ini->globals, f);
513 write_section(ini->sections, f);
514
515 if(fname)
516 fclose(f);
517
518 return SUCCESS;
519 }
520
521 /****************************************************************************/
522
523 int ini_has_section(struct ini_file *ini, const char *sec) {
524 return find_section(ini->sections, sec) != NULL;
525 }
526
527 /*
528 * Finds a specific parameter-value pair in the configuration file
529 */
530 static ini_pair *find_param(const struct ini_file *ini,
531 const char *sec,
532 const char *par) {
533 ini_section *s;
534 ini_pair *p;
535
536 if(!ini) return NULL;
537
538 if(sec) {
539 s = find_section(ini->sections, sec);
540 if(!s) return NULL;
541 p = s->fields;
542 } else
543 p = ini->globals;
544
545 if(!p) return NULL;
546
547 return find_pair(p, par);
548 }
549
550 /*
551 * Retrieves a parameter 'par' from a section 'sec' within the ini_file 'ini'
552 * and returns its value.
553 * If 'sec' is NULL, the global parameters ini 'ini' are searched.
554 * If the value is not found, 'def' is returned.
555 * It returns a string. Functions like atoi(), atof(), strtol() and even
556 * sscanf() can be used to convert it to the relevant type.
557 */
558 const char *ini_get(struct ini_file *ini,
559 const char *sec,
560 const char *par,
561 const char *def) {
562 ini_pair *p;
563
564 p = find_param(ini, sec, par);
565 if(!p) {
566 if(def)
567 ini_put(ini, sec, par, def);
568 return def;
569 }
570
571 return p->value;
572 }
573
574 /*
575 * Sets a parameter 'par' in section 'sec's value to 'val', replacing the
576 * current value if it already exists, or creates the section if it does not
577 * exist
578 */
579 int ini_put(struct ini_file *ini, const char *sec, const char *par, const char *val) {
580 ini_section *s;
581 ini_pair *p, **pp;
582
583 if(!ini || !val) return 0;
584
585 p = find_param(ini, sec, par);
586 if(p) {
587 /* Replace the existing value */
588 char *t = p->value;
589 if(!(p->value = my_strdup(val))) {
590 p->value = t;
591 return 0;
592 }
593
594 free(t);
595 return 1;
596 }
597
598 if(sec) {
599 s = find_section(ini->sections, sec);
600 if(!s) {
601 /* Create a new section */
602 if(!(s = (ini_section*)malloc(sizeof *s))) return 0;
603 if(!(s->name = my_strdup(sec))) {
604 free(s);
605 return 0;
606 }
607
608 s->fields = NULL;
609 s->left = s->right = NULL;
610
611 if(ini->sections)
612 insert_section(ini->sections, s);
613 else
614 ini->sections = s;
615 }
616
617 pp = &s->fields;
618 } else
619 pp = &ini->globals;
620
621 if(!(p = (ini_pair*)malloc(sizeof *p)))
622 return 0;
623
624 if(!(p->param = my_strdup(par)) || !(p->value = my_strdup(val))) {
625 free(p);
626 return 0;
627 }
628
629 p->left = p->right = NULL;
630
631 if(!*pp)
632 *pp = p;
633 else
634 insert_pair(*pp, p);
635
636 return 1;
637 }
638
639 /*
640 * ini_putf() takes a printf() style format string and uses vsnprintf() to
641 * pass a value to ini_put(). This function is intended for placing
642 * data types that are not strings into the ini_file
643 *
644 * The other parameters are the same as those of ini_put().
645 */
646 int ini_putf(struct ini_file *ini,
647 const char *sec,
648 const char *par,
649 const char *fmt,
650 ...) {
651 char buffer[MAX_LINE];
652 va_list arg;
653
654 va_start(arg, fmt);
655
656 #ifdef _MSC_VER /* Microsoft Visual C++? */
657 /* VC++ messes around with _'s before vsnprintf(): */
658 #define vsnprintf _vsnprintf
659 #endif
660
661 #if 1
662 vsnprintf(buffer, MAX_LINE, fmt, arg);
663 #else
664 vsprintf(buffer, fmt, arg );
665 assert(strlen(buffer) < MAX_LINE);
666 #endif
667 va_end(arg);
668
669 return ini_put(ini, sec, par, buffer);
670 }
调用
1 static struct ini_file *gamedb = NULL;
2 BOOL CRobomoduleTestDlg::ResetConfig()
3 {
4 ini_put(gamedb, "System", "Half", "0");
5 ini_put(gamedb, "InitialPose", "X", "0.0");
6 ini_put(gamedb, "InitialPose", "Y", "0.0");
7 ini_put(gamedb, "InitialPose", "theta", "0.0");
8
9 ini_put(gamedb, "TilingUnit_Pose", "XTrans", "0.0");
10 ini_put(gamedb, "TilingUnit_Pose", "YTrans", "0.0");
11 ini_put(gamedb, "TilingUnit_Pose", "Height", "1.10");
12
13 ini_put(gamedb, "Laser_TilingUnitO", "RotateX", "0.0");
14 ini_put(gamedb, "Laser_TilingUnitO", "RotateY", "0.0");
15 ini_put(gamedb, "Laser_TilingUnitO", "RotateZ", "0.785398163");
16
17 ini_put(gamedb, "Laser_TilingUnitO", "TransformX", "0.165");
18 ini_put(gamedb, "Laser_TilingUnitO", "TransformY", "0.0");
19 ini_put(gamedb, "Laser_TilingUnitO", "TransformZ", "0.0");
20
21 ini_put(gamedb, "LaserO", "CalibRotateX", "-0.023289177");
22 ini_put(gamedb, "LaserO", "CalibRotateY", "0.0");
23 ini_put(gamedb, "LaserO", "CalibRotateZ", "-0.01573419");
24
25 ini_put(gamedb, "LaserO", "CalibTransformX", "0.0");
26 ini_put(gamedb, "LaserO", "CalibTransformY", "0.0");
27 ini_put(gamedb, "LaserO", "CalibTransformZ", "0.0");
28
29 char buffer[256];
30 _snprintf(buffer, sizeof buffer, "%s/%s", "D:", "config.ini");
31
32 int result = ini_write(gamedb,"config.ini");
33 ini_free(gamedb);
34
35 gamedb=NULL ;
36 return TRUE;
37 }
38
39 BOOL CRobomoduleTestDlg::OnInitDialog()
40 {
41 CDialog::OnInitDialog();
42 ini_free(gamedb);
43 gamedb = ini_read(NULL, NULL, NULL);
44 int err, line;
45 ini_free(gamedb);
46 gamedb = ini_read("config.ini", &err, &line);
47 if(ini_get(gamedb,"InitialPose", "X", NULL) != NULL)
48 {
49 const char* a=ini_get(gamedb, "InitialPose", "X", NULL);
50 InitialPoseX= atof(a);
51 }
52 if(ini_get(gamedb,"InitialPose", "Y", NULL) != NULL)
53 {
54 const char* a=ini_get(gamedb, "InitialPose", "Y", NULL);
55 InitialPoseY= atof(a);
56 }
57 if(ini_get(gamedb,"InitialPose", "theta", NULL) != NULL)
58 {
59 const char* a=ini_get(gamedb, "InitialPose", "theta", NULL);
60 InitialPoseTheta= atof(a);
61 }
62 if(ini_get(gamedb,"TilingUnit_Pose", "XTrans", NULL) != NULL)
63 {
64 const char* a=ini_get(gamedb, "TilingUnit_Pose", "XTrans", NULL);
65 XTrans= atof(a);
66 }
67 if(ini_get(gamedb,"TilingUnit_Pose", "YTrans", NULL) != NULL)
68 {
69 const char* a=ini_get(gamedb, "TilingUnit_Pose", "YTrans", NULL);
70 YTrans= atof(a);
71 }
72 if(ini_get(gamedb,"TilingUnit_Pose", "Height", NULL) != NULL)
73 {
74 const char* a=ini_get(gamedb, "TilingUnit_Pose", "Height", NULL);
75 Height= atof(a);
76 }
77 if(ini_get(gamedb,"Laser_TilingUnitO", "RotateX", NULL) != NULL)
78 {
79 const char* b=ini_get(gamedb, "Laser_TilingUnitO", "RotateX", NULL);
80 RotateX= atof(b);
81 }
82 if(ini_get(gamedb,"Laser_TilingUnitO", "RotateY", NULL) != NULL)
83 {
84 const char* a=ini_get(gamedb, "Laser_TilingUnitO", "RotateY", NULL);
85 RotateY= atof(a);
86 }
87 if(ini_get(gamedb,"Laser_TilingUnitO", "RotateZ", NULL) != NULL)
88 {
89 const char* a=ini_get(gamedb, "Laser_TilingUnitO", "RotateZ", NULL);
90 RotateZ= atof(a);
91 }
92 if(ini_get(gamedb,"Laser_TilingUnitO", "TransformX", NULL) != NULL)
93 {
94 const char* a=ini_get(gamedb, "Laser_TilingUnitO", "TransformX", NULL);
95 TransformX= atof(a);
96 }
97 if(ini_get(gamedb,"Laser_TilingUnitO", "TransformY", NULL) != NULL)
98 {
99 const char* a=ini_get(gamedb, "Laser_TilingUnitO", "TransformY", NULL);
100 TransformY= atof(a);
101 }
102 if(ini_get(gamedb,"Laser_TilingUnitO", "TransformZ", NULL) != NULL)
103 {
104 const char* a=ini_get(gamedb, "Laser_TilingUnitO", "TransformZ", NULL);
105 TransformZ= atof(a);
106 }
107 if(ini_get(gamedb,"LaserO", "CalibRotateX", NULL) != NULL)
108 {
109 const char* a=ini_get(gamedb, "LaserO", "CalibRotateX", NULL);
110 CalibRotateX= atof(a);
111 }
112 if(ini_get(gamedb,"LaserO", "CalibRotateY", NULL) != NULL)
113 {
114 const char* a=ini_get(gamedb, "LaserO", "CalibRotateY", NULL);
115 CalibRotateY= atof(a);
116 }
117 if(ini_get(gamedb,"LaserO", "CalibRotateZ", NULL) != NULL)
118 {
119 const char* a=ini_get(gamedb, "LaserO", "CalibRotateZ", NULL);
120 CalibRotateZ= atof(a);
121 }
122 if(ini_get(gamedb,"LaserO", "CalibTransformX", NULL) != NULL)
123 {
124 const char* a=ini_get(gamedb, "LaserO", "CalibTransformX", NULL);
125 CalibTransformX= atof(a);
126 }
127 if(ini_get(gamedb,"LaserO", "CalibTransformY", NULL) != NULL)
128 {
129 const char* a=ini_get(gamedb, "LaserO", "CalibTransformY", NULL);
130 CalibTransformY= atof(a);
131 }
132 if(ini_get(gamedb,"LaserO", "CalibTransformZ", NULL) != NULL)
133 {
134 const char* a=ini_get(gamedb, "LaserO", "CalibTransformZ", NULL);
135 CalibTransformZ= atof(a);
136 }
137 if(ini_get(gamedb,"System", "Half", NULL) != NULL)
138 {
139 const char* a=ini_get(gamedb, "System", "Half", NULL);
140 useHalf= atof(a);
141 }
参考:https://github.com/wernsey/rengine/blob/master/src/ini.c