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

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