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

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

More controls at the compiler level
still working with the problems around variable arguments

  • Property svn:eol-style set to native
File size: 10.2 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
19#include "mr_msg.h"
20#include "mr_mem.h"
21#include "mr_gettext.h"
22
23/* error flags */
24#define MRCONF_NO_ERROR 0x0
25#define MRCONF_BAD_FILE 0x1
26#define MRCONF_ALLOC_FAILED 0x2
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);
69static void mr_conf_error_msg(int error_code, const char *add_line);
[1064]70static void mr_conf_remove_comments(void);
[1054]71static int mr_conf_check_int_flag(const int flag);
72static void mr_conf_set_int_flag(const int flag);
73static void mr_conf_drop_int_flag(const int flag);
74
75/*global "private" variables*/
76static char *buffer = NULL; /*buffer for configuration file */
77static int internal_flags = 0; /*state of the module */
78static FILE *CONF = NULL; /* Configuration file FD */
79
80/*if output all error and warning messages*/
81static int mr_conf_flags = MRCONF_FLAG_VERBOSE;
82
83/*
84 * Format of the configuration file is as follows:
85 *
86 * attribute1 = int_value
87 * attribute2 = float_value
88 * attribute3 = string_value
89 */
90
91
92/*open and read file: each call must be coupled with mr_conf_close
93 function: return 0 if success*/
94int mr_conf_open(const char *filename) {
95 size_t length; /*length of the buffer/file */
96 size_t res = 0;
97
98 /* check if mr_conf is already opened? */
99 if (mr_conf_check_int_flag(MRCONF_INTFLAG_OPEN)) {
100 mr_conf_error_msg(MRCONF_OPEN_OPENED, NULL);
101 return MRCONF_OPEN_OPENED;
102 }
103
104 length = mr_conf_filesize(filename);
105 CONF = fopen(filename, "r");
106
107 /*if file is empty or not exist => error */
108 if (length == 0) {
109 mr_conf_error_msg(MRCONF_BAD_FILE, filename);
110 return (MRCONF_BAD_FILE);
111 }
112
113 /*creating and reading buffer for file content */
114
115 /*allocate memory for the buffers */
116 buffer = (char *) mr_malloc(sizeof(char) * (length + 1));
117
118 if (buffer == NULL) {
119 mr_conf_error_msg(MRCONF_ALLOC_FAILED, "");
120 return (MRCONF_ALLOC_FAILED);
121 }
122
123 /*set flag that module is in "open" state */
124 mr_conf_set_int_flag(MRCONF_INTFLAG_OPEN);
125
126 /*reading file in buffer (skip all 0 characters) */
127
128 res = fread(buffer, sizeof(char), length, CONF);
129 buffer[length] = (char) 0; /*finalize the string */
130
131 if (ferror(CONF)) {
132 mr_conf_error_msg(MRCONF_READING_FAILED, "");
133 return (MRCONF_READING_FAILED);
134 }
135
136 /* finally we have to remove all comment lines */
137 mr_conf_remove_comments();
138
139 return MRCONF_NO_ERROR;
140}
141
142/*release all memory and prepare to the next possiable config file*/
[1064]143void mr_conf_close(void) {
[1054]144 /* if not opened => error */
145 if (!mr_conf_check_int_flag(MRCONF_INTFLAG_OPEN)) {
146 mr_conf_error_msg(MRCONF_CLOSE_BUT_NOT_OPEN, NULL);
147 }
148 mr_free(buffer);
149 fclose(CONF);
150
151 /*set flag that module is in "close" state */
152 mr_conf_drop_int_flag(MRCONF_INTFLAG_OPEN);
153}
154
155/*read field value after string str in the current file*/
156static char *mr_conf_read(const char *field_name) {
157 char *p = NULL; /*pointer to the field */
158
159 /* check if mr_conf is not yet opened? */
160 if (!mr_conf_check_int_flag(MRCONF_INTFLAG_OPEN)) {
161 mr_conf_error_msg(MRCONF_CALL_BUT_NOT_OPEN, NULL);
162 return NULL;
163 }
164
165 /*read the number */
166 p = strstr(buffer, field_name);
167 if (p == NULL) {
168 mr_conf_error_msg(MRCONF_FIELD_NOT_FOUND, field_name);
169 return NULL;
170 } else {
171 p += strlen(field_name);
172 while ((*p != '\n') && (*p != '\0') && (*p != '=')) {
173 p++;
174 }
175 if (*p != '=') {
176 mr_conf_error_msg(MRCONF_FIELD_NO_VALUE, field_name);
177 return NULL;
178 } else {
179 /* points after the = sign */
180 p++;
181 }
182 }
183 /* skip initial spaces and tabs after = */
184 while ((*p == ' ') || (*p == '\t')) {
185 p++;
186 }
187
188 return p;
189}
190
191/*read integer number after string str in the current file*/
192int mr_conf_iread(const char *field_name) {
193 char *p = NULL; /*pointer to the field */
194 int ret = 0; /*return value */
195
196 p = mr_conf_read(field_name);
197 if (p != NULL) {
198 ret = atoi(p);
199 }
200 return ret;
201}
202
203/*read float/double number after string str in the current file*/
204double mr_conf_fread(const char *field_name) {
205 char *p = NULL; /*pointer to the field */
206 double ret = 0.0; /*return value */
207
208 p = mr_conf_read(field_name);
209 if (p != NULL) {
210 ret = atof(p);
211 }
212 return ret;
213}
214
215/*
216 reads string outstr after string str in the current file (between
217 "..."), not more than maxlength symbols: cannot check if outstr has
218 enough length! It must be at least maxlength+1 ! Returns number of
219 read chars
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 != '"') {
238 mr_conf_error_msg(MRCONF_STRING_QUOTE, "");
239 return (NULL);
240 }
241 p++;
242
243 /* trunk at first \n */
244 r = index(q,'\n');
245 r--;
246 if (*r != '"') {
247 mr_conf_error_msg(MRCONF_STRING_QUOTE, "");
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 if (ret == NULL) {
256 mr_conf_error_msg(MRCONF_ALLOC_FAILED, "");
257 return (NULL);
258 }
259 while (i < size - 1) {
260 ret[i] = *p;
261 i++;
262 p++;
263 }
264
265 ret[i] = (char) 0; /* and set its length */
266 mr_free(q);
267
268 return ret;
269}
270
271/*removes all comments from the buffer*/
272static void mr_conf_remove_comments() {
273 char *tmp_buf; /*temporary buffer without comments */
274 size_t length /*initial length */ ;
275 size_t i; /*iterator */
276 size_t k; /*conditioned iterator for tmp_buffer */
277
278 length = strlen(buffer);
279
280 /*sizing the new chain */
281 k = 0;
282 i = 0;
283 while (i < length) {
284 if (buffer[i] != MRCONF_COMM_CHAR) {
285 k++;
286 i++;
287 } else {
288 while ((buffer[i] != '\n') && (buffer[i] != (char) 0)) {
289 i++;
290 }
291 }
292 }
293 /* k is new buffer length now */
294 tmp_buf = (char *) mr_malloc(sizeof(char) * (k + 1));
295 if (tmp_buf == NULL) {
296 mr_conf_error_msg(MRCONF_ALLOC_FAILED, "");
297 return;
298 }
299
300 k = 0;
301 i = 0;
302 while (i < length) {
303 if (buffer[i] != MRCONF_COMM_CHAR) {
304 tmp_buf[k++] = buffer[i++];
305 } else {
306 while ((buffer[i] != '\n') && (buffer[i] != (char) 0)) {
307 i++;
308 }
309 }
310 }
311 tmp_buf[k] = (char) 0; /*and set its length */
312
313 mr_free(buffer);
314 /*copy filtered data to the buffer */
315 buffer = tmp_buf;
316}
317
318static int mr_conf_check_int_flag(const int flag) {
319 return (flag & internal_flags);
320}
321
322static void mr_conf_set_int_flag(const int flag) {
323 internal_flags = flag | internal_flags;
324}
325
326static void mr_conf_drop_int_flag(const int flag) {
327 internal_flags = (~flag) & internal_flags;
328}
329
330
331/*local function to define size of a file. Return 0 for mistake*/
332static size_t mr_conf_filesize(const char *name) {
333 FILE *F = fopen(name, "r"); /*file to open */
334 size_t length; /*number to return */
335
336 if (F == NULL) {
337 return 0;
338 }
339
340 fseek(F, 0, SEEK_END); /*set position to the end of file */
341 length = ftell(F); /*define number of position=> this is its
342 length */
343 fclose(F);
344
345 return length;
346}
347
348/*output error message*/
349static void mr_conf_error_msg(int error_code, const char *add_line) {
350 if ((mr_conf_flags & MRCONF_FLAG_VERBOSE)) { /*if verbose mode */
351 switch (error_code) {
352 case MRCONF_BAD_FILE:
353 mr_msg(0,"%s %s %s\n", MRCONF_STR_ERROR, MRCONF_STR_BAD_FILE,
354 add_line);
355 break;
356
357 case MRCONF_ALLOC_FAILED:
358 mr_msg(0,"%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_ALLOC_FAILED);
359 break;
360
361 case MRCONF_READING_FAILED:
362 mr_msg(0,"%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_READING_FAILED);
363 break;
364
365 case MRCONF_FIELD_NOT_FOUND:
366 mr_msg(1,"%s %s \"%s\"\n", MRCONF_STR_ERROR, MRCONF_STR_FIELD_NOT_FOUND, add_line);
367 mr_msg(1,"%s %s\n", MRCONF_STR_WARNING, MRCONF_STR_SET_TO_ZERO);
368 break;
369
370 case MRCONF_FIELD_NO_VALUE:
371 mr_msg(1,"%s %s \"%s\"\n", MRCONF_STR_ERROR, MRCONF_STR_FIELD_NO_VALUE, add_line);
372 mr_msg(1,"%s %s\n", MRCONF_STR_WARNING, MRCONF_STR_IGNORE);
373 break;
374
375 case MRCONF_CLOSE_BUT_NOT_OPEN:
376 mr_msg(0,"%s %s\n", MRCONF_STR_WARNING, MRCONF_STR_CLOSE_BUT_NOT_OPEN);
377 break;
378
379 case MRCONF_CALL_BUT_NOT_OPEN:
380 mr_msg(0,"%s %s\n", MRCONF_STR_WARNING, MRCONF_STR_CALL_BUT_NOT_OPEN);
381 break;
382
383 case MRCONF_OPEN_OPENED:
384 mr_msg(0,"%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_OPEN_OPENED);
385 break;
386
387 case MRCONF_STRING_QUOTE:
388 mr_msg(0,"%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_STRING_QUOTE);
389 break;
390
391 default:
392 mr_msg(1,"%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_DEFAULT_ERROR);
393 break;
394 }
395 }
396}
Note: See TracBrowser for help on using the repository browser.