/*
** CONFIG FILE: Simple config file parser
** Copyright (C) 2002 Michael W. Shaffer <mwshaffer@angrypot.com>
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program (see the file COPYING). If not, write to:
**
** The Free Software Foundation, Inc.
** 59 Temple Place, Suite 330,
** Boston, MA 02111-1307 USA
*/
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "config_file.h"
/*
** Config file format is as follows:
**
** - settings are in the form of either:
**
** key = value
**
** or:
**
** key : value
**
** - keys and values may contain only the characters:
**
** - _ . / + a-z A-Z 0-9
**
** - whitespace is optional and is discarded along with anything
** else no explicitly listed above
** - comments start with either ';' or '#' and continue
** until end of line
** - only one 'setting' per line
**
** The parsing routine basically supports either the classic
** unix style conf file with ':' as key/value separator and
** '#' as comment character as well as .ini like syntax with
** '=' as key/value separator and ';' as comment character. I
** don't think that real windows .ini files allow comments on
** the same line as settings, but this routine does.
**
** Here are some short samples of each format:
**
*******************************************************************************
**
** #
** # sample exampled.conf file
** # (classic unix syntax)
** #
**
** host: 127.0.0.1 # peer host to monitor
** interval: 20 # interval in seconds between checks
** tolerance: 3 # number of failed checks to initiate failover
**
*******************************************************************************
**
** ;
** ; sample exampled.conf file
** ; (.ini like systax)
** ;
**
** host = 127.0.0.1 ; peer host to monitor
** interval = 20 ; interval in seconds between checks
** tolerance = 3 ; number of failed checks to initiate failover
**
*******************************************************************************
*/
enum {
tagsize = 8192,
bufsize = 8192
};
enum character_classes {
c_junk = 0,
c_name_char,
c_separator,
c_end_of_line,
c_comment
};
enum parse_states {
s_comment = 0,
s_key,
s_value
};
static int parse_state = s_key;
static int classify (char c)
{
if ((parse_state == s_comment) && !((c == '\n') || (c == '\r')))
return c_comment;
if ((c >= 'a') && (c <= 'z'))
return c_name_char;
if ((c >= 'A') && (c <= 'Z'))
return c_name_char;
if ((c >= '0') && (c <= '9'))
return c_name_char;
switch (c) {
case '-':
case '_':
case '.':
case '/':
case '+':
return c_name_char;
case ':':
case '=':
case '|':
parse_state = s_value;
return c_separator;
case ';':
case '#':
parse_state = s_comment;
return c_comment;
case '\n':
case '\r':
parse_state = s_key;
return c_end_of_line;
default:
return c_junk;
}
}
int parse_config_file (char *conf_path, struct hash_table *conf)
{
int fd = -1;
char *buf = NULL;
char *bufp = NULL;
struct datum d;
char c = '\0';
char key[tagsize];
char val[tagsize];
int kpos = 0;
int vpos = 0;
if ( !(conf_path && conf))
return -1;
fd = open (conf_path, O_RDONLY);
if (fd == -1) {
return -1;
}
buf = (char *) malloc (bufsize);
if (!buf) {
return -1;
}
parse_state = s_key;
memset (key, 0, sizeof (key));
memset (val, 0, sizeof (val));
memset (&d, 0, sizeof (struct datum));
d.key = key;
d.val = val;
memset (buf, 0, bufsize);
while (read (fd, buf, (bufsize - 1)) > 0) {
bufp = buf;
while ((c = *(bufp++))) {
switch (classify (c)) {
case c_name_char:
if (parse_state == s_key) {
if (kpos < (tagsize - 1))
key[kpos++] = c;
} else if (parse_state == s_value) {
if (vpos < (tagsize - 1))
val[vpos++] = c;
}
break;
case c_end_of_line:
if (strlen (key) > 0) {
d.ksize = strlen (key);
d.vsize = strlen (val);
hash_table_insert (conf, &d);
}
memset (key, 0, sizeof (key));
memset (val, 0, sizeof (val));
kpos = 0;
vpos = 0;
break;
default:
break;
}
}
memset (buf, 0, bufsize);
}
if (buf)
free (buf);
if (fd > 0)
close (fd);
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1