source: trunk/mondo/src/lib/mr_conf.c @ 979

Last change on this file since 979 was 900, checked in by Bruno Cornec, 14 years ago

Huge patch to introduce low level functions that will bw used everywhere (mr_free, mr_asprintf, ...)
Nearly linking now due to that.

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