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

Last change on this file since 1064 was 1064, checked in by bruno, 12 years ago

More controls at the compiler level
still working with the problems around variable arguments

  • 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(void);
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(void) {
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.