source: MondoRescue/trunk/mondo/src/lib/mr_conf.c@ 900

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

Huge patch to introduce low level functions that will bw used everywhere (mr_free, mr_asprintf, ...)
Nearly linking now due to that.

File size: 9.8 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_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
37/*setting flags*/
38#define MRCONF_FLAG_VERBOSE 0x1
39
40/*All strings of the library are here*/
41#define MRCONF_STR_ERROR _("MRCONF: Error:")
42#define MRCONF_STR_WARNING _("MRCONF: Warning:")
43
44#define MRCONF_STR_BAD_FILE _("cannot open the file: ")
45#define MRCONF_STR_ALLOC_FAILED _("cannot allocate the memory")
46#define MRCONF_STR_READING_FAILED _("cannot read file into buffer")
47#define MRCONF_STR_DEFAULT_ERROR _("default")
48#define MRCONF_STR_FIELD_NOT_FOUND _("the field is not found, field:")
49#define MRCONF_STR_FIELD_NO_VALUE _("the field :")
50#define MRCONF_STR_OPEN_OPENED _("attempt to open mr_conf, but it is opened: aborted")
51#define MRCONF_STR_HALT _("MRCONF: Error occured: immidiate halt")
52
53/*warnings*/
54#define MRCONF_STR_SET_TO_ZERO _("variable will be set to 0")
55#define MRCONF_STR_IGNORE _("has no value, ignoring it")
56#define MRCONF_STR_CLOSE_BUT_NOT_OPEN _("attempt to close mr_conf but it has not been opened yet")
57#define MRCONF_STR_CALL_BUT_NOT_OPEN _("attempt to use mr_conf when it has not been opened yet")
58
59/*Flags of internal state*/
60#define MRCONF_INTFLAG_OPEN 0x1 /*set if memory allocated */
61
62/* Character for comments */
63#define MRCONF_COMM_CHAR '#'
64
65/*"private" members declarations*/
66static size_t mr_conf_filesize(const char *name);
67static void mr_conf_error_msg(int error_code, const char *add_line);
68static void mr_conf_remove_comments();
69static int mr_conf_check_int_flag(const int flag);
70static void mr_conf_set_int_flag(const int flag);
71static void mr_conf_drop_int_flag(const int flag);
72
73/*global "private" variables*/
74static char *buffer = NULL; /*buffer for configuration file */
75static int internal_flags = 0; /*state of the module */
76static FILE *CONF = NULL; /* Configuration file FD */
77
78/*if output all error and warning messages*/
79static int mr_conf_flags = MRCONF_FLAG_VERBOSE;
80
81/*
82 * Format of the configuration file is as follows:
83 *
84 * attribute1 = int_value
85 * attribute2 = float_value
86 * attribute3 = string_value
87 */
88
89
90/*open and read file: each call must be coupled with mr_conf_close
91 function: return 0 if success*/
92int mr_conf_open(const char *filename) {
93 size_t length; /*length of the buffer/file */
94 size_t res = 0;
95
96 /* check if mr_conf is already opened? */
97 if (mr_conf_check_int_flag(MRCONF_INTFLAG_OPEN)) {
98 mr_conf_error_msg(MRCONF_OPEN_OPENED, NULL);
99 return MRCONF_OPEN_OPENED;
100 }
101
102 length = mr_conf_filesize(filename);
103 CONF = fopen(filename, "r");
104
105 /*if file is empty or not exist => error */
106 if (length == 0) {
107 mr_conf_error_msg(MRCONF_BAD_FILE, filename);
108 return (MRCONF_BAD_FILE);
109 }
110
111 /*creating and reading buffer for file content */
112
113 /*allocate memory for the buffers */
114 buffer = (char *) malloc(sizeof(char) * (length + 1));
115
116 if (buffer == NULL) {
117 mr_conf_error_msg(MRCONF_ALLOC_FAILED, "");
118 return (MRCONF_ALLOC_FAILED);
119 }
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() {
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 reads string outstr after string str in the current file (between
215 "..."), not more than maxlength symbols: cannot check if outstr has
216 enough length! It must be at least maxlength+1 ! Returns number of
217 read chars
218*/
219char *mr_conf_sread(const char *field_name) {
220 char *p = NULL; /*pointer to the field */
221 char *q = NULL; /*pointer to the field */
222 char *r = NULL; /*pointer to the field */
223 char *ret = NULL; /*return value */
224 int size = 0; /*size of returned string */
225 int i = 0;
226
227 ret = NULL;
228
229 p = mr_conf_read(field_name);
230 if (p == NULL) {
231 return(p);
232 }
233 mr_asprintf(&q, p);
234
235 /* trunk at first \n */
236 r = index(q,'\n');
237
238 size = r-q+1;
239 /*copy filtered data to the buffer */
240 ret = (char *) malloc(sizeof(char) * (size));
241 if (ret == NULL) {
242 mr_conf_error_msg(MRCONF_ALLOC_FAILED, "");
243 return (NULL);
244 }
245 while (i < size - 1) {
246 ret[i] = *p;
247 i++;
248 p++;
249 }
250
251 ret[i] = (char) 0; /*and set its length */
252 mr_free(q);
253
254 return ret;
255}
256
257/*removes all comments from the buffer*/
258static void mr_conf_remove_comments() {
259 char *tmp_buf; /*temporary buffer without comments */
260 size_t length /*initial length */ ;
261 size_t i; /*iterator */
262 size_t k; /*conditioned iterator for tmp_buffer */
263
264 length = strlen(buffer);
265
266 /*sizing the new chain */
267 k = 0;
268 i = 0;
269 while (i < length) {
270 if (buffer[i] != MRCONF_COMM_CHAR) {
271 k++;
272 i++;
273 } else {
274 while ((buffer[i] != '\n') && (buffer[i] != (char) 0)) {
275 i++;
276 }
277 }
278 }
279 /* k is new buffer length now */
280 tmp_buf = (char *) malloc(sizeof(char) * (k + 1));
281 if (tmp_buf == NULL) {
282 mr_conf_error_msg(MRCONF_ALLOC_FAILED, "");
283 return;
284 }
285
286 k = 0;
287 i = 0;
288 while (i < length) {
289 if (buffer[i] != MRCONF_COMM_CHAR) {
290 tmp_buf[k++] = buffer[i++];
291 } else {
292 while ((buffer[i] != '\n') && (buffer[i] != (char) 0)) {
293 i++;
294 }
295 }
296 }
297 tmp_buf[k] = (char) 0; /*and set its length */
298
299 mr_free(buffer);
300 /*copy filtered data to the buffer */
301 buffer = tmp_buf;
302}
303
304static int mr_conf_check_int_flag(const int flag) {
305 return (flag & internal_flags);
306}
307
308static void mr_conf_set_int_flag(const int flag) {
309 internal_flags = flag | internal_flags;
310}
311
312static void mr_conf_drop_int_flag(const int flag) {
313 internal_flags = (~flag) & internal_flags;
314}
315
316
317/*local function to define size of a file. Return 0 for mistake*/
318static size_t mr_conf_filesize(const char *name) {
319 FILE *F = fopen(name, "r"); /*file to open */
320 size_t length; /*number to return */
321
322 if (F == NULL) {
323 return 0;
324 }
325
326 fseek(F, 0, SEEK_END); /*set position to the end of file */
327 length = ftell(F); /*define number of position=> this is its
328 length */
329 fclose(F);
330
331 return length;
332}
333
334/*output error message*/
335static void mr_conf_error_msg(int error_code, const char *add_line) {
336 if ((mr_conf_flags & MRCONF_FLAG_VERBOSE)) { /*if verbose mode */
337 switch (error_code) {
338 case MRCONF_BAD_FILE:
339 mr_msg(0,"%s %s %s\n", MRCONF_STR_ERROR, MRCONF_STR_BAD_FILE,
340 add_line);
341 break;
342
343 case MRCONF_ALLOC_FAILED:
344 mr_msg(0,"%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_ALLOC_FAILED);
345 break;
346
347 case MRCONF_READING_FAILED:
348 mr_msg(0,"%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_READING_FAILED);
349 break;
350
351 case MRCONF_FIELD_NOT_FOUND:
352 mr_msg(1,"%s %s \"%s\"\n", MRCONF_STR_ERROR, MRCONF_STR_FIELD_NOT_FOUND, add_line);
353 mr_msg(1,"%s %s\n", MRCONF_STR_WARNING, MRCONF_STR_SET_TO_ZERO);
354 break;
355
356 case MRCONF_FIELD_NO_VALUE:
357 mr_msg(1,"%s %s \"%s\"\n", MRCONF_STR_ERROR, MRCONF_STR_FIELD_NO_VALUE, add_line);
358 mr_msg(1,"%s %s\n", MRCONF_STR_WARNING, MRCONF_STR_IGNORE);
359 break;
360
361 case MRCONF_CLOSE_BUT_NOT_OPEN:
362 mr_msg(0,"%s %s\n", MRCONF_STR_WARNING, MRCONF_STR_CLOSE_BUT_NOT_OPEN);
363 break;
364
365 case MRCONF_CALL_BUT_NOT_OPEN:
366 mr_msg(0,"%s %s\n", MRCONF_STR_WARNING, MRCONF_STR_CALL_BUT_NOT_OPEN);
367 break;
368
369 case MRCONF_OPEN_OPENED:
370 mr_msg(0,"%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_OPEN_OPENED);
371 break;
372
373 default:
374 mr_msg(1,"%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_DEFAULT_ERROR);
375 break;
376 }
377 }
378}
Note: See TracBrowser for help on using the repository browser.