source: MondoRescue/branches/stable/mondo/src/lib/mr_conf.c@ 1422

Last change on this file since 1422 was 1422, checked in by Bruno Cornec, 17 years ago

mr_conf now handles # inside strings correctly (before they were considered as a comment which they are not !)

  • Property svn:eol-style set to native
File size: 10.9 KB
Line 
1/* mr_conf.c
2 *
3 * $Id$
4 *
5 * Based on the work done by Anton (c)2002-2004 Anton Kulchitsky mailto:anton@kulchitsky.org
6 * Code (c)2006 Bruno Cornec <bruno@mondorescue.org>
7 *
8 * Main file of mr_conf : a very small and simple
9 * library for configuration file reading
10 *
11 * Provided under the GPLv2
12 */
13
14
15#include <stdlib.h>
16#include <stdio.h>
17#include <string.h>
18
19#include "mr_types.h"
20#include "mr_msg.h"
21#include "mr_mem.h"
22#include "mr_gettext.h"
23
24/* error flags */
25#define MRCONF_NO_ERROR 0x0
26#define MRCONF_BAD_FILE 0x1
27#define MRCONF_READING_FAILED 0x3
28#define MRCONF_NO_GROUP_START 0x4
29#define MRCONF_NO_GROUP_END 0x5
30#define MRCONF_FIELD_NOT_FOUND 0x6
31#define MRCONF_FIELD_NO_VALUE 0x7
32#define MRCONF_TOO_LONG_STRING 0x8
33#define MRCONF_CLOSE_BUT_NOT_OPEN 0x9
34#define MRCONF_OPEN_OPENED 0xA
35#define MRCONF_CALL_BUT_NOT_OPEN 0xB
36#define MRCONF_STRING_QUOTE 0xC
37
38/*setting flags*/
39#define MRCONF_FLAG_VERBOSE 0x1
40
41/*All strings of the library are here*/
42#define MRCONF_STR_ERROR _("MRCONF: Error:")
43#define MRCONF_STR_WARNING _("MRCONF: Warning:")
44
45#define MRCONF_STR_BAD_FILE _("cannot open the file: ")
46#define MRCONF_STR_ALLOC_FAILED _("cannot allocate the memory")
47#define MRCONF_STR_READING_FAILED _("cannot read file into buffer")
48#define MRCONF_STR_DEFAULT_ERROR _("default")
49#define MRCONF_STR_FIELD_NOT_FOUND _("the field is not found, field:")
50#define MRCONF_STR_FIELD_NO_VALUE _("the field :")
51#define MRCONF_STR_OPEN_OPENED _("attempt to open mr_conf, but it is opened: aborted")
52#define MRCONF_STR_HALT _("MRCONF: Error occured: immidiate halt")
53
54/*warnings*/
55#define MRCONF_STR_SET_TO_ZERO _("variable will be set to 0")
56#define MRCONF_STR_IGNORE _("has no value, ignoring it")
57#define MRCONF_STR_CLOSE_BUT_NOT_OPEN _("attempt to close mr_conf but it has not been opened yet")
58#define MRCONF_STR_CALL_BUT_NOT_OPEN _("attempt to use mr_conf when it has not been opened yet")
59#define MRCONF_STR_STRING_QUOTE _("string should be surrounded by quotes")
60
61/*Flags of internal state*/
62#define MRCONF_INTFLAG_OPEN 0x1 /*set if memory allocated */
63
64/* Character for comments */
65#define MRCONF_COMM_CHAR '#'
66
67/*"private" members declarations*/
68static size_t mr_conf_filesize(const char *name);
69#define mr_conf_error_msg(x, y) {mr_conf_error_msg_int(x, y, __LINE__,__FILE__);}
70static void mr_conf_error_msg_int(int error_code, const char *add_line, int line, const char *file);
71static void mr_conf_remove_comments(void);
72static int mr_conf_check_int_flag(const int flag);
73static void mr_conf_set_int_flag(const int flag);
74static void mr_conf_drop_int_flag(const int flag);
75
76/*global "private" variables*/
77static char *buffer = NULL; /*buffer for configuration file */
78static int internal_flags = 0; /*state of the module */
79static FILE *CONF = NULL; /* Configuration file FD */
80
81/*if output all error and warning messages*/
82static int mr_conf_flags = MRCONF_FLAG_VERBOSE;
83
84/*
85 * Format of the configuration file is as follows:
86 *
87 * attribute1 = int_value
88 * attribute2 = float_value
89 * attribute3 = string_value
90 */
91
92
93/*open and read file: each call must be coupled with mr_conf_close
94 function: return 0 if success*/
95int mr_conf_open(const char *filename) {
96 size_t length; /*length of the buffer/file */
97 size_t res = 0;
98
99 /* check if mr_conf is already opened? */
100 if (mr_conf_check_int_flag(MRCONF_INTFLAG_OPEN)) {
101 mr_conf_error_msg(MRCONF_OPEN_OPENED, NULL);
102 return MRCONF_OPEN_OPENED;
103 }
104
105 length = mr_conf_filesize(filename);
106 CONF = fopen(filename, "r");
107
108 /*if file is empty or not exist => error */
109 if (length == 0) {
110 mr_conf_error_msg(MRCONF_BAD_FILE, filename);
111 return (MRCONF_BAD_FILE);
112 }
113
114 /*creating and reading buffer for file content */
115
116 /*allocate memory for the buffers */
117 buffer = (char *) mr_malloc(sizeof(char) * (length + 1));
118
119 /*set flag that module is in "open" state */
120 mr_conf_set_int_flag(MRCONF_INTFLAG_OPEN);
121
122 /*reading file in buffer (skip all 0 characters) */
123
124 res = fread(buffer, sizeof(char), length, CONF);
125 buffer[length] = (char) 0; /*finalize the string */
126
127 if (ferror(CONF)) {
128 mr_conf_error_msg(MRCONF_READING_FAILED, "");
129 return (MRCONF_READING_FAILED);
130 }
131
132 /* finally we have to remove all comment lines */
133 mr_conf_remove_comments();
134
135 return MRCONF_NO_ERROR;
136}
137
138/*release all memory and prepare to the next possiable config file*/
139void mr_conf_close(void) {
140 /* if not opened => error */
141 if (!mr_conf_check_int_flag(MRCONF_INTFLAG_OPEN)) {
142 mr_conf_error_msg(MRCONF_CLOSE_BUT_NOT_OPEN, NULL);
143 }
144 mr_free(buffer);
145 fclose(CONF);
146
147 /*set flag that module is in "close" state */
148 mr_conf_drop_int_flag(MRCONF_INTFLAG_OPEN);
149}
150
151/*read field value after string str in the current file*/
152static char *mr_conf_read(const char *field_name) {
153 char *p = NULL; /*pointer to the field */
154
155 /* check if mr_conf is not yet opened? */
156 if (!mr_conf_check_int_flag(MRCONF_INTFLAG_OPEN)) {
157 mr_conf_error_msg(MRCONF_CALL_BUT_NOT_OPEN, NULL);
158 return NULL;
159 }
160
161 /*read the number */
162 p = strstr(buffer, field_name);
163 if (p == NULL) {
164 mr_conf_error_msg(MRCONF_FIELD_NOT_FOUND, field_name);
165 return NULL;
166 } else {
167 p += strlen(field_name);
168 while ((*p != '\n') && (*p != '\0') && (*p != '=')) {
169 p++;
170 }
171 if (*p != '=') {
172 mr_conf_error_msg(MRCONF_FIELD_NO_VALUE, field_name);
173 return NULL;
174 } else {
175 /* points after the = sign */
176 p++;
177 }
178 }
179 /* skip initial spaces and tabs after = */
180 while ((*p == ' ') || (*p == '\t')) {
181 p++;
182 }
183
184 return p;
185}
186
187/*read integer number after string str in the current file*/
188int mr_conf_iread(const char *field_name) {
189 char *p = NULL; /*pointer to the field */
190 int ret = 0; /*return value */
191
192 p = mr_conf_read(field_name);
193 if (p != NULL) {
194 ret = atoi(p);
195 }
196 return ret;
197}
198
199/*read float/double number after string str in the current file*/
200double mr_conf_fread(const char *field_name) {
201 char *p = NULL; /*pointer to the field */
202 double ret = 0.0; /*return value */
203
204 p = mr_conf_read(field_name);
205 if (p != NULL) {
206 ret = atof(p);
207 }
208 return ret;
209}
210
211
212/*
213 reads string outstr after string str in the current file (between
214 "..."), not more than maxlength symbols: cannot check if outstr has
215 enough length! It must be at least maxlength+1 ! Returns number of
216 read chars
217*/
218char *mr_conf_sread(const char *field_name) {
219 char *p = NULL; /*pointer to the field */
220 char *q = NULL; /*pointer to the field */
221 char *r = NULL; /*pointer to the field */
222 char *ret = NULL; /*return value */
223 int size = 0; /*size of returned string */
224 int i = 0;
225
226 ret = NULL;
227
228 p = mr_conf_read(field_name);
229 if (p == NULL) {
230 return(p);
231 }
232 mr_asprintf(&q, p);
233
234 if (*p != '"') {
235 mr_conf_error_msg(MRCONF_STRING_QUOTE, "");
236 return (NULL);
237 }
238 p++;
239
240 /* trunk at first \n */
241 r = index(q,'\n');
242 r--;
243 if (*r != '"') {
244 mr_conf_error_msg(MRCONF_STRING_QUOTE, "");
245 return (NULL);
246 }
247 r--;
248
249 size = r-q+1;
250 /*copy filtered data to the buffer */
251 ret = (char *) mr_malloc(sizeof(char) * (size));
252 while (i < size - 1) {
253 ret[i] = *p;
254 i++;
255 p++;
256 }
257
258 ret[i] = (char) 0; /* and set its length */
259 mr_free(q);
260
261 return ret;
262}
263
264/*read boolean after string str in the current file*/
265bool mr_conf_bread(const char *field_name) {
266 char *p = NULL; /*pointer to the field */
267 bool ret = FALSE;
268
269 p = mr_conf_sread(field_name);
270 if (p != NULL) {
271 /* match if yes/true/1 */
272 if ((strncasecmp(p, "y" , (size_t)1) == 0) ||
273 (strncasecmp(p, "t" , (size_t)1) == 0) ||
274 (strncasecmp(p, "1" , (size_t)1) == 0)) {
275 ret = TRUE;
276 }
277 }
278 return ret;
279}
280
281/*removes all comments from the buffer*/
282static void mr_conf_remove_comments(void) {
283 char *tmp_buf; /*temporary buffer without comments */
284 size_t length /*initial length */ ;
285 size_t i; /*iterator */
286 size_t k; /*conditioned iterator for tmp_buffer */
287 bool found_quote = FALSE;
288
289 length = strlen(buffer);
290
291 /*sizing the new chain */
292 k = 0;
293 i = 0;
294 while (i < length) {
295 /* Handle quotes */
296 if (buffer[i] = '"') {
297 if (found_quote) {
298 found_quote = FALSE;
299 } else {
300 found_quote = TRUE;
301 }
302 if ((buffer[i] != MRCONF_COMM_CHAR) && (! found_quote)){
303 k++;
304 i++;
305 } else {
306 while ((buffer[i] != '\n') && (buffer[i] != (char) 0)) {
307 i++;
308 }
309 }
310 }
311 /* k is new buffer length now */
312 tmp_buf = (char *) mr_malloc(sizeof(char) * (k + 1));
313
314 k = 0;
315 i = 0;
316 while (i < length) {
317 if (buffer[i] = '"') {
318 if (found_quote) {
319 found_quote = FALSE;
320 } else {
321 found_quote = TRUE;
322 }
323 if ((buffer[i] != MRCONF_COMM_CHAR) && (! found_quote)){
324 tmp_buf[k++] = buffer[i++];
325 } else {
326 while ((buffer[i] != '\n') && (buffer[i] != (char) 0)) {
327 i++;
328 }
329 }
330 }
331 tmp_buf[k] = (char) 0; /*and set its length */
332
333 mr_free(buffer);
334 /*copy filtered data to the buffer */
335 buffer = tmp_buf;
336}
337
338static int mr_conf_check_int_flag(const int flag) {
339 return (flag & internal_flags);
340}
341
342static void mr_conf_set_int_flag(const int flag) {
343 internal_flags = flag | internal_flags;
344}
345
346static void mr_conf_drop_int_flag(const int flag) {
347 internal_flags = (~flag) & internal_flags;
348}
349
350
351/*local function to define size of a file. Return 0 for mistake*/
352static size_t mr_conf_filesize(const char *name) {
353 FILE *F = fopen(name, "r"); /*file to open */
354 size_t length; /*number to return */
355
356 if (F == NULL) {
357 return 0;
358 }
359
360 fseek(F, 0, SEEK_END); /*set position to the end of file */
361 length = ftell(F); /*define number of position=> this is its
362 length */
363 fclose(F);
364
365 return length;
366}
367
368/*output error message*/
369static void mr_conf_error_msg_int(int error_code, const char *add_line, int line, const char *file) {
370 if ((mr_conf_flags & MRCONF_FLAG_VERBOSE)) { /*if verbose mode */
371 switch (error_code) {
372 case MRCONF_BAD_FILE:
373 mr_msg_int(0,line,file,"%s %s %s\n", MRCONF_STR_ERROR, MRCONF_STR_BAD_FILE,
374 add_line);
375 break;
376
377 case MRCONF_READING_FAILED:
378 mr_msg_int(0,line,file,"%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_READING_FAILED);
379 break;
380
381 case MRCONF_FIELD_NOT_FOUND:
382 mr_msg_int(0,line,file,"%s %s \"%s\"\n", MRCONF_STR_ERROR, MRCONF_STR_FIELD_NOT_FOUND, add_line);
383 mr_msg_int(0,line,file,"%s %s\n", MRCONF_STR_WARNING, MRCONF_STR_SET_TO_ZERO);
384 break;
385
386 case MRCONF_FIELD_NO_VALUE:
387 mr_msg_int(0,line,file,"%s %s \"%s\"\n", MRCONF_STR_ERROR, MRCONF_STR_FIELD_NO_VALUE, add_line);
388 mr_msg_int(0,line,file,"%s %s\n", MRCONF_STR_WARNING, MRCONF_STR_IGNORE);
389 break;
390
391 case MRCONF_CLOSE_BUT_NOT_OPEN:
392 mr_msg_int(0,line,file,"%s %s\n", MRCONF_STR_WARNING, MRCONF_STR_CLOSE_BUT_NOT_OPEN);
393 break;
394
395 case MRCONF_CALL_BUT_NOT_OPEN:
396 mr_msg_int(0,line,file,"%s %s\n", MRCONF_STR_WARNING, MRCONF_STR_CALL_BUT_NOT_OPEN);
397 break;
398
399 case MRCONF_OPEN_OPENED:
400 mr_msg_int(0,line,file,"%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_OPEN_OPENED);
401 break;
402
403 case MRCONF_STRING_QUOTE:
404 mr_msg_int(0,line,file,"%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_STRING_QUOTE);
405 break;
406
407 default:
408 mr_msg_int(0,line,file,"%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_DEFAULT_ERROR);
409 break;
410 }
411 }
412}
Note: See TracBrowser for help on using the repository browser.