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

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

Typo

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