source: trunk/mondo/mondo/lib/mrconf.c @ 767

Last change on this file since 767 was 767, checked in by bruno, 13 years ago

Creating a new library common for all mondo binaries
This should become the only common library when we now which functions should go there

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