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

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

Fix the function process_the_s_switch
Still improving conf file handling

  • Property svn:eol-style set to native
File size: 11.4 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_types.h"
20#include "mr_msg.h"
21#include "mr_mem.h"
22#include "mr_gettext.h"
23
24/* error flags */
25#define MRCONF_NO_ERROR             0x0
26#define MRCONF_BAD_FILE             0x1
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#define MRCONF_STR_STRING_ENDQUOTE      _("a string is not finished by a quote")
61
62/*Flags of internal state*/
63#define MRCONF_INTFLAG_OPEN 0x1 /*set if memory allocated */
64
65/* Character for comments */
66#define MRCONF_COMM_CHAR '#'
67
68/*"private" members declarations*/
69static size_t mr_conf_filesize(const char *name);
70#define mr_conf_error_msg(x, y) {mr_conf_error_msg_int(x, y, __LINE__,__FILE__);}
71static void mr_conf_error_msg_int(int error_code, const char *add_line, int line, const char *file);
72static void mr_conf_remove_comments(void);
73static int mr_conf_check_int_flag(const int flag);
74static void mr_conf_set_int_flag(const int flag);
75static void mr_conf_drop_int_flag(const int flag);
76
77/*global "private" variables*/
78static char *buffer = NULL;     /*buffer for configuration file */
79static int internal_flags = 0;  /*state of the module */
80static FILE *CONF = NULL;       /* Configuration file FD */
81
82/*if output all error and warning messages*/
83static int mr_conf_flags = MRCONF_FLAG_VERBOSE;
84
85/*
86 * Format of the configuration file is as follows:
87 *
88 * attribute1 = int_value
89 * attribute2 = float_value
90 * attribute3 = string_value
91 */
92
93
94/*open and read file: each call must be coupled with mr_conf_close
95  function: return 0 if success*/
96int mr_conf_open(const char *filename) {
97    size_t length;              /*length of the buffer/file */
98    size_t res = 0;
99
100    /* check if mr_conf is already opened? */
101    if (mr_conf_check_int_flag(MRCONF_INTFLAG_OPEN)) {
102        mr_conf_error_msg(MRCONF_OPEN_OPENED, NULL);
103        return MRCONF_OPEN_OPENED;
104    }
105
106    length = mr_conf_filesize(filename);
107    CONF = fopen(filename, "r");
108
109    /*if file is empty or not exist => error */
110    if (length == 0) {
111        mr_conf_error_msg(MRCONF_BAD_FILE, filename);
112        return (MRCONF_BAD_FILE);
113    }
114
115    /*creating and reading buffer for file content */
116
117    /*allocate memory for the buffers */
118    buffer = (char *) mr_malloc(sizeof(char) * (length + 1));
119
120    /*set flag that module is in "open" state */
121    mr_conf_set_int_flag(MRCONF_INTFLAG_OPEN);
122
123    /*reading file in buffer (skip all 0 characters) */
124
125    res = fread(buffer, sizeof(char), length, CONF);
126    buffer[length] = (char) 0;  /*finalize the string */
127
128    if (ferror(CONF)) {
129        mr_conf_error_msg(MRCONF_READING_FAILED, "");
130        return (MRCONF_READING_FAILED);
131    }
132
133    /* finally we have to remove all comment lines */
134    mr_conf_remove_comments();
135
136    return MRCONF_NO_ERROR;
137}
138
139/*release all memory and prepare to the next possiable config file*/
140void mr_conf_close(void) {
141    /* if not opened => error */
142    if (!mr_conf_check_int_flag(MRCONF_INTFLAG_OPEN)) {
143        mr_conf_error_msg(MRCONF_CLOSE_BUT_NOT_OPEN, NULL);
144    }
145    mr_free(buffer);
146    fclose(CONF);
147
148    /*set flag that module is in "close" state */
149    mr_conf_drop_int_flag(MRCONF_INTFLAG_OPEN);
150}
151
152/*read field value after string str in the current file*/
153static char *mr_conf_read(const char *field_name) {
154    char *p = NULL;             /*pointer to the field */
155
156    /* check if mr_conf is not yet opened? */
157    if (!mr_conf_check_int_flag(MRCONF_INTFLAG_OPEN)) {
158        mr_conf_error_msg(MRCONF_CALL_BUT_NOT_OPEN, NULL);
159        return NULL;
160    }
161
162    /*read the number */
163    p = strstr(buffer, field_name);
164    if (p == NULL) {
165        mr_conf_error_msg(MRCONF_FIELD_NOT_FOUND, field_name);
166        return NULL;
167    } else {
168        p += strlen(field_name);
169        while ((*p != '\n') && (*p != '\0') && (*p != '=')) {
170                p++;
171        }
172        if (*p != '=') {
173            mr_conf_error_msg(MRCONF_FIELD_NO_VALUE, field_name);
174            return NULL;
175        } else {
176            /* points after the = sign */
177            p++;
178        }
179    }
180    /* skip initial spaces and tabs after = */
181    while ((*p == ' ') || (*p == '\t')) {
182            p++;
183    }
184
185    return p;
186}
187
188/*read integer number after string str in the current file*/
189int mr_conf_iread(const char *field_name) {
190    char *p = NULL;             /*pointer to the field */
191    int ret = 0;                /*return value */
192
193    p = mr_conf_read(field_name);
194    if (p != NULL) {
195        ret = atoi(p);
196        }
197    return ret;
198}
199
200/*read float/double number after string str in the current file*/
201double mr_conf_fread(const char *field_name) {
202    char *p = NULL;             /*pointer to the field */
203    double ret = 0.0;               /*return value */
204
205    p = mr_conf_read(field_name);
206    if (p != NULL) {
207        ret = atof(p);
208    }
209    return ret;
210}
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    if (*p != '"') {
236        mr_conf_error_msg(MRCONF_STRING_QUOTE, "");
237        return (NULL);
238    }
239    p++;
240
241    /* trunk at first \n */
242    r = index(q,'\n');
243    r--;
244    if (*r != '"') {
245        mr_conf_error_msg(MRCONF_STRING_QUOTE, "");
246        return (NULL);
247    }
248    r--;
249
250    size = r-q+1;
251    /*copy filtered data to the buffer */
252    ret = (char *) mr_malloc(sizeof(char) * (size));
253    while (i < size - 1) {
254        ret[i] = *p;
255        i++;
256        p++;
257    }
258
259    ret[i] = (char) 0;      /* and set its length */
260    mr_free(q);
261
262    return ret;
263}
264
265/*read boolean after string str in the current file*/
266bool mr_conf_bread(const char *field_name) {
267    char *p = NULL;             /*pointer to the field */
268    bool ret = FALSE;
269   
270    p = mr_conf_sread(field_name);
271    if (p != NULL) {
272        /* match if yes/true/1 */
273        if ((strncasecmp(p, "y" , (size_t)1) == 0) ||
274            (strncasecmp(p, "t" , (size_t)1) == 0) ||
275            (strncasecmp(p, "1" , (size_t)1) == 0)) {
276            ret = TRUE;
277        }
278    }
279    return ret;
280}
281
282/*removes all comments from the buffer*/
283static void mr_conf_remove_comments(void) {
284    char *tmp_buf;              /*temporary buffer without comments */
285    size_t length               /*initial length */ ;
286    size_t i;                   /*iterator */
287    size_t k;                   /*conditioned iterator for tmp_buffer */
288    bool found_quote = FALSE;
289    bool found_comment = FALSE;
290
291    length = strlen(buffer);
292
293    /*sizing the new chain */
294    k = 0;
295    i = 0;
296    while (i < length) {
297        /* Handle quotes to detect strings */
298        if ((buffer[i] == '"') && (! found_comment)) {
299            if (found_quote) {
300                found_quote = FALSE;
301            } else {
302                found_quote = TRUE;
303            }
304        }
305        /* Handle start of comment - only when not in a string */
306        if (buffer[i] == MRCONF_COMM_CHAR) {
307            if (found_quote) {
308                found_comment = FALSE;
309            } else {
310                found_comment = TRUE;
311            }
312        }
313        /* Comments end with EOL */
314        if (buffer[i] == '\n') {
315            found_comment = FALSE;
316        }
317        if (! found_comment) {
318            k++;
319            i++;
320        } else {
321            /* Skip comment */
322            while ((buffer[i] != '\n') && (buffer[i] != (char) 0)) {
323                i++;
324            }
325            if (buffer[i] == (char) 0) {
326                mr_conf_error_msg(MRCONF_STR_STRING_ENDQUOTE, "");
327            }
328        }
329    }
330    /* k is new buffer length now */
331    tmp_buf = (char *) mr_malloc(sizeof(char) * (k + 1));
332
333    k = 0;
334    i = 0;
335    while (i < length) {
336        if (buffer[i] == '"') {
337            if (found_quote) {
338                found_quote = FALSE;
339            } else {
340                found_quote = TRUE;
341            }
342        }
343        if ((buffer[i] != MRCONF_COMM_CHAR) || (found_quote)) {
344            tmp_buf[k++] = buffer[i++];
345        } else {
346            /* Skip comment as it's not inside a string */
347            while ((buffer[i] != '\n') && (buffer[i] != (char) 0)) {
348                i++;
349            }
350        }
351    }
352    tmp_buf[k] = (char) 0;      /*and set its length */
353
354    mr_free(buffer);
355    /*copy filtered data to the buffer */
356    buffer = tmp_buf;
357}
358
359static int mr_conf_check_int_flag(const int flag) {
360    return (flag & internal_flags);
361}
362
363static void mr_conf_set_int_flag(const int flag) {
364    internal_flags = flag | internal_flags;
365}
366
367static void mr_conf_drop_int_flag(const int flag) {
368    internal_flags = (~flag) & internal_flags;
369}
370
371
372/*local function to define size of a file. Return 0 for mistake*/
373static size_t mr_conf_filesize(const char *name) {
374    FILE *F = fopen(name, "r"); /*file to open */
375    size_t length;              /*number to return */
376
377    if (F == NULL) {
378        return 0;
379    }
380
381    fseek(F, 0, SEEK_END);      /*set position to the end of file */
382    length = ftell(F);          /*define number of position=> this is its
383                                   length */
384    fclose(F);
385
386    return length;
387}
388
389/*output error message*/
390static void mr_conf_error_msg_int(int error_code, const char *add_line, int line, const char *file) {
391    if ((mr_conf_flags & MRCONF_FLAG_VERBOSE)) {    /*if verbose mode */
392        switch (error_code) {
393        case MRCONF_BAD_FILE:
394            mr_msg_int(1,line,file,"%s %s %s\n", MRCONF_STR_ERROR, MRCONF_STR_BAD_FILE,
395                   add_line);
396            break;
397
398        case MRCONF_READING_FAILED:
399            mr_msg_int(1,line,file,"%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_READING_FAILED);
400            break;
401
402        case MRCONF_FIELD_NOT_FOUND:
403            mr_msg_int(1,line,file,"%s %s \"%s\"\n", MRCONF_STR_ERROR, MRCONF_STR_FIELD_NOT_FOUND, add_line);
404            mr_msg_int(1,line,file,"%s %s\n", MRCONF_STR_WARNING, MRCONF_STR_SET_TO_ZERO);
405            break;
406
407        case MRCONF_FIELD_NO_VALUE:
408            mr_msg_int(1,line,file,"%s %s \"%s\"\n", MRCONF_STR_ERROR, MRCONF_STR_FIELD_NO_VALUE, add_line);
409            mr_msg_int(1,line,file,"%s %s\n", MRCONF_STR_WARNING, MRCONF_STR_IGNORE);
410            break;
411
412        case MRCONF_CLOSE_BUT_NOT_OPEN:
413            mr_msg_int(1,line,file,"%s %s\n", MRCONF_STR_WARNING, MRCONF_STR_CLOSE_BUT_NOT_OPEN);
414            break;
415
416        case MRCONF_CALL_BUT_NOT_OPEN:
417            mr_msg_int(1,line,file,"%s %s\n", MRCONF_STR_WARNING, MRCONF_STR_CALL_BUT_NOT_OPEN);
418            break;
419
420        case MRCONF_OPEN_OPENED:
421            mr_msg_int(1,line,file,"%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_OPEN_OPENED);
422            break;
423
424        case MRCONF_STRING_QUOTE:
425            mr_msg_int(1,line,file,"%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_STRING_QUOTE);
426            break;
427
428        default:
429            mr_msg_int(1,line,file,"%s %s\n", MRCONF_STR_ERROR, MRCONF_STR_DEFAULT_ERROR);
430            break;
431        }
432    }
433}
Note: See TracBrowser for help on using the repository browser.