source: MondoRescue/branches/stable/mondo/mondo/common/libmondo-conf.c@ 531

Last change on this file since 531 was 531, checked in by bcornec, 18 years ago

Introduction of new functions in mondorescue library to handle the new configuration files developped for mondo/mindi
As well a rudimentary test suite was developped to test these functions
valgrind usage revealed no memory leak.
These 2 methods will be further extended to the rest of mr.

File size: 10.8 KB
Line 
1/* libmondo-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 libmondo-conf (mrconf): a very small and simple
9 * library for configuration file reading
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free
23 * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24 * 02111-1307 USA
25 */
26
27
28#include <stdlib.h>
29#include <stdio.h>
30#include <string.h>
31
32#include "my-stuff.h"
33
34/* error flags */
35#define MRCONF_NO_ERROR 0x0
36#define MRCONF_BAD_FILE 0x1
37#define MRCONF_ALLOC_FAILED 0x2
38#define MRCONF_READING_FAILED 0x3
39#define MRCONF_NO_GROUP_START 0x4
40#define MRCONF_NO_GROUP_END 0x5
41#define MRCONF_FIELD_NOT_FOUND 0x6
42#define MRCONF_FIELD_NO_VALUE 0x7
43#define MRCONF_TOO_LONG_STRING 0x8
44#define MRCONF_CLOSE_BUT_NOT_OPEN 0x9
45#define MRCONF_OPEN_OPENED 0xA
46#define MRCONF_CALL_BUT_NOT_OPEN 0xB
47
48/*setting flags*/
49#define MRCONF_FLAG_VERBOSE 0x1
50#define MRCONF_FLAG_ERROR_EXIT 0x2
51
52/*All strings of the library are here*/
53#define MRCONF_STR_ERROR _("MRCONF: Error:")
54#define MRCONF_STR_WARNING _("MRCONF: Warning:")
55
56#define MRCONF_STR_BAD_FILE _("cannot open the file: ")
57#define MRCONF_STR_ALLOC_FAILED _("cannot allocate the memory")
58#define MRCONF_STR_READING_FAILED _("cannot read file into buffer")
59#define MRCONF_STR_DEFAULT_ERROR _("default")
60#define MRCONF_STR_FIELD_NOT_FOUND _("the field is not found, field:")
61#define MRCONF_STR_FIELD_NO_VALUE _("the field :")
62#define MRCONF_STR_OPEN_OPENED _("attempt to open libmondo-conf, but it is opened: aborted")
63#define MRCONF_STR_HALT _("MRCONF: Error occured: immidiate halt")
64
65/*warnings*/
66#define MRCONF_STR_SET_TO_ZERO _("variable will be set to 0")
67#define MRCONF_STR_IGNORE _("has no value, ignoring it")
68#define MRCONF_STR_CLOSE_BUT_NOT_OPEN _("attempt to close libmondo-conf but it has not been opened yet")
69#define MRCONF_STR_CALL_BUT_NOT_OPEN _("attempt to use libmondo-conf when it has not been opened yet")
70
71/*Flags of internal state*/
72#define MRCONF_INTFLAG_OPEN 0x1 /*set if memory allocated */
73
74/* Character for comments */
75#define MRCONF_COMM_CHAR '#'
76
77/*"private" members declarations*/
78static size_t mrconf_filesize(const char *name);
79static void mrconf_error_msg(int error_code, const char *add_line);
80static void mrconf_remove_comments();
81static int mrconf_check_int_flag(const int flag);
82static void mrconf_set_int_flag(const int flag);
83static void mrconf_drop_int_flag(const int flag);
84
85/*global "private" variables*/
86static char *buffer = NULL; /*buffer for configuration file */
87static int internal_flags = 0; /*state of the module */
88static FILE *CONF = NULL; /* Configuration file FD */
89
90/*if output all error and warnin messages*/
91static int mrconf_flags = MRCONF_FLAG_VERBOSE;
92
93/*
94 * Format of the configuration file is as follows:
95 *
96 * attribute1 = int_value
97 * attribute2 = float_value
98 * attribute3 = string_value
99 */
100
101
102/*open and read file: each call must be coupled with mrconf_close
103 function: return 0 if success*/
104int mrconf_open(const char *filename) {
105 size_t length; /*length of the buffer/file */
106
107 /* check if libmondo-conf is already opened? */
108 if (mrconf_check_int_flag(MRCONF_INTFLAG_OPEN)) {
109 mrconf_error_msg(MRCONF_OPEN_OPENED, NULL);
110 return MRCONF_OPEN_OPENED;
111 }
112
113 length = mrconf_filesize(filename);
114 CONF = fopen(filename, "r");
115
116 /*if file is empty or not exist => error */
117 if (length == 0) {
118 mrconf_error_msg(MRCONF_BAD_FILE, filename);
119 return (MRCONF_BAD_FILE);
120 }
121
122 /*creating and reading buffer for file content */
123
124 /*allocate memory for the buffers */
125 buffer = (char *) malloc(sizeof(char) * (length + 1));
126
127 if (buffer == NULL) {
128 mrconf_error_msg(MRCONF_ALLOC_FAILED, "");
129 return (MRCONF_ALLOC_FAILED);
130 }
131
132 /*set flag that module is in "open" state */
133 mrconf_set_int_flag(MRCONF_INTFLAG_OPEN);
134
135 /*reading file in buffer (skip all 0 characters) */
136
137 (void) fread(buffer, sizeof(char), length, CONF);
138 buffer[length] = (char) 0; /*finalize the string */
139
140 if (ferror(CONF)) {
141 mrconf_error_msg(MRCONF_READING_FAILED, "");
142 return (MRCONF_READING_FAILED);
143 }
144
145 /* finally we have to remove all comment lines */
146 mrconf_remove_comments();
147
148 return MRCONF_NO_ERROR;
149}
150
151/*release all memory and prepare to the next possiable config file*/
152void mrconf_close() {
153 /* if not opened => error */
154 if (!mrconf_check_int_flag(MRCONF_INTFLAG_OPEN)) {
155 mrconf_error_msg(MRCONF_CLOSE_BUT_NOT_OPEN, NULL);
156 }
157 paranoid_free(buffer);
158 fclose(CONF);
159
160 /*set flag that module is in "close" state */
161 mrconf_drop_int_flag(MRCONF_INTFLAG_OPEN);
162}
163
164/*read field value after string str in the current file*/
165static char *mrconf_read(const char *field_name) {
166 char *p = NULL; /*pointer to the field */
167
168 /* check if libmondo-conf is not yet opened? */
169 if (!mrconf_check_int_flag(MRCONF_INTFLAG_OPEN)) {
170 mrconf_error_msg(MRCONF_CALL_BUT_NOT_OPEN, NULL);
171 return NULL;
172 }
173
174 /*read the number */
175 p = strstr(buffer, field_name);
176 if (p == NULL) {
177 mrconf_error_msg(MRCONF_FIELD_NOT_FOUND, field_name);
178 return NULL;
179 } else {
180 p += strlen(field_name);
181 while ((*p != '\n') && (*p != '\0') && (*p != '=')) {
182 p++;
183 }
184 if (*p != '=') {
185 mrconf_error_msg(MRCONF_FIELD_NO_VALUE, field_name);
186 return NULL;
187 } else {
188 /* points after the = sign */
189 p++;
190 }
191 }
192 /* skip initial spaces and tabs after = */
193 while ((*p == ' ') || (*p == '\t')) {
194 p++;
195 }
196
197 return p;
198}
199
200/*read integer number after string str in the current file*/
201int mrconf_iread(const char *field_name) {
202 char *p = NULL; /*pointer to the field */
203 int ret = 0; /*return value */
204
205 p = mrconf_read(field_name);
206 if (p != NULL) {
207 ret = atoi(p);
208 }
209 return ret;
210}
211
212/*read float/double number after string str in the current file*/
213double mrconf_fread(const char *field_name) {
214 char *p = NULL; /*pointer to the field */
215 double ret = 0.0; /*return value */
216
217 p = mrconf_read(field_name);
218 if (p != NULL) {
219 ret = atof(p);
220 }
221 return ret;
222}
223
224/*
225 reads string outstr after string str in the current file (between
226 "..."), not more than maxlength simbols: cannot check if outstr has
227 enough length! It must be at least maxlength+1 ! Returns number of
228 read chars
229*/
230char *mrconf_sread(const char *field_name) {
231 char *p = NULL; /*pointer to the field */
232 char *q = NULL; /*pointer to the field */
233 char *r = NULL; /*pointer to the field */
234 char *ret = NULL; /*return value */
235 int size = 0; /*size of returned string */
236 int i = 0;
237
238 ret = NULL;
239
240 p = mrconf_read(field_name);
241 if (p == NULL) {
242 return(p);
243 }
244 asprintf(&q, p);
245
246 /* trunk at first \n */
247 r = index(q,'\n');
248
249 size = r-q+1;
250 /*copy filtered data to the buffer */
251 ret = (char *) malloc(sizeof(char) * (size));
252 if (ret == NULL) {
253 mrconf_error_msg(MRCONF_ALLOC_FAILED, "");
254 return (NULL);
255 }
256 while (i < size - 1) {
257 ret[i] = *p;
258 i++;
259 p++;
260 }
261
262 ret[i] = (char) 0; /*and set its length */
263 paranoid_free(q);
264
265 return ret;
266}
267
268/*removes all comments from the buffer*/
269static void mrconf_remove_comments() {
270 char *tmp_buf; /*temporary buffer without comments */
271 size_t length /*initial length */ ;
272 size_t i; /*iterator */
273 size_t k; /*conditioned iterator for tmp_buffer */
274
275 length = strlen(buffer);
276
277 /*sizing the new chain */
278 k = 0;
279 i = 0;
280 while (i < length) {
281 if (buffer[i] != MRCONF_COMM_CHAR) {
282 k++;
283 i++;
284 } else {
285 while ((buffer[i] != '\n') && (buffer[i] != (char) 0)) {
286 i++;
287 }
288 }
289 }
290 /* k is new buffer length now */
291 tmp_buf = (char *) malloc(sizeof(char) * (k + 1));
292 if (tmp_buf == NULL) {
293 mrconf_error_msg(MRCONF_ALLOC_FAILED, "");
294 return;
295 }
296
297 k = 0;
298 i = 0;
299 while (i < length) {
300 if (buffer[i] != MRCONF_COMM_CHAR) {
301 tmp_buf[k++] = buffer[i++];
302 } else {
303 while ((buffer[i] != '\n') && (buffer[i] != (char) 0)) {
304 i++;
305 }
306 }
307 }
308 tmp_buf[k] = (char) 0; /*and set its length */
309
310 paranoid_free(buffer);
311 /*copy filtered data to the buffer */
312 buffer = tmp_buf;
313}
314
315static int mrconf_check_int_flag(const int flag) {
316 return (flag & internal_flags);
317}
318
319static void mrconf_set_int_flag(const int flag) {
320 internal_flags = flag | internal_flags;
321}
322
323static void mrconf_drop_int_flag(const int flag) {
324 internal_flags = (~flag) & internal_flags;
325}
326
327
328/*local function to define size of a file. Return 0 for mistake*/
329static size_t mrconf_filesize(const char *name) {
330 FILE *F = fopen(name, "r"); /*file to open */
331 size_t length; /*number to return */
332
333 if (F == NULL) {
334 return 0;
335 }
336
337 fseek(F, 0, SEEK_END); /*set position to the end of file */
338 length = ftell(F); /*define number of position=> this is its
339 length */
340 fclose(F);
341
342 return length;
343}
344
345/*output error message*/
346static void mrconf_error_msg(int error_code, const char *add_line) {
347 if ((mrconf_flags & MRCONF_FLAG_VERBOSE)) { /*if verbose mode */
348 switch (error_code) {
349 case MRCONF_BAD_FILE:
350 log_msg(4, "%s %s %s\n", MRCONF_STR_ERROR, MRCONF_STR_BAD_FILE,
351 add_line);
352 break;
353
354 case MRCONF_ALLOC_FAILED:
355 log_msg(4, "%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_ALLOC_FAILED);
356 break;
357
358 case MRCONF_READING_FAILED:
359 log_msg(4, "%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_READING_FAILED);
360 break;
361
362 case MRCONF_FIELD_NOT_FOUND:
363 log_msg(4, "%s %s \"%s\"\n", MRCONF_STR_ERROR,
364 MRCONF_STR_FIELD_NOT_FOUND, add_line);
365 log_msg(4, "%s %s\n", MRCONF_STR_WARNING, MRCONF_STR_SET_TO_ZERO);
366 break;
367
368 case MRCONF_FIELD_NO_VALUE:
369 log_msg(4, "%s %s \"%s\"\n", MRCONF_STR_ERROR,
370 MRCONF_STR_FIELD_NO_VALUE, add_line);
371 log_msg(4, "%s %s\n", MRCONF_STR_WARNING, MRCONF_STR_IGNORE);
372 break;
373
374 case MRCONF_CLOSE_BUT_NOT_OPEN:
375 log_msg(4, "%s %s\n", MRCONF_STR_WARNING,
376 MRCONF_STR_CLOSE_BUT_NOT_OPEN);
377 break;
378
379 case MRCONF_CALL_BUT_NOT_OPEN:
380 log_msg(4, "%s %s\n", MRCONF_STR_WARNING,
381 MRCONF_STR_CALL_BUT_NOT_OPEN);
382 break;
383
384 case MRCONF_OPEN_OPENED:
385 log_msg(4, "%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_OPEN_OPENED);
386 break;
387
388 default:
389 log_msg(4, "%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_DEFAULT_ERROR);
390 break;
391 }
392 }
393
394 /* if the flag is set to ERROR_EXIT then any error leads to halt */
395 if (mrconf_flags & MRCONF_FLAG_ERROR_EXIT) {
396 if (mrconf_check_int_flag(MRCONF_INTFLAG_OPEN))
397 mrconf_close();
398 log_msg(4, "%s\n", MRCONF_STR_HALT);
399 exit(error_code);
400 }
401}
402
403
Note: See TracBrowser for help on using the repository browser.