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

Last change on this file since 1054 was 1054, checked in by Bruno Cornec, 17 years ago
  • Backporting more trunk content into stable
  • Adding the test and lib directories
  • Preparing for l10n
  • Property svn:eol-style set to native
File size: 10.2 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#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);
70static void mr_conf_remove_comments();
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*/
143void mr_conf_close() {
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.