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

Last change on this file since 1054 was 1054, checked in by bruno, 12 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.