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

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

Fix a bug where a msg was used instead of a code

  • Property svn:eol-style set to native
File size: 11.3 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#define MRCONF_STR_STRING_ENDQUOTE _("a string is not finished by a quote")
61
62/*Flags of internal state*/
63#define MRCONF_INTFLAG_OPEN 0x1 /*set if memory allocated */
64
65/* Character for comments */
66#define MRCONF_COMM_CHAR '#'
67
68/*"private" members declarations*/
69static size_t mr_conf_filesize(const char *name);
70#define mr_conf_error_msg(x, y) {mr_conf_error_msg_int(x, y, __LINE__,__FILE__);}
71static void mr_conf_error_msg_int(int error_code, const char *add_line, int line, const char *file);
72static void mr_conf_remove_comments(void);
73static int mr_conf_check_int_flag(const int flag);
74static void mr_conf_set_int_flag(const int flag);
75static void mr_conf_drop_int_flag(const int flag);
76
77/*global "private" variables*/
78static char *buffer = NULL; /*buffer for configuration file */
79static int internal_flags = 0; /*state of the module */
80static FILE *CONF = NULL; /* Configuration file FD */
81
82/*if output all error and warning messages*/
83static int mr_conf_flags = MRCONF_FLAG_VERBOSE;
84
85/*
86 * Format of the configuration file is as follows:
87 *
88 * attribute1 = int_value
89 * attribute2 = float_value
90 * attribute3 = string_value
91 */
92
93
94/*open and read file: each call must be coupled with mr_conf_close
95 function: return 0 if success*/
96int mr_conf_open(const char *filename) {
97 size_t length; /*length of the buffer/file */
98 size_t res = 0;
99
100 /* check if mr_conf is already opened? */
101 if (mr_conf_check_int_flag(MRCONF_INTFLAG_OPEN)) {
102 mr_conf_error_msg(MRCONF_OPEN_OPENED, NULL);
103 return MRCONF_OPEN_OPENED;
104 }
105
106 length = mr_conf_filesize(filename);
107 CONF = fopen(filename, "r");
108
109 /*if file is empty or not exist => error */
110 if (length == 0) {
111 mr_conf_error_msg(MRCONF_BAD_FILE, filename);
112 return (MRCONF_BAD_FILE);
113 }
114
115 /*creating and reading buffer for file content */
116
117 /*allocate memory for the buffers */
118 buffer = (char *) mr_malloc(sizeof(char) * (length + 1));
119
120 /*set flag that module is in "open" state */
121 mr_conf_set_int_flag(MRCONF_INTFLAG_OPEN);
122
123 /*reading file in buffer (skip all 0 characters) */
124
125 res = fread(buffer, sizeof(char), length, CONF);
126 buffer[length] = (char) 0; /*finalize the string */
127
128 if (ferror(CONF)) {
129 mr_conf_error_msg(MRCONF_READING_FAILED, "");
130 return (MRCONF_READING_FAILED);
131 }
132
133 /* finally we have to remove all comment lines */
134 mr_conf_remove_comments();
135
136 return MRCONF_NO_ERROR;
137}
138
139/*release all memory and prepare to the next possiable config file*/
140void mr_conf_close(void) {
141 /* if not opened => error */
142 if (!mr_conf_check_int_flag(MRCONF_INTFLAG_OPEN)) {
143 mr_conf_error_msg(MRCONF_CLOSE_BUT_NOT_OPEN, NULL);
144 }
145 mr_free(buffer);
146 fclose(CONF);
147
148 /*set flag that module is in "close" state */
149 mr_conf_drop_int_flag(MRCONF_INTFLAG_OPEN);
150}
151
152/*read field value after string str in the current file*/
153static char *mr_conf_read(const char *field_name) {
154 char *p = NULL; /*pointer to the field */
155
156 /* check if mr_conf is not yet opened? */
157 if (!mr_conf_check_int_flag(MRCONF_INTFLAG_OPEN)) {
158 mr_conf_error_msg(MRCONF_CALL_BUT_NOT_OPEN, NULL);
159 return NULL;
160 }
161
162 /*read the number */
163 p = strstr(buffer, field_name);
164 if (p == NULL) {
165 mr_conf_error_msg(MRCONF_FIELD_NOT_FOUND, field_name);
166 return NULL;
167 } else {
168 p += strlen(field_name);
169 while ((*p != '\n') && (*p != '\0') && (*p != '=')) {
170 p++;
171 }
172 if (*p != '=') {
173 mr_conf_error_msg(MRCONF_FIELD_NO_VALUE, field_name);
174 return NULL;
175 } else {
176 /* points after the = sign */
177 p++;
178 }
179 }
180 /* skip initial spaces and tabs after = */
181 while ((*p == ' ') || (*p == '\t')) {
182 p++;
183 }
184
185 return p;
186}
187
188/*read integer number after string str in the current file*/
189int mr_conf_iread(const char *field_name) {
190 char *p = NULL; /*pointer to the field */
191 int ret = 0; /*return value */
192
193 p = mr_conf_read(field_name);
194 if (p != NULL) {
195 ret = atoi(p);
196 }
197 return ret;
198}
199
200/*read float/double number after string str in the current file*/
201double mr_conf_fread(const char *field_name) {
202 char *p = NULL; /*pointer to the field */
203 double ret = 0.0; /*return value */
204
205 p = mr_conf_read(field_name);
206 if (p != NULL) {
207 ret = atof(p);
208 }
209 return ret;
210}
211
212
213/*
214*/
215char *mr_conf_sread(const char *field_name) {
216 char *p = NULL; /*pointer to the field */
217 char *q = NULL; /*pointer to the field */
218 char *r = NULL; /*pointer to the field */
219 char *ret = NULL; /*return value */
220 int size = 0; /*size of returned string */
221 int i = 0;
222
223 ret = NULL;
224
225 p = mr_conf_read(field_name);
226 if (p == NULL) {
227 return(p);
228 }
229 mr_asprintf(&q, p);
230
231 if (*p != '"') {
232 mr_conf_error_msg(MRCONF_STRING_QUOTE, "");
233 return (NULL);
234 }
235 p++;
236
237 /* trunk at first \n */
238 r = index(q,'\n');
239 r--;
240 if (*r != '"') {
241 mr_conf_error_msg(MRCONF_STRING_QUOTE, "");
242 return (NULL);
243 }
244 r--;
245
246 size = r-q+1;
247 /*copy filtered data to the buffer */
248 ret = (char *) mr_malloc(sizeof(char) * (size));
249 while (i < size - 1) {
250 ret[i] = *p;
251 i++;
252 p++;
253 }
254
255 ret[i] = (char) 0; /* and set its length */
256 mr_free(q);
257
258 return ret;
259}
260
261/*read boolean after string str in the current file*/
262bool mr_conf_bread(const char *field_name) {
263 char *p = NULL; /*pointer to the field */
264 bool ret = FALSE;
265
266 p = mr_conf_sread(field_name);
267 if (p != NULL) {
268 /* match if yes/true/1 */
269 if ((strncasecmp(p, "y" , (size_t)1) == 0) ||
270 (strncasecmp(p, "t" , (size_t)1) == 0) ||
271 (strncasecmp(p, "1" , (size_t)1) == 0)) {
272 ret = TRUE;
273 }
274 }
275 return ret;
276}
277
278/*removes all comments from the buffer*/
279static void mr_conf_remove_comments(void) {
280 char *tmp_buf; /*temporary buffer without comments */
281 size_t length /*initial length */ ;
282 size_t i; /*iterator */
283 size_t k; /*conditioned iterator for tmp_buffer */
284 bool found_quote = FALSE;
285 bool found_comment = FALSE;
286
287 length = strlen(buffer);
288
289 /*sizing the new chain */
290 k = 0;
291 i = 0;
292 while (i < length) {
293 /* Handle quotes to detect strings */
294 if ((buffer[i] == '"') && (! found_comment)) {
295 if (found_quote) {
296 found_quote = FALSE;
297 } else {
298 found_quote = TRUE;
299 }
300 }
301 /* Handle start of comment - only when not in a string */
302 if (buffer[i] == MRCONF_COMM_CHAR) {
303 if (found_quote) {
304 found_comment = FALSE;
305 } else {
306 found_comment = TRUE;
307 }
308 }
309 /* Comments end with EOL */
310 if (buffer[i] == '\n') {
311 found_comment = FALSE;
312 }
313 if (! found_comment) {
314 k++;
315 i++;
316 } else {
317 /* Skip comment */
318 while ((buffer[i] != '\n') && (buffer[i] != (char) 0)) {
319 i++;
320 }
321 if (buffer[i] == (char) 0) {
322 mr_conf_error_msg(MRCONF_STRING_ENDQUOTE, "");
323 }
324 }
325 }
326 /* k is new buffer length now */
327 tmp_buf = (char *) mr_malloc(sizeof(char) * (k + 1));
328
329 k = 0;
330 i = 0;
331 while (i < length) {
332 if (buffer[i] == '"') {
333 if (found_quote) {
334 found_quote = FALSE;
335 } else {
336 found_quote = TRUE;
337 }
338 }
339 if ((buffer[i] != MRCONF_COMM_CHAR) || (found_quote)) {
340 tmp_buf[k++] = buffer[i++];
341 } else {
342 /* Skip comment as it's not inside a string */
343 while ((buffer[i] != '\n') && (buffer[i] != (char) 0)) {
344 i++;
345 }
346 }
347 }
348 tmp_buf[k] = (char) 0; /*and set its length */
349
350 mr_free(buffer);
351 /*copy filtered data to the buffer */
352 buffer = tmp_buf;
353}
354
355static int mr_conf_check_int_flag(const int flag) {
356 return (flag & internal_flags);
357}
358
359static void mr_conf_set_int_flag(const int flag) {
360 internal_flags = flag | internal_flags;
361}
362
363static void mr_conf_drop_int_flag(const int flag) {
364 internal_flags = (~flag) & internal_flags;
365}
366
367
368/*local function to define size of a file. Return 0 for mistake*/
369static size_t mr_conf_filesize(const char *name) {
370 FILE *F = fopen(name, "r"); /*file to open */
371 size_t length; /*number to return */
372
373 if (F == NULL) {
374 return 0;
375 }
376
377 fseek(F, 0, SEEK_END); /*set position to the end of file */
378 length = ftell(F); /*define number of position=> this is its
379 length */
380 fclose(F);
381
382 return length;
383}
384
385/*output error message*/
386static void mr_conf_error_msg_int(int error_code, const char *add_line, int line, const char *file) {
387 if ((mr_conf_flags & MRCONF_FLAG_VERBOSE)) { /*if verbose mode */
388 switch (error_code) {
389 case MRCONF_BAD_FILE:
390 mr_msg_int(1,line,file,"%s %s %s\n", MRCONF_STR_ERROR, MRCONF_STR_BAD_FILE,
391 add_line);
392 break;
393
394 case MRCONF_READING_FAILED:
395 mr_msg_int(1,line,file,"%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_READING_FAILED);
396 break;
397
398 case MRCONF_FIELD_NOT_FOUND:
399 mr_msg_int(1,line,file,"%s %s \"%s\"\n", MRCONF_STR_ERROR, MRCONF_STR_FIELD_NOT_FOUND, add_line);
400 mr_msg_int(1,line,file,"%s %s\n", MRCONF_STR_WARNING, MRCONF_STR_SET_TO_ZERO);
401 break;
402
403 case MRCONF_FIELD_NO_VALUE:
404 mr_msg_int(1,line,file,"%s %s \"%s\"\n", MRCONF_STR_ERROR, MRCONF_STR_FIELD_NO_VALUE, add_line);
405 mr_msg_int(1,line,file,"%s %s\n", MRCONF_STR_WARNING, MRCONF_STR_IGNORE);
406 break;
407
408 case MRCONF_CLOSE_BUT_NOT_OPEN:
409 mr_msg_int(1,line,file,"%s %s\n", MRCONF_STR_WARNING, MRCONF_STR_CLOSE_BUT_NOT_OPEN);
410 break;
411
412 case MRCONF_CALL_BUT_NOT_OPEN:
413 mr_msg_int(1,line,file,"%s %s\n", MRCONF_STR_WARNING, MRCONF_STR_CALL_BUT_NOT_OPEN);
414 break;
415
416 case MRCONF_OPEN_OPENED:
417 mr_msg_int(1,line,file,"%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_OPEN_OPENED);
418 break;
419
420 case MRCONF_STRING_QUOTE:
421 mr_msg_int(1,line,file,"%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_STRING_QUOTE);
422 break;
423
424 case MRCONF_STRING_ENDQUOTE:
425 mr_msg_int(1,line,file,"%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_STRING_ENDQUOTE);
426 break;
427
428 default:
429 mr_msg_int(1,line,file,"%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_DEFAULT_ERROR);
430 break;
431 }
432 }
433}
Note: See TracBrowser for help on using the repository browser.