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

Last change on this file since 1256 was 1256, checked in by Bruno Cornec, 13 years ago

Begining of work on conf file introduction in mondo

  • create a new struct mr_ar_conf to store conf info
  • adds a static mr_ar_store_conf function to store conf file info in that struc
  • mondo.conf is now the .dist version
  • md5 not done yet

Not tested may not work at all nor compile

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