source: branches/2.2.10/mondo/src/lib/mr_conf.c @ 2323

Last change on this file since 2323 was 2323, checked in by Bruno Cornec, 11 years ago

r3334@localhost: bruno | 2009-08-08 12:17:37 +0200

  • Change mr_asprintf interface to pass only the char * (makes bkpinfo usage more easy)
  • Property svn:eol-style set to native
File size: 12.0 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#define MRCONF_STRING_ENDQUOTE      0xD
38
39/*setting flags*/
40#define MRCONF_FLAG_VERBOSE         0x1
41
42/*All strings of the library are here*/
43#define MRCONF_STR_ERROR          _("MRCONF: Error:")
44#define MRCONF_STR_WARNING        _("MRCONF: Warning:")
45
46#define MRCONF_STR_BAD_FILE       _("cannot open the file: ")
47#define MRCONF_STR_ALLOC_FAILED   _("cannot allocate the memory")
48#define MRCONF_STR_READING_FAILED _("cannot read file into buffer")
49#define MRCONF_STR_DEFAULT_ERROR  _("default")
50#define MRCONF_STR_FIELD_NOT_FOUND   _("the field is not found, field:")
51#define MRCONF_STR_FIELD_NO_VALUE   _("the field :")
52#define MRCONF_STR_OPEN_OPENED _("attempt to open mr_conf, but it is opened: aborted")
53#define MRCONF_STR_HALT _("MRCONF: Error occured: immidiate halt")
54
55/*warnings*/
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 */
81static char *mr_conf_filename = NULL;   /* Configuration filename */
82
83/*if output all error and warning messages*/
84static int mr_conf_flags = MRCONF_FLAG_VERBOSE;
85
86/*
87 * Format of the configuration file is as follows:
88 *
89 * attribute1 = int_value
90 * attribute2 = float_value
91 * attribute3 = string_value
92 */
93
94
95/*open and read file: each call must be coupled with mr_conf_close
96  function: return 0 if success*/
97int mr_conf_open(const char *filename) {
98    size_t length;              /*length of the buffer/file */
99    size_t res = 0;
100
101    /* check if mr_conf is already opened? */
102    if (mr_conf_check_int_flag(MRCONF_INTFLAG_OPEN)) {
103        mr_conf_error_msg(MRCONF_OPEN_OPENED, NULL);
104        return MRCONF_OPEN_OPENED;
105    }
106
107    length = mr_conf_filesize(filename);
108    CONF = fopen(filename, "r");
109
110    mr_asprintf(mr_conf_filename, "%s", filename);
111
112    /*if file is empty or not exist => error */
113    if (length == 0) {
114        mr_conf_error_msg(MRCONF_BAD_FILE, filename);
115        return (MRCONF_BAD_FILE);
116    }
117
118    /*creating and reading buffer for file content */
119
120    /*allocate memory for the buffers */
121    buffer = (char *) mr_malloc(sizeof(char) * (length + 1));
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    mr_free(mr_conf_filename);
152
153    /*set flag that module is in "close" state */
154    mr_conf_drop_int_flag(MRCONF_INTFLAG_OPEN);
155}
156
157/*read field value after string str in the current file*/
158static char *mr_conf_read(const char *field_name) {
159    char *p = NULL;             /*pointer to the field */
160
161    /* check if mr_conf is not yet opened? */
162    if (!mr_conf_check_int_flag(MRCONF_INTFLAG_OPEN)) {
163        mr_conf_error_msg(MRCONF_CALL_BUT_NOT_OPEN, NULL);
164        return NULL;
165    }
166
167    /*read the number */
168    p = strstr(buffer, field_name);
169    if (p == NULL) {
170        mr_conf_error_msg(MRCONF_FIELD_NOT_FOUND, field_name);
171        return NULL;
172    } else {
173        p += strlen(field_name);
174        while ((*p != '\n') && (*p != '\0') && (*p != '=')) {
175                p++;
176        }
177        if (*p != '=') {
178            mr_conf_error_msg(MRCONF_FIELD_NO_VALUE, field_name);
179            return NULL;
180        } else {
181            /* points after the = sign */
182            p++;
183        }
184    }
185    /* skip initial spaces and tabs after = */
186    while ((*p == ' ') || (*p == '\t')) {
187            p++;
188    }
189
190    return p;
191}
192
193/*read integer number after string str in the current file*/
194char *mr_conf_iread(const char *field_name) {
195    char *p = NULL;             /*pointer to the field */
196    char *p1 = NULL;            /*return field */
197
198    p = mr_conf_read(field_name);
199    if (p != NULL) {
200        mr_asprintf(p1, "%d", p);
201        }
202    return p1;
203}
204
205/*read float/double number after string str in the current file*/
206char *mr_conf_fread(const char *field_name) {
207    char *p = NULL;             /*pointer to the field */
208    char *p1 = NULL;            /*return field */
209
210    p = mr_conf_read(field_name);
211    if (p != NULL) {
212        mr_asprintf(p1, "%f", p);
213    }
214    return p1;
215}
216
217
218/*
219*/
220char *mr_conf_sread(const char *field_name) {
221    char *p = NULL;             /*pointer to the field */
222    char *q = NULL;             /*pointer to the field */
223    char *r = NULL;             /*pointer to the field */
224    char *ret = NULL;           /*return value */
225    int size = 0;               /*size of returned string */
226    int i = 0;
227
228    ret = NULL;
229
230    p = mr_conf_read(field_name);
231    if (p == NULL) {
232        return(p);
233    }
234    mr_asprintf(q, "%s", p);
235
236    if (*p != '"') {
237        mr_conf_error_msg(MRCONF_STRING_QUOTE, field_name);
238        return (NULL);
239    }
240    p++;
241
242    /* trunk at first \n */
243    r = index(q,'\n');
244    r--;
245    if (*r != '"') {
246        mr_conf_error_msg(MRCONF_STRING_QUOTE, field_name);
247        return (NULL);
248    }
249    r--;
250
251    size = r-q+1;
252    /*copy filtered data to the buffer */
253    ret = (char *) mr_malloc(sizeof(char) * (size));
254    while (i < size - 1) {
255        ret[i] = *p;
256        i++;
257        p++;
258    }
259
260    ret[i] = (char) 0;      /* and set its length */
261    mr_free(q);
262
263    return ret;
264}
265
266/*read boolean after string str in the current file*/
267char *mr_conf_bread(const char *field_name) {
268    char *p = NULL;             /*pointer to the field */
269    char *p1 = NULL;                /*pointer to the field */
270   
271    p = mr_conf_read(field_name);
272    if (p != NULL) {
273        /* match if yes/true/1 */
274        if ((strncasecmp(p, "y" , (size_t)1) == 0) ||
275            (strncasecmp(p, "t" , (size_t)1) == 0) ||
276            (strncasecmp(p, "1" , (size_t)1) == 0)) {
277            mr_asprintf(p1, "%d", TRUE);
278        } else {
279            mr_asprintf(p1, "%d", FALSE);
280        }
281    }
282    return p1;
283}
284
285/* Convert a string with decimal value of TRUE/FALSE in boolean */
286bool mr_atob(const char *str) {
287    bool ret = FALSE;
288    char *p = NULL;
289
290    mr_asprintf(p, "%d", FALSE);
291    if (strcmp(str,p) != 0) {
292        ret = TRUE;
293    }
294    mr_free(p);
295    return(ret);
296}
297
298/*removes all comments from the buffer*/
299static void mr_conf_remove_comments(void) {
300    char *tmp_buf;              /*temporary buffer without comments */
301    size_t length               /*initial length */ ;
302    size_t i;                   /*iterator */
303    size_t k;                   /*conditioned iterator for tmp_buffer */
304    bool found_quote = FALSE;
305    bool found_comment = FALSE;
306
307    length = strlen(buffer);
308
309    /*sizing the new chain */
310    k = 0;
311    i = 0;
312    while (i < length) {
313        /* Handle quotes to detect strings */
314        if ((buffer[i] == '"') && (! found_comment)) {
315            if (found_quote) {
316                found_quote = FALSE;
317            } else {
318                found_quote = TRUE;
319            }
320        }
321        /* Handle start of comment - only when not in a string */
322        if (buffer[i] == MRCONF_COMM_CHAR) {
323            if (found_quote) {
324                found_comment = FALSE;
325            } else {
326                found_comment = TRUE;
327            }
328        }
329        /* Comments end with EOL */
330        if (buffer[i] == '\n') {
331            found_comment = FALSE;
332        }
333        if (! found_comment) {
334            k++;
335            i++;
336        } else {
337            /* Skip comment */
338            while ((buffer[i] != '\n') && (buffer[i] != (char) 0)) {
339                i++;
340            }
341            if (buffer[i] == (char) 0) {
342                mr_conf_error_msg(MRCONF_STRING_ENDQUOTE, buffer);
343            }
344        }
345    }
346    /* k is new buffer length now */
347    tmp_buf = (char *) mr_malloc(sizeof(char) * (k + 1));
348
349    k = 0;
350    i = 0;
351    while (i < length) {
352        if (buffer[i] == '"') {
353            if (found_quote) {
354                found_quote = FALSE;
355            } else {
356                found_quote = TRUE;
357            }
358        }
359        if ((buffer[i] != MRCONF_COMM_CHAR) || (found_quote)) {
360            tmp_buf[k++] = buffer[i++];
361        } else {
362            /* Skip comment as it's not inside a string */
363            while ((buffer[i] != '\n') && (buffer[i] != (char) 0)) {
364                i++;
365            }
366        }
367    }
368    tmp_buf[k] = (char) 0;      /*and set its length */
369
370    mr_free(buffer);
371    /*copy filtered data to the buffer */
372    buffer = tmp_buf;
373}
374
375static int mr_conf_check_int_flag(const int flag) {
376    return (flag & internal_flags);
377}
378
379static void mr_conf_set_int_flag(const int flag) {
380    internal_flags = flag | internal_flags;
381}
382
383static void mr_conf_drop_int_flag(const int flag) {
384    internal_flags = (~flag) & internal_flags;
385}
386
387
388/*local function to define size of a file. Return 0 for mistake*/
389static size_t mr_conf_filesize(const char *name) {
390    FILE *F = fopen(name, "r"); /*file to open */
391    size_t length;              /*number to return */
392
393    if (F == NULL) {
394        return 0;
395    }
396
397    fseek(F, 0, SEEK_END);      /*set position to the end of file */
398    length = ftell(F);          /*define number of position=> this is its
399                                   length */
400    fclose(F);
401
402    return length;
403}
404
405/*output error message*/
406static void mr_conf_error_msg_int(int error_code, const char *add_line, int line, const char *file) {
407    if ((mr_conf_flags & MRCONF_FLAG_VERBOSE)) {    /*if verbose mode */
408        switch (error_code) {
409        case MRCONF_BAD_FILE:
410            mr_msg_int(1,line,file,"%s (%s) %s %s", MRCONF_STR_ERROR, mr_conf_filename, MRCONF_STR_BAD_FILE,
411                   add_line);
412            break;
413
414        case MRCONF_READING_FAILED:
415            mr_msg_int(1,line,file,"%s (%s) %s", MRCONF_STR_ERROR, mr_conf_filename, MRCONF_STR_READING_FAILED);
416            break;
417
418        case MRCONF_FIELD_NOT_FOUND:
419            mr_msg_int(1,line,file,"%s (%s) %s \"%s\"", MRCONF_STR_WARNING, mr_conf_filename, MRCONF_STR_FIELD_NOT_FOUND, add_line);
420            break;
421
422        case MRCONF_FIELD_NO_VALUE:
423            mr_msg_int(1,line,file,"%s (%s) %s \"%s\"", MRCONF_STR_ERROR, mr_conf_filename, MRCONF_STR_FIELD_NO_VALUE, add_line);
424            mr_msg_int(1,line,file,"%s (%s) %s", MRCONF_STR_WARNING, mr_conf_filename, MRCONF_STR_IGNORE);
425            break;
426
427        case MRCONF_CLOSE_BUT_NOT_OPEN:
428            mr_msg_int(1,line,file,"%s (%s) %s", MRCONF_STR_WARNING, mr_conf_filename, MRCONF_STR_CLOSE_BUT_NOT_OPEN);
429            break;
430
431        case MRCONF_CALL_BUT_NOT_OPEN:
432            mr_msg_int(1,line,file,"%s (%s) %s", MRCONF_STR_WARNING, mr_conf_filename, MRCONF_STR_CALL_BUT_NOT_OPEN);
433            break;
434
435        case MRCONF_OPEN_OPENED:
436            mr_msg_int(1,line,file,"%s (%s) %s", MRCONF_STR_ERROR, mr_conf_filename, MRCONF_STR_OPEN_OPENED);
437            break;
438
439        case MRCONF_STRING_QUOTE:
440            mr_msg_int(1,line,file,"%s: %s (%s) %s", add_line, MRCONF_STR_ERROR, mr_conf_filename, MRCONF_STR_STRING_QUOTE);
441            break;
442
443        case MRCONF_STRING_ENDQUOTE:
444            mr_msg_int(1,line,file,"%s: %s (%s) %s", add_line, MRCONF_STR_ERROR, mr_conf_filename, MRCONF_STR_STRING_ENDQUOTE);
445            break;
446
447        default:
448            mr_msg_int(1,line,file,"%s (%s) %s", MRCONF_STR_ERROR, mr_conf_filename, MRCONF_STR_DEFAULT_ERROR);
449            break;
450        }
451    }
452}
Note: See TracBrowser for help on using the repository browser.